Files
RustProxy/docs/SECURITY.md
T
2026-10-03 00:27:09 +01:00

13 KiB

Security model and limitations

This is a development source release with no executed Rust integration results in the packaging environment. Do not expose it as a production security boundary until the actual build, protocol tests, deployment review and an appropriate security assessment have passed.

Administration

Administration binds to loopback HTTP by default. Settings can enable a dedicated administration HTTPS listener, choose the application-managed certificate or a certificate from the inventory, persist a non-loopback bind and allow explicit DNS Host/Origin names. Remote persisted binding is accepted only with administration TLS. An explicit startup --allow-remote-admin can expose plain HTTP on a non-loopback address; that path should remain behind a trusted firewall/private network boundary. Passwords use salted Argon2id; password work has admission limits and runs off the network I/O path. Setup requires local filesystem authority or the one-time random capability. No default administrator/password is created.

Sessions have HttpOnly/SameSite=Strict cookies, idle and absolute expiries and credential-generation revocation. Mutations require scheme-aware Host/Origin checks, the request marker and a CSRF token. Local CLI reset changes the hash and invalidates all existing sessions without editing SQLite manually. Administration HTTPS marks the session cookie Secure; HTTP cannot. The admin certificate and bind changes are restart-required. A dedicated metrics credential is separate from browser sessions.

The data directory and SQLite files are private. The local OS user with data-directory access is a recovery authority and can create short-lived CLI sessions. Protect that account, filesystem and backup copies; browser authentication does not defend against a compromised process owner. .env is trusted shell code, never untrusted input.

Backend and routing boundary

Only configured HTTP/HTTPS origins may be dialed. Absolute-form client targets and CONNECT cannot turn the proxy into an unrestricted forward proxy. ACL is evaluated before new TCP/TLS connections and before reuse of an existing upstream connection. Host and route restrictions combine; route allow cannot override host deny. Forwarded headers are rebuilt from socket identity by default. An explicit trusted-proxy CIDR policy can accept a bounded existing chain and derive the client IP for ACL/affinity; see INTEGRATIONS_040.md. Routing still uses the actual local destination, never any forwarded address or host.

Private/loopback destinations require explicit approval. DNS answers pass the same policy and optional per-backend CIDR restriction; an unsafe answer fails the entire resolution. Validated results are used without a second DNS lookup. Special-address blocks include common metadata/link-local targets and normalize mapped IPv6. Listener self-target restrictions prevent simple loops and control-plane access by default. A privileged administrator can deliberately set accept_local_listener_risk=true on one backend; private/loopback destinations additionally require allow_private=true. This is intended for consciously accepted local-listener use (including port 9090) and can create a request loop or expose administration through a public vhost. It does not relax metadata/link-local/special-address filtering or CIDR restrictions. Keep network egress and frontend ACLs as defense in depth.

No backend Location redirect is followed internally. HTTPS transport encryption remains available, but backend trust/hostname verification is off by default. Set tls_verify: true for origins where certificate-chain and hostname authentication is required. With verification disabled, a network attacker able to intercept that route may impersonate the origin. Address/DNS restrictions still apply; the local-listener exception exists only when explicitly accepted as above. Operator-supplied backend configuration is privileged configuration, not a field that an unauthenticated caller can edit.

TLS and tunnels

Private key files are size-bounded, regular files, owner-only on POSIX and opened without following final-component symlinks. Named files cannot escape the certificate directory by using path separators. Keep the entire directory tree private as well. Keys and certificate name coverage are validated before publication. Generated self-signed certificates are development material, not automatic public trust.

Existing TLS sessions/tunnels are not revoked by changing a certificate or ACL. Policies apply to new requests and handshakes. Restart/stop the relevant process for immediate termination until a scoped administrative close operation is implemented.

WebSocket payloads remain opaque byte streams. The proxy validates upgrade metadata, not application-level authorization or message semantics. Frame/message limits on a backend remain the backend's responsibility. Proxy buffers, tunnel/connection counts and inactivity timers bound proxy-side resource usage.

Information and resource controls

Access logging does not collect credential headers, query values, cookies, bodies or WebSocket payloads. Hostnames and paths are logged; never put secrets in them. Do not enable third-party verbose tracing or application logging without reviewing their output separately. Access rings, viewer slots, auth work, updates, DNS workers and request/connection admission are bounded. A slow log viewer does not create an unbounded delivery queue.

Backups include TLS private keys and credential/session state. Restore matching SQLite and certificate data together, then revoke restored sessions. Never commit .env, the data directory, backups or generated certificates to a public repository.

Not a completed security feature

Docker socket access controls, service-account metrics access, 2FA, roles, provider secret storage, certificate expiry automation, a full special-address registry policy and independent fuzz/load assessment remain roadmap work. Feature availability is not evidence of a completed security audit or a performance guarantee.

Cache, response transforms and ports (0.1.0)

Cache is enabled by default in 0.8.1 and ACLs precede lookup. Cookie (outside the configured static-asset exception), Authorization, Range, unsafe preconditions and request/response no-store remain hard shared-cache exclusions. Conditional validators can be satisfied from a fresh object or revalidated against the origin. Response no-cache with a usable validator may be retained only for mandatory validation before reuse. Origin privacy is checked before custom header removal, and generated request IDs are not cached. Bounded fill permits, object/entry/byte limits and generation checks protect cancellation, update and purge paths. Purge is authenticated, CSRF-protected and audited, not a public PURGE/BAN capability.

