Skip to content

Security: sarangshahane/who-signed

Security

SECURITY.md

Security

Reporting

Please report vulnerabilities privately via GitHub's "Report a vulnerability" on this repository, rather than opening a public issue.

What this tool is

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 model

In scope

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

Out of scope

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.

Notable design decisions

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.

Hardening beyond the defaults

  • 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_token on shared or multi-user machines
  • Reduce log_max_bytes and raise log_keep to retain more history

There aren't any published security advisories