# whoami.filippo.io: an SSH server that reports your GitHub identity back to you

> A small Go program that turns SSH public key negotiation into a lookup, using a scraped GitHub key database and the GitHub API to name you.

**FiloSottile/whoami.filippo.io** — A ssh server that knows who you are. $ ssh whoami.filippo.io

- Repository: https://github.com/FiloSottile/whoami.filippo.io
- Stars: 2,368 · Forks: 112
- Language: Go
- License: ISC
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/filosottile-whoami-filippo-io

## One ssh command against a server that refuses every key

The pitch fits in a single line. The README calls this a ssh server that knows who you are, and the try-it block is the whole demonstration:

```bash
ssh whoami.filippo.io
```

What comes back is a username, a real name pulled from the GitHub API, and a closed terminal. No shell, no files, no command execution. The README pre-empts the obvious objection by publishing both host key fingerprints, an ED25519 and an RSA value, so a client can verify it is talking to the intended host rather than something intercepting the connection.

The repository is correspondingly small. The tree is `.gitignore`, `Dockerfile`, `LICENSE`, `README.md`, `cmd/`, `fly.toml`, `go.mod`, `go.sum` and `server.go`. There is one Go source file, a `cmd/` directory for the entrypoint, and a `fly.toml` that points at Fly.io hosting. The README points readers at `server.go` for the interesting parts, which is a reasonable thing to say about a program this size.

## Enumerating client keys during public key negotiation

The mechanism is a property of the SSH protocol rather than a bug in any implementation. When a client authenticates with a public key, it sends the server each key it holds, one at a time, until the server accepts one or the list runs out. A server that never accepts any of them still learns every key offered.

whoami.filippo.io advertises `(publickey,keyboard-interactive)` and leans on both halves. It refuses every public key but records them. Then it accepts keyboard-interactive without sending a challenge, so the client moves past authentication without any password prompt and without any human interaction. A shell and PTY are granted, and at that point the program knows the client's full key set and can go do a lookup.

That last detail is what makes the demo work unattended. Most key-enumeration ideas stall because the server would need to authenticate before it knows who it is talking to. This one resolves identity after the fact, from data the client volunteered during a phase where declining to send keys was the only available objection.

## Turning a key into a username with a scraped database

Key material is not a name, so the next step is a join. GitHub lets anyone download a user's public keys, and the README credits Ben Cox with turning that availability into a dataset covering all GitHub public keys. The server matches the collected keys against that dataset, recovers a username, and then asks the GitHub API for the account's real name.

The dependencies in `go.mod` show how that is wired in Go 1.25.0: `golang.org/x/crypto` for the SSH server itself, `github.com/google/go-github/v72` and `golang.org/x/oauth2` for the API call, `zombiezen.com/go/sqlite` for the local key database, and `github.com/prometheus/client_golang` for metrics. The SQLite driver is a pure Go implementation, which is why the indirect dependency list is long: it pulls in `modernc.org/sqlite`, `modernc.org/libc` and `remyoudompheng/bigfft` rather than cgo.

The `Dockerfile` confirms the shape. A builder stage compiles with `go install -trimpath`, and the runtime stage copies the binary alongside a `whoami.sqlite3` file, pointing `DB_PATH` at it under `/usr/local/share/`. The key data ships as a file with the container rather than being fetched at startup.

## The ssh config that stops presenting your keys

A server that enumerates keys is only interesting against clients that volunteer them, so the README spends its last section on opting out. The fix goes at the end of `~/.ssh/config`, after other Host directives, and applies to every host:

```bash
Host *
    PubkeyAuthentication no
    IdentitiesOnly yes
```

That disables public key authentication outright. The cost is that you then have to name the keys you do want per host, which the next block shows:

```bash
Host example.com
    PubkeyAuthentication yes
    IdentityFile ~/.ssh/id_rsa
    # IdentitiesOnly yes # Enable ssh-agent (PKCS11 etc.) keys
```

The interesting suggestion is further down. Separate keys per destination stop the correlation:

```bash
Host github.com
    PubkeyAuthentication yes
    IdentityFile ~/.ssh/github_id_rsa
```

This is the practical lesson the project teaches without stating it as one. A public key is a stable identifier, and presenting the same one to unrelated services lets anyone holding both logs link those services to the same person. Generating a distinct key per host is more work and it removes that link.

## A demonstration server rather than a component to build on

It is worth being direct about what this program is. It is a public demonstration of an authentication edge case, hosted on Fly.io, with metrics instrumentation and a bundled SQLite database of GitHub keys. Nothing about it is designed to sit in an application path, and it would be a strange thing to depend on.

The dependency versions suggest steady, unhurried maintenance. `go-github/v72`, `prometheus/client_golang v1.23.2`, `x/crypto v0.50.0`, `x/oauth2 v0.36.0` and `zombiezen.com/go/sqlite v1.4.2` are all recent, and the module targets Go 1.25.0. The last push was on 2026-04-16 and the repository is not archived, with 2366 stars, 112 forks and 10 open issues. That combination suggests a project that gets touched when its dependencies or hosting need attention rather than one with a release cadence.

There are no tagged releases, which is consistent with the shape: this is something you connect to, not something you install. The README is the entire documentation, and the one piece of friction in it is a link that points at `server.go` in a differently named repository, which is either a leftover from the project's previous name or a redirect that never got updated.

## Conclusion

The trick at the centre of this is narrow and legible: SSH offers a client several public keys before giving up, and a server that accepts keyboard-interactive without a challenge can therefore collect that list without ever being granted access. whoami.filippo.io does exactly that, joins the result against a SQLite copy of GitHub public keys, asks the API for a display name, and closes the shell. It is a demonstration of an authentication edge case rather than infrastructure you should put in a path, and the README is honest that it accepts no keys at all. Everything lives in a single `server.go`, and the surrounding questions it raises, key reuse across hosts and what a scraped key database can tell an observer, are the interesting part.

## FAQ

### What does whoami.filippo.io do when I connect to it?

It collects the public keys your SSH client offers, matches them against a local SQLite copy of GitHub public keys to find your username, asks the GitHub API for your real name, prints both and closes the terminal. It accepts no keys and grants no shell access, so nothing you own is at risk beyond the key list itself.

### How can I stop a server from seeing my SSH public keys?

Set PubkeyAuthentication no and IdentitiesOnly yes for Host * at the end of your ~/.ssh/config, then name an IdentityFile per host where you still want key authentication. A separate key for each destination also stops unrelated services from correlating you through a shared key.

### Is it safe to ssh into whoami.filippo.io?

The server runs a shell and PTY but the program immediately prints what it found and closes the terminal, without accepting any key or executing anything you send. The README publishes ED25519 and RSA host key fingerprints so the connection can be verified rather than trusted.

## Sources

- [FiloSottile/whoami.filippo.io on GitHub](https://github.com/FiloSottile/whoami.filippo.io)
- [Issues](https://github.com/FiloSottile/whoami.filippo.io/issues)
- [License: ISC](https://github.com/FiloSottile/whoami.filippo.io/blob/master/LICENSE)
- [README](https://github.com/FiloSottile/whoami.filippo.io/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/filosottile-whoami-filippo-io
