Please report vulnerabilities privately via GitHub's "Report a vulnerability" on this repository, rather than opening a public issue.
who-signed is a visibility tool. It sits between your SSH clients and
your SSH agent and records who asked for what. It does not hold keys, does not
approve or deny signatures, and does not change what your agent would have
done.
| Threat | Mitigation |
|---|---|
| Another local account reading your activity | Runtime dir 0700, log 0600, socket 0600 |
| Secrets on command lines reaching disk | Pattern-based redaction before write (redact.py) |
| A web page reaching the dashboard via DNS rebinding | Host header must be loopback (always on) |
| Another user account reading the dashboard | Optional token (require_token), 0600, constant-time compare |
| Log content executing in your browser | All rendered values HTML-escaped; strict CSP |
| Evidence erased by flooding the log | Dated rotation retaining log_keep generations |
| Misattributing a request after PID reuse | Process start time compared to connection time; flagged |
| A hung agent hanging every git command | Timeouts on connect and read; no filesystem I/O on the request path |
An attacker who already runs code as you. They can stop the proxy, edit the log, or talk to your agent directly. Nothing running with your privileges can be defended against by another thing running with your privileges.
Malicious agents. If your SSH agent is compromised, this tool faithfully records requests to a compromised agent.
Guaranteeing capture. Installation is fail-open: if the proxy is not
running, ~/.zshrc falls back to the real agent so you can still work.
Signatures made that way are not recorded. This trades completeness for
availability deliberately — a crashed audit tool must not stop you working.
Key names come from the protocol, not the filesystem. An earlier version
read .pub files from the agent's container directory on every request. On
macOS, reading another application's container can block indefinitely behind a
TCC privacy prompt — directly on the signing path, meaning every git commit
hangs. Names are now taken from the agent's own identity listings, which
require no filesystem access and cannot block.
Bookkeeping never breaks signing. Process inspection, redaction and logging are all wrapped so that a failure degrades the audit record rather than the SSH operation.
Loopback binding is not access control. A hostile web page can point a
hostname at 127.0.0.1 and reach the server through your browser, so the
Host check is always enforced.
The token is off by default, deliberately. It defends against other user
accounts on the machine, which can reach loopback HTTP even without
permission to read ~/.who-signed. It does not defend against code running
as you: such code can read the log file, or the token file, directly.
Requiring it by default meant every user pasting a secret before they could
see their own dashboard — real friction for a threat most single-user Macs do
not have. Turn it on with "require_token": true on shared machines.
- Make the log append-only:
chflags uappnd ~/.who-signed/audit-log.jsonl - Ship records off the machine (syslog, or your SIEM) so a local attacker cannot rewrite history
- Set
require_tokenon shared or multi-user machines - Reduce
log_max_bytesand raiselog_keepto retain more history