gopherkind's whole premise is key hygiene: the bridge never holds a user key,
signing is always remote over NIP-46, and disk state is limited to the Gemini
TLS cert and a mode-600 pairings.json. Reports that undermine those
properties are taken seriously.
Please report privately, not in a public issue:
- Open a GitHub security advisory, or
- Zap or DM
npub1mgvlrnf5hm9yf0n5mf9nqmvarhvxkc6remu5ec3vf8r0txqkuk7su0e7q2on Nostr.
Include a description, affected version or commit, and a proof of concept if you have one. gopherkind is unfunded hobby work, so there is no bounty, but credit is given in the changelog unless you prefer otherwise.
- Anything that gets a user key onto the bridge, or has it signed without the user's intent (CSRF, request forgery, the credential guard).
- Escaping a hole's selector namespace, or injecting into a wire format (gopher menus, gemtext, HTML).
- Reaching the loopback operator surface from a remote client (source-IP spoofing, DNS rebinding, reverse-proxy confusion).
- SSRF through the gopher proxy or the NIP-46 pairing flow.
- Serving content that should not be served (expired NIP-40 events).
- Relays ignoring NIP-09 deletion requests: this is documented behaviour,
not a bug. Use NIP-40
expirationfor content that must stop being served. - Gopher being plaintext and unauthenticated: it is read-only by design and never accepts credentials.
- Denial of service from a single well-resourced client beyond the per-IP token bucket.
-
Relay connections can be routed through a SOCKS5 proxy (
--proxy socks5h://host:portorGOPHERKIND_PROXY) so relays do not learn the reader's or bridge's network location, and so.onionrelay URLs are reachable. When a proxy is active the connection-time DNS guard cannot run (the proxy resolves and dials), so untrusted relay URLs get only the hostname-level internal-address check. A trusted relay on a local address is still dialled directly. See docs/privacy.md for the full threat model. -
The HTTP frontend trusts loopback as the operator. Behind a reverse proxy every request originates on loopback, so operator trust is disabled unless the bridge is bound to a loopback address (or you pass
--trust-loopback-anyway). Use--no-local-trustbehind a proxy so visitors must pair their own signer, and put the frontend behind TLS before exposing it. -
The gopher proxy refuses to connect to private, loopback and link-local ranges. Do not re-expose it to internal networks.
-
Author relay lists, NIP-19 hints and public bunker URIs are resolved through the same socket-time network guard. Operator-configured relays are trusted so local development relays remain possible.