Add MITM hooks for host-specific HTTPS request clamping

This commit is contained in:
viyatb-oai
2026-03-17 13:40:39 -07:00
parent da616136cc
commit d16c7aa41c
15 changed files with 1439 additions and 32 deletions

View File

@@ -5,7 +5,8 @@
- an HTTP proxy (default `127.0.0.1:3128`)
- a SOCKS5 proxy (default `127.0.0.1:8081`, enabled by default)
It enforces an allow/deny policy and a "limited" mode intended for read-only network access.
It enforces an allow/deny policy, a "limited" mode intended for read-only network access, and
host-specific HTTPS MITM hooks for request matching and header injection.
## Quickstart
@@ -32,8 +33,9 @@ allow_upstream_proxy = true
# By default, non-loopback binds are clamped to loopback for safety.
# If you want to expose these listeners beyond localhost, you must opt in explicitly.
dangerously_allow_non_loopback_proxy = false
mode = "full" # default when unset; use "limited" for read-only mode
# When true, HTTPS CONNECT can be terminated so limited-mode method policy still applies.
mode = "full" # default when unset; hooks can still clamp specific HTTPS hosts
# When true, HTTPS CONNECT can be terminated so limited-mode policy and host-specific MITM hooks
# can inspect inner requests.
mitm = false
# CA cert/key are managed internally under $CODEX_HOME/proxy/ (ca.pem + ca.key).
@@ -54,6 +56,27 @@ allow_unix_sockets = ["/tmp/example.sock"]
# DANGEROUS (macOS-only): bypasses unix socket allowlisting and permits any
# absolute socket path from `x-unix-socket`.
dangerously_allow_all_unix_sockets = false
[[permissions.workspace.network.mitm_hooks]]
host = "api.github.com"
[permissions.workspace.network.mitm_hooks.match]
methods = ["POST", "PUT"]
path_prefixes = ["/repos/openai/"]
[permissions.workspace.network.mitm_hooks.match.headers]
"x-github-api-version" = ["2022-11-28"]
[permissions.workspace.network.mitm_hooks.actions]
strip_request_headers = ["authorization"]
[[permissions.workspace.network.mitm_hooks.actions.inject_request_headers]]
name = "authorization"
secret_env_var = "CODEX_GITHUB_TOKEN"
prefix = "Bearer "
# `match.body` is reserved for a future release. Current hooks match only on
# method/path/query/headers and can mutate outbound request headers.
```
### 2) Run the proxy
@@ -86,12 +109,15 @@ When a request is blocked, the proxy responds with `403` and includes:
- `x-proxy-error`: one of:
- `blocked-by-allowlist`
- `blocked-by-denylist`
- `blocked-by-mitm-hook`
- `blocked-by-method-policy`
- `blocked-by-policy`
In "limited" mode, only `GET`, `HEAD`, and `OPTIONS` are allowed. HTTPS `CONNECT` requests require
MITM to enforce limited-mode method policy; otherwise they are blocked. SOCKS5 remains blocked in
limited mode.
MITM to enforce limited-mode method policy; otherwise they are blocked. Separately, hosts covered
by `mitm_hooks` are authoritative even when `mode = "full"`: hooks are evaluated in order, the
first match wins, and if no hook matches the inner HTTPS request is denied with
`blocked-by-mitm-hook`. SOCKS5 remains blocked in limited mode.
Websocket clients typically tunnel `wss://` through HTTPS `CONNECT`; those CONNECT targets still go
through the same host allowlist/denylist checks.
@@ -195,9 +221,12 @@ what it can reasonably guarantee.
and common private/link-local ranges. Explicit allowlisting of local IP literals (or `localhost`)
is required to permit them; hostnames that resolve to local/private IPs are still blocked even if
allowlisted (best-effort DNS lookup).
- Limited mode enforcement:
- only `GET`, `HEAD`, and `OPTIONS` are allowed
- HTTPS `CONNECT` remains a tunnel; limited-mode method enforcement does not apply to HTTPS
- HTTPS enforcement:
- in limited mode, only `GET`, `HEAD`, and `OPTIONS` are allowed
- when `mitm = true`, HTTPS inner requests can be matched by `mitm_hooks` and have request
headers rewritten before forwarding
- hooked hosts are authoritative even in `mode = "full"`: if a host has `mitm_hooks` and none
match, the request is denied
- Listener safety defaults:
- the HTTP proxy listener clamps non-loopback binds unless explicitly enabled via
`dangerously_allow_non_loopback_proxy`