10 KiB
RustProxy 0.31.0 - API, panel and HTTP cache-maintenance security review
Scope: source snapshot supplied for the v0.31.0 maintenance follow-up, reviewed
2026-10-10. This is a code/contract review with offline regressions, not a
penetration test or proof of production safety. The supplied archive has no
.git directory; the review does not establish parity with remote master.
Interfaces and trust boundaries
| Surface | Exposure | Authentication and mutation rules | Assessment |
|---|---|---|---|
Public administration bootstrap (/, login JS/CSS, /api/auth/status, setup/login POST) |
Login/public administration listener | Host/origin validation; request marker for unsafe bootstrap actions; one-time setup capability and login throttling | Source-reviewed; live browser flow pending |
| Private panel HTML, JS, documentation, OpenAPI | Administration listener | Administrator session; Cache-Control: no-store; CSP, frame and MIME protections |
Source and anonymous-response test reviewed; runtime pending |
/api/status, /api/system-info, /api/traffic, /api/cache, logs, config, preferences, audit |
Administration listener | Administrator cookie session; sensitive reads not on anonymous allowlist | Source and regression tests added; runtime pending |
/api/events, live-log SSE |
Administration listener | Session on subscribe and repeated validity checks; bounded viewers; heartbeat/disconnect cleanup | Source-reviewed; reconnect/load pending |
| State-changing admin APIs (including cache/config/preferences) | Administration listener | Valid session, Origin/Host, X-RustProxy-Request: 1, CSRF token; audit on cache commands |
Source and regression tests added; runtime pending |
Certificate API (/api/certificates/{id}/reload, deploy) |
Administration listener | Narrow-scoped Key ID + Bearer grant; no general read access; HTTPS required remotely; origin validation when supplied | Source-reviewed; token rotation/revocation live tests pending |
Public BAN/PURGE |
Configured public vhost listener | No admin session: separate explicit IP/CIDR allowlist (empty by default), matched listener/vhost/ACL and optional rate limit | Hardened below; reverse/HTTP tests pending |
| Separate Prometheus metrics exporter | Distinct optional listener | Configured IP CIDRs and bearer-token policy; not the admin session | Unchanged; deployment exposure audit pending |
Findings addressed in this follow-up
- E0716 / compilation defect (high functional impact).
error()accepts&'static str; a reference toformat!(...)was a temporary. Invalid selector errors now log the detailed reason server-side and return a fixed, non-sensitive message with status 422. This removes the reported lifetime violation; the Rust compiler must still verify the entire crate. - Cache protocol-scope confusion (medium). Path-only
BAN/PURGEselectors could affect representations of the same host/path across both HTTP and HTTPS. Targets are now built with the trusted external scheme, validated tohttp/https, and the matched Host/vhost. IPv6 literal Hosts are bracketed for the URL parser. Other tenants, schemes and hosts remain outside the selector. - Unbounded blocking maintenance work (medium availability risk). Cache
invalidation may scan hot/cold entries. Both public HTTP and authenticated
admin cache purge/selective invalidation share two maintenance slots and
execute scans with
spawn_blocking. Bursts receive 429 instead of piling up unbounded blocking work on Tokio core threads. The permit stays with the worker after a client disconnects. This is a concurrency bound, not a per-client rate quota or a hard time limit for disk work. - Ambiguous maintenance input (medium). Duplicate TTL/confirmation or
Content-Lengthheaders, transfer-encoded bodies, nonempty bodies and upgrade requests are rejected;Content-Length: 0remains compatible with CLI clients. TTL is limited to 1..604800 s. BroadBAN /requires the explicit confirmation header;PURGEcannot use BAN-only controls. - Audit ordering (low/medium). Removal of an administrator-created BAN rule now records the audit entry before mutating state. Unavailable audit storage blocks the mutation rather than allowing an unaudited removal.
- Operator safety/usability (low). An EN/PL help popover beside the HTTP
allowlist gives exact
curlsyntax, IP-only authentication semantics and reverse-proxy identity requirements. No new global config variable is added.
Existing protections checked in source
- Admin router's exact anonymous method/path allowlist contains only the
expected authentication bootstrap APIs; private docs and assets remain
session-protected. Request guard rejects duplicate Host/Origin and checks
browser
Sec-Fetch-Sitecross-site signals. - Mutation guard uses an Origin/Host match, per-session CSRF comparison and
X-RustProxy-Requestmarker; cookie sessions are HttpOnly/SameSite=Strict and use Secure under HTTPS/trusted forwarded protocol. - Secure response policy includes CSP,
X-Frame-Options: DENY,X-Content-Type-Options: nosniff, referrer restrictions and no-store for private material. A static scan checked 27 first-party browser JS files for direct unsafe HTML injection and dynamiceval/Functionsinks; this scan cannot establish that the entire DOM is XSS-free. - IP trust comes from the transport peer or a validated forwarding chain only
when the peer is configured trusted. An untrusted client-supplied XFF does
not independently grant BAN/PURGE permission. The cache allowlist rejects
/0, invalid CIDRs, duplicates and more than 32 entries. Requests are never forwarded upstream. - Certificate API tokens have explicit operation/ID grants and cannot use the general admin read API; Bearer grant operations are intentionally separate from cookie + CSRF authentication.
HTTP maintenance CLI (allowlisted client only)
# One URL, including the query string: 200 with JSON result.
curl -i -X PURGE 'https://site.example/assets/app.js?v=3'
# Lazily ban previously cached objects under this path: 202 with JSON result.
curl -i -X BAN 'https://site.example/assets/'
# Entire host: explicit opt-in confirmation header.
curl -i -X BAN 'https://site.example/' -H 'X-RustProxy-Confirm-Wide: 1'
# Optional BAN expiration (30 seconds).
curl -i -X BAN 'https://site.example/assets/' -H 'X-RustProxy-Ban-Ttl: 30'
Use Settings -> Cache -> HTTP BAN / PURGE IP allowlist to grant the caller IP/CIDR. This HTTP interface does not accept admin cookies/tokens as an alternative to the allowlist. The domain, Host header, external scheme and listener must select the intended vhost. Behind a reverse proxy, forward the non-standard methods untouched and replace, rather than append untrusted, XFF/Forwarded headers at the edge. Never add the entire reverse-proxy subnet as a maintenance client merely because it is trusted for forwarding.
Release security test plan (requires compiled RustProxy)
- On the deployment host, run
cargo fmt --all -- --check,./dev.sh check,./dev.sh test, and./dev.sh release. Address any compiler/regression errors before installation.cargo auditor an equivalent advisory scan requires an up-to-date advisory DB and was not run in this offline environment. - Start a disposable instance with a populated cache under both HTTP and
HTTPS for the same vhost/URL. Confirm
PURGEreturns 200 and drops the exact query variant only;BANreturns 202 and invalidates only older entries on the URL prefix. Confirm the other scheme and vhost stay hot. - From a denied IP, expect 403 on
BANandPURGE. With an empty allowlist, all clients must be denied. Send duplicate TTL/confirmation/Content-Length, TE/body andBAN /without confirmation: expect 400. On a trusted-proxy hop with missing real client identity, expect 403. Test both IPv4 and IPv6. - From an allowed IP, send 10 concurrent broad maintenance requests; confirm that only two workers run simultaneously and excess return 429. Verify server CPU/IO and audit entries while the cold tier is populated.
- Send GET requests without admin cookies to
/api/config,/api/status,/api/system-info,/api/events,/api/logs,/docs/openapi.jsonand/assets/app.js; expect 401 and protective headers. With valid cookie but missing/bad Origin, marker or CSRF on PUT/POST/DELETE, expect 403. Test logout and password/session invalidation, live SSE reconnect/expiry. - Test the Certificate API with no grant, a valid certificate-specific grant,
revoked token, HTTP remote peer, and misuse against
/api/config/logs. Check errors for token disclosure and audit coverage. - Test actual browser startup, CSP console, output escaping and form save
with malicious HTML strings; inspect reverse-proxy Host/Origin forwarding.
Prefer HTTPS administration with a strict
allowed_hostslist.
Residual risk / non-claims
- Not executed in this environment: Cargo format/check/tests/release, actual Rust listener requests, HTTP/2/3, fuzzing, penetration tests, session revocation under load, proxy deployment configuration, dependency CVE scanning and long-running cold-cache resource measurements.
- Proxy trust configuration is security-critical. A misconfigured edge that accepts forged forwarded client addresses can let external users impersonate an allowlisted IP. Restrict direct listener reachability and sanitize headers.
- A public IP allowlist is not user authentication; anyone using an allowed IP/network can issue destructive maintenance commands. Use narrow CIDRs and optionally enforce additional controls on the edge (mTLS, firewall).
- The two-worker concurrency bound mitigates bursts, not all denial-of-service scenarios: configured cache size and storage latency still determine scan cost. Per-IP quotas are not provided here.
- Proxy protocol path, certificate verification, arbitrary upstream code, all application content and third-party packages are not certified safe by this audit. Production acceptance remains open until the runtime test plan is completed.