conductor/docs/PROXY_SECURITY.md

32 lines
3.8 KiB
Markdown

# Proxy Security and Execution-History Policy
## Threat model
The REST proxy accepts destinations and request templates from project authors. Treat those values, DNS answers, redirects, upstream headers, bodies, and errors as untrusted. The proxy must prevent access to the Conductor host and private infrastructure, credential forwarding to a different origin, request smuggling, unbounded memory use, and disclosure through responses, logs, or execution history.
Conductor v0.1.0 is single-user software. This policy does not provide tenant isolation, RBAC, malware inspection, TLS interception, or protection from an already-compromised backend process.
## Destination contract
- Only `http:` and `https:` URLs without embedded credentials are accepted.
- Public destinations are allowed after every DNS result is classified. Loopback, unspecified, private, carrier-grade NAT, link-local, multicast, documentation, benchmark, reserved, and metadata-service address ranges are denied. A hostname is denied if any returned address is unsafe or DNS returns no usable address.
- Connections use a validated address rather than performing an unchecked second DNS lookup.
- Redirects are followed manually, resolved against the prior URL, and fully revalidated. At most three redirects are allowed. Authentication and author-supplied sensitive headers are removed whenever the redirect changes origin.
- Internal exceptions are server-controlled exact origins in `CONDUCTOR_PROXY_INTERNAL_ORIGINS`, separated by commas (for example `https://api.internal.example:8443`). Schemes and effective ports must match. Paths, credentials, IP literals, and wildcards are invalid; subdomains are not inferred. Exceptions never enter project JSON.
- Public hosts do not require an administrative hostname allowlist in the MVP. There are no wildcard rules. Any explicit non-default port is allowed only when its resolved addresses remain safe; deployments can constrain egress further at the network layer.
## Request and response controls
- Methods remain GET, POST, PUT, PATCH, and DELETE.
- Author-supplied request headers are limited to `Accept`, `Accept-Language`, `Content-Type`, `If-Match`, `If-None-Match`, `Idempotency-Key`, and names beginning `X-`. `Authorization` and API-key headers may only be injected from server-side secrets. Cookie, proxy, forwarding, host, connection, transfer, upgrade, content-length, and other hop-by-hop headers are prohibited.
- Request bodies are limited to 1 MiB after UTF-8 encoding. Proxy API JSON is limited to 2 MiB.
- Response bodies are limited to 5 MiB while streaming. Execution-history previews are independently limited to 2 KiB.
- The existing fixed 30-second total timeout is retained. There is no canonical per-action timeout.
- Network, DNS, TLS, timeout, malformed-response, policy, and limit failures use stable safe codes and messages. They do not include stack traces, DNS answers, private addresses, or raw transport errors.
## Execution-history contract
SQLite stores the most recent 1,000 executions globally. Each record contains its timestamp, optional project identity supplied by the runtime, action ID/name, method, sanitized URL (query values and embedded credentials redacted), upstream status when available, duration, outcome, safe error code/message, response byte count, truncation flag, content type, and a redacted preview no larger than 2 KiB. Oldest records are deleted after insertion.
History persists across restart. `GET /api/executions` supports project, action, outcome, and status filters with a maximum page size of 100. `DELETE /api/executions` clears all history and returns no records. History never stores request or response headers, cookies, credential values, sensitive query values, stack traces, DNS results, resolved addresses, or secret-resolution details.