Which project, and which command, just asked to use your SSH key?
How it works · Install · Security · Contributing
Your SSH agent asks you to approve a signature. It does not tell you what asked — it cannot, because by the time it sees the request all it knows is that something on the machine wants a signature.
So when a compromised npm package asks for one at the moment you expected a
prompt, you approve it. who-signed is the missing half of that prompt:
It sits transparently in front of your agent and records, for every request:
- which command and chain of programs (
ssh-keygen ‹ git ‹ zsh ‹ Cursor) - from which directory and git project
- which key, by name and fingerprint
- whether it was a git signature, an SSH login, or a key listing
- and whether you approved or denied it
Your agent is never modified, and private keys never pass through it. It sees the requests, never the key material.
→ How it works walks through the whole process, from
git commit to log entry, assuming no prior knowledge.
Any SSH agent: Secretive, 1Password, gpg-agent, YubiKey, or
plain ssh-agent. The installer detects whichever you use.
macOS today. Linux needs a small change (SO_PEERCRED instead of
LOCAL_PEERPID) — the hook is in whosigned/procinfo.py.
git clone https://github.com/sarangshahane/who-signed.git ~/who-signed && ~/who-signed/install.shThe installer detects your agent, installs a LaunchAgent that keeps the proxy
running, points ~/.zshrc and ~/.ssh/config at it, and refuses to finish
unless the agent actually answers through the proxy. It backs up every file it
edits and is safe to re-run.
Then open a new terminal. You now have a who-signed command:
who-signed doctor # check the install is healthy
who-signed open # open the dashboard
who-signed status # machine-readable statusAnd the dashboard is at:
That is it — no token, no flags, no command to run first. Bookmark it.
The LaunchAgent runs the code from wherever you cloned it, so an update is a pull plus a restart:
git -C ~/who-signed pull && launchctl kickstart -k gui/$(id -u)/com.who-signed.agentRe-running install.sh also works and is safe — it is idempotent — but it is
only necessary if the LaunchAgent, shell config or who-signed command need
recreating.
| Command | Does |
|---|---|
who-signed run |
Run the proxy in the foreground (the LaunchAgent does this for you) |
who-signed open |
Open the dashboard in your browser |
who-signed url |
Print the dashboard URL (with a token, if one is required) |
who-signed status |
Machine-readable status as JSON |
who-signed doctor |
Check the install is actually healthy |
who-signed config |
Show effective configuration |
~/who-signed/uninstall.shStops the agent, removes the LaunchAgent, strips its blocks out of ~/.zshrc
and ~/.ssh/config, and restores your original agent. Your audit log is kept;
add --purge to delete it too.
~/.who-signed/config.json, all keys optional:
{
"upstream_socket": "/path/to/your/agent.sock",
"http_port": 8722,
"require_token": false,
"log_max_bytes": 5000000,
"log_keep": 30,
"redact_secrets": true,
"connect_timeout": 5.0,
"response_timeout": 300.0
}It records metadata about requests. Never key material. Your keys stay in the Secure Enclave, your YubiKey, or wherever your agent keeps them.
The log is yours alone. ~/.who-signed/ is 0700 and the log is 0600,
so other accounts on the machine cannot read which projects you work on.
Command lines are redacted. Tokens, passwords, and keys that appear on a
command line are replaced before anything is written. See whosigned/redact.py.
The dashboard rejects requests whose Host header is not loopback, so a
web page you visit cannot reach it by DNS rebinding. That protection is always
on and costs you nothing.
On a shared Mac, add a token. Set "require_token": true and the
dashboard also demands a secret (printed by who-signed url). This
guards against other user accounts on the same machine, which can reach
loopback HTTP even though they cannot read ~/.who-signed. It is off by
default because it adds nothing against code running as you — that can read
the log file directly — and it would make every visit require a setup step.
It fails open, by design. If the proxy stops, ~/.zshrc falls back to your
real agent so you can still sign — but those signatures are not recorded.
Anyone who can run code as you can stop the proxy. This is a visibility tool,
not a security boundary.
The log is not tamper-proof. It is a file you own; anything running as you can edit it. For stronger guarantees, ship a copy off the machine.
Attribution can rarely be wrong. The requesting process is identified by
PID, and a process that exits immediately could have its PID recycled before
we read it. When the timing looks impossible the record is flagged
pid_reused rather than quietly attributed to the wrong program.
This records what you work on, when, and the commands you run. The data never leaves your machine — there is no telemetry, no upload, and no network listener beyond loopback.
If your organisation ever adds central collection, that changes the tool from a personal audit log into employee monitoring, with the legal and ethical obligations that follow. Make that opt-in, documented, and agreed — do not bolt it on quietly.
The images above come from a demo instance with synthetic data — the projects, keys and commands in them are invented, not anyone's real activity.
python3 -m unittest discover -s tests110 tests, no dependencies, no network, and no real agent required — the suite runs against a fake agent socket, so it never touches your keys.
your tool ──► who-signed ──► your real SSH agent
│
├── appends a record to ~/.who-signed/audit-log.jsonl
└── serves the Key Ledger on 127.0.0.1
Every byte is forwarded unchanged in both directions; the audit record is a side effect that can never alter the conversation. Key names are learned from the agent's own identity listings rather than read off disk — reading another app's container can block indefinitely behind a macOS privacy prompt, and on the signing path that would hang every git command.
Built by Sarang Shahane.
Issues and pull requests welcome — see CONTRIBUTING.md.
MIT © Sarang Shahane — see LICENSE.