Compression is opt-in, with authenticated/private/no-transform exclusions. Response rules cannot overwrite protected framing and identity fields. Required Age remains on cache hits even when debug headers are disabled. Server hiding is cosmetic and must not be considered an access-control or vulnerability mitigation substitute.

Standard public 80/443 ports are supported without globally forbidding remote origins using those ports. Local listener targets remain guarded. Review SETTINGS.md for interface-enumeration and restart semantics. A Linux service can grant only CAP_NET_BIND_SERVICE to a dedicated unprivileged account; the application does not acquire capabilities itself. Public listener controls do not implicitly expose the separate admin API. The provided systemd unit is an unexecuted example, not an audit result.

Language packs are trusted build inputs with size/type/metadata bounds. The browser renders strings as text and falls back per key. Translations are not executable plugins, and no directory browsing or runtime arbitrary file loading is exposed.

0.2.0 frontend and pool boundaries

An explicit vhost binding is checked using the accepted stream's real local IP, port and TLS state. Host, SNI and forwarded headers cannot assert a different local address. A shared wildcard TCP listener does not grant every vhost access on every accepted IP. Legacy routing does not inherit additional frontend sockets. Conflicting hostname ownership is rejected, including disabled declarations.

Binding a private IP is not an authorization mechanism or firewall. NAT, port forwarding or another proxy can make that destination reachable. Configure network restrictions and application authentication as well; no trusted-proxy identity or Keepalived/VRRP service is introduced. New unavailable IP bindings fail startup.

Health probes share literal/DNS/allowlist/loop protections, including actual old listeners and desired new listeners, and cannot follow redirects to arbitrary origins. They are bounded and do not use user cookies or credentials. Probes can still hit an operator-selected GET path; select a side-effect-free health endpoint.

Affinity uses opaque random tokens but is not authentication, CSRF protection or session replication. Tokens survive compatible edits, not process restarts. Cookie mode bypasses cache; the dedicated cookie is stripped before origin forwarding and cannot be overridden by an origin Set-Cookie. No failed request, especially a write, is replayed on another member to obtain a successful response.

Dedicated per-vhost security headers also cover matching-host denials/errors and cache hits. HSTS is removed on plaintext; includeSubDomains/preload remain explicit opt-ins. Preload directives do not enroll a domain in a browser list. Arbitrary CSP and Permissions-Policy values are encoding-validated, not semantically audited. Old configurations retain origin headers unless an explicit policy overrides them.

Certificate uploads and custom pages (0.3.0)

Certificate upload is an authenticated local-control-plane mutation protected by Origin and CSRF validation, body/per-file bounds and two-worker admission. PEM pairs are parsed, key-matched and checked against supplied DNS names. Private immutable files use generated simple names, mode 600 and the existing no-symlink/directory lock protections. Public API responses/config/audit contain metadata, not key PEM. JavaScript clears file controls after use, but does not claim secure erasure of browser memory. Only configuration publication activates an inventory selection. No new listener or public certificate-upload endpoint is created.

Custom HTML is fully trusted administrator-authored content served on the chosen public vhost. It may contain executable HTML/scripts there; it is never previewed or inserted as HTML in the admin DOM. Do not upload untrusted markup. The fixed welcome page interpolates only the software version, not Host, URL or user input. HTML is bounded to 32 KiB per page and by the overall 256 KiB configuration limit. Responses use no-store; old representation encoding/length/cookies are discarded when replacing an origin error. Authentication challenges, Allow and Retry-After are retained, then administrator response/security rules are applied.

ACLs run before static/fallback/direct-IP pages. Even a custom status 200 for a blocked request never authorizes an upstream fetch. Such overrides can confuse clients and monitoring; retaining the original 401/403/5xx status is recommended. Direct-IP HTTPS still needs a completed TLS handshake and a suitable certificate; an HTTP welcome page cannot remove a TLS certificate-name error.

Integration boundaries in 0.4.0

Tinyauth runs after host/path ACLs and before any cached/static/origin response or WebSocket upgrade. Incoming identity headers are stripped, including after generic header rules, and only configured fields from a successful verifier are copied. The verifier gets no request body or admin session cookie. Its DNS/private-network and TLS checks match the origin safety boundary. Authentication failure cannot be turned into a 200 by custom pages. Denials and protected responses are no-store; there is no auth-result or protected-content shared cache. Existing upgraded sessions are not reauthenticated continuously.

Only configured login-origin redirects are accepted. Do not expose the fake-auth helper or treat its test cookie as an actual login. H3 uses the same routing, auth, request limits and response policies; 0-RTT is disabled. Transport resource limits do not replace rate limiting, firewalls or independent security/conformance testing. H3 is uncompiled/unexecuted in this packaging environment.

Diagnostic response fields are hidden by default, but origin secrets still need explicit response rules. In 0.5.0 the dedicated controls expose request ID and revision independently; the obsolete hide_mock_origin field is not accepted. X-Mock-Origin can be removed using ordinary response-header rules. Scope labels on listeners never enforce network restrictions. See ACME_RFC2136.md for private TSIG/account storage and the separate backup requirement for manual DNS-01 issuance.