Security
How bolthub protects your data, credentials, and API traffic.
NWC credential encryption
Tenant NWC connection URIs are encrypted at rest using AES-256-GCM with a unique random IV per credential. Credentials are decrypted only at the moment they are needed (e.g. to create an invoice) and are never logged or cached in plaintext.
SSRF protection
All outbound HTTP requests (e.g. proxying to tenant origins, NWC relay connections, wallet configuration URLs) pass through a multi-layer SSRF protection system:
- Private IP blocking: all private, reserved, and link-local IP ranges are blocked, including cloud metadata endpoints.
- Alternative encoding detection: private IPs encoded in decimal, hexadecimal, octal, or IPv6-mapped formats are detected and blocked.
- DNS rebinding prevention: after static checks pass, hostnames are resolved via DNS and all resolved addresses are validated against the blocklist.
- Wallet URL validation: when tenants configure Lightning wallet connections (LND, LNbits, NWC, Phoenixd, and similar), URLs are validated against the SSRF blocklist before being stored.
L402 token security
L402 tokens (issued in WWW-Authenticate challenges) are secured with:
- HMAC-SHA256 signing with domain separation to prevent cross-type token confusion.
- Scoped to tenant + endpoint: a token issued for one endpoint cannot be used on another.
- Preimage verification: the payment preimage is verified against the original payment hash using constant-time comparison to prevent timing side-channel attacks.
- Generic error messages: all authentication failures return a uniform error, preventing attackers from distinguishing between failure modes.
Session token security
For billing models that use session tokens (time_pass, metered, token_bucket, per_kb):
- Session tokens are cryptographically signed and scoped to a specific tenant and endpoint.
- Session tokens include an embedded expiry, enforced server-side during verification.
- Time pass sessions expire after the purchased duration. Metered sessions track remaining balance and reject requests when the balance is exhausted.
Access control
All tenant-scoped API routes verify the authenticated user owns the requested resource. Routes that operate on endpoints include an additional ownership check to prevent unauthorized access to other tenants' data.
Rate limiting
Both the API and the Go gateway apply multiple layers of rate limiting:
- Per-IP rate limiting on all public endpoints.
- Per-path rate limiting for fine-grained control.
- Stricter limits on expensive operations such as invoice creation and wallet connections.
- Shared Redis backend: when Upstash Redis is configured, rate limit counters are shared across all API and gateway replicas so that limits are enforced globally. If Redis is unavailable, each instance falls back to independent in-memory limits automatically.
Row Level Security (RLS)
All tenant-scoped database tables are protected by Row Level Security policies:
- Tenants can only read and modify their own data.
- Billing cycles, endpoints, and credentials are scoped to the authenticated tenant.
- Public tables (e.g. directory listings) use RLS to restrict reads to approved entries.
- Service-role access is restricted to the API backend.
HMAC request signing
Requests from the gateway to tenant origins are signed with HMAC-SHA256. The signature, timestamp, and nonce are included as headers on the proxied request. Tenant origins can verify the signature to ensure requests come from the bolthub gateway and have not been tampered with.
Security headers
All HTTP responses include hardened security headers including Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, Cross-Origin-Opener-Policy, X-Content-Type-Options, and Referrer-Policy.
Proxy header sanitization
Before forwarding requests to tenant origins, the gateway strips sensitive headers including forwarding headers (X-Forwarded-For, X-Real-IP), CDN headers, cookies, and the L402 Authorization header. The Go gateway additionally strips response headers from the origin (Set-Cookie, Server, X-Powered-By, Strict-Transport-Security, Content-Security-Policy, Public-Key-Pins, Alt-Svc) to prevent origin infrastructure leakage.
Body size limits
Request bodies are limited to 1 MB and response bodies are limited to 10 MB. Requests exceeding the request body limit are rejected with a 413 Payload Too Large response. Responses exceeding the response body limit are rejected with a 502 Bad Gateway error.
Response streaming
Uncached proxy responses are streamed directly to the client rather than buffered in memory, with a 50 MB cap per response. Cached GET responses are buffered within the 10 MB response body limit.
Circuit breaker
The gateway implements a circuit breaker per endpoint to protect against cascading failures from unhealthy origins. After 5 consecutive failures (5xx responses or connection errors), the circuit opens and requests are immediately rejected with 502 Service temporarily unavailable for 30 seconds. After the timeout, the circuit enters a half-open state allowing 2 test requests before fully closing.