Skip to content

Security considerations

What a Pinggy installation stores, publishes, and never publishes.

Advertised monitoring source addresses

If you operate a service that only accepts traffic from known addresses, a Pinggy installation can publish the addresses its monitoring may originate from — but only ones an operator has explicitly declared and enabled. Nothing is ever inferred from a heartbeat, a management connection, a network interface, or an external-IP lookup; an installation that has published nothing says so honestly rather than falling back to a guess.

The published list is at the public allowlist page and, for programmatic use, GET /api/public/v1/source-ips. Read that page for the address model itself — canonical net/netip semantics, how a host address and a CIDR range are represented, and what "advertised" does and does not promise.

What monitoring targets can be

This is a self-hosted deployment, and the authenticated control plane trusts the operator who configures it. A monitor's target is validated for shape — a well-formed URL, a well-formed host — but reaching an internal or private address is not blocked: an operator who wants to monitor something on their own network is expected to be able to. That means target validation alone is not a server-side request forgery boundary; if untrusted parties can create monitors in your deployment, that is a trust decision for the operator to make, not a gap this validation closes.

Secrets at rest

Notification channel secrets — an ntfy access token, a webhook signing secret, a custom header value — are sealed under the deployment's own master key and stored as an authenticated envelope; a value that is not a correctly sealed envelope is rejected by the database itself, not only by application code. A secret is never returned by an API, never rendered in a template, and never logged. Losing the master key does not stop monitoring; it disables exactly the actions that need to open or seal a secret, and fails closed rather than guessing at a value it cannot verify.

Sessions and mutation

Browser sessions are random opaque tokens; only a hash of one is stored, and a session is revoked by removing that row, not by marking it invalid. State-changing browser requests require a CSRF token bound to the session. Every mutation an operator makes is CSRF-protected the same way, whether it is a monitor's configuration, a notification channel, or the advertised source addresses above.

What is never logged

Passwords, credentials, cookies, authorization headers, and request bodies are never logged. On the public surfaces — the landing page, this knowledge base, and the public status page and its API — the request path itself is reader-supplied text, so it is never logged either: a public route logs a fixed route class in its place, never the address a reader actually typed.

Transport

Pinggy expects to sit behind a TLS-terminating reverse proxy in production, with secure cookies enabled once that proxy is in place. The control plane itself does not terminate TLS for the browser or API surfaces.

This article is part of this repository and is served by the same binary, so what you read here is the documentation for the version you are running.