Commit Graph
8 Commits
Author SHA1 Message Date
989f55defa feat(network-proxy): experimental local credential broker (#28034)
## Why

Codex child processes can inherit injectable local credentials directly,
which lets commands read and exfiltrate the real values. This
experimental slice keeps supported workflows working while moving those
credentials behind the managed network proxy.

This PR contains only the proxy-owned broker implementation. The Codex
config and runtime integration is stacked separately in #29752.

## What changed

- discover supported credentials during child setup, retain real values
only in the in-memory proxy broker, and replace them with shaped dummy
values
- require a presented dummy to select a stored credential and preserve
unrelated explicit authorization headers
- bind GitHub cloud, GitHub Enterprise, and OpenAI credentials to their
intended hosts
- inject credentials only into TLS traffic by default; plaintext
injection requires the explicit dangerous opt-in
- use TLS ClientHello routing for CONNECT so non-TLS protocols remain
opaque tunnels
- expose a pure API that identifies environment keys still holding
broker-generated dummies without mutating the caller's environment

## Scope

- supported credentials: `GH_TOKEN`, `GITHUB_TOKEN`,
`GH_ENTERPRISE_TOKEN`, `GITHUB_ENTERPRISE_TOKEN`, and `OPENAI_API_KEY`
- GitHub cloud credentials match `github.com`, `api.github.com`, and
`*.ghe.com`
- GitHub Enterprise credentials match only the normalized non-cloud
`GH_HOST`
- OpenAI API keys match only `api.openai.com`
- this does not cover SSH agents, kube client certificates, filesystem
secret discovery, or context-injected secret scrubbing

## Validation

- `just test -p codex-network-proxy` (191 passed)
- focused opaque CONNECT, plaintext opt-in, dummy-selection, and
child-isolation regressions passed
- scoped Clippy check for `codex-network-proxy` passed

---------

Co-authored-by: viyatb-oai <viyatb@openai.com>
Co-authored-by: Codex <noreply@openai.com>
2026-06-24 13:21:16 -07:00
Winston Howesandviyatb-oai c5a9a95ab6 Keep managed MITM CA private keys in proxy memory (#29013)
## Why

The managed MITM trust bundle must be readable by sandboxed commands.
Persisting its sibling CA private key under `$CODEX_HOME/proxy`
therefore requires a deny-read sandbox rule, but the Windows unelevated
backend rejects deny-read paths and WSL1's legacy Landlock path cannot
enforce that rule.

A persistent OS credential store also does not provide the same
cross-platform boundary from other processes running as the same user.
Keeping the signer inside the network proxy process avoids both
problems: ordinary sandbox setup stays independent of CA-key state, and
no private signing key is exposed through the filesystem or a persistent
credential record.

## What

- generate one managed CA per proxy process and retain its private
signer only in proxy memory
- emit only content-addressed public CA certificates and trust bundles
under `$CODEX_HOME/proxy`
- hold a cross-process lease for each active public certificate and
prune artifacts from inactive proxy processes
- keep all CA ownership in `codex-network-proxy`; no `codex-core` or
sandbox-policy changes
- validate generated trust-bundle paths by their content hash
- keep the public bundle readable by sandboxed commands on Windows,
WSL1, macOS, and Linux

The independent startup custom-CA follow-up is #29014.

## Validation

- `CODEX_HOME=/private/tmp/codex-test-home-network-proxy just test -p
codex-network-proxy` (179 tests)
- `just bazel-lock-check`
- `just fix -p codex-network-proxy`
- `just fmt`

---------

Co-authored-by: viyatb-oai <viyatb@openai.com>
2026-06-23 12:20:51 -07:00
Winston Howes 527ccb4a5d Honor startup custom CA bundles with managed MITM (#29014)
## Why

When Codex starts with a custom CA override such as
`SSL_CERT_FILE=/path/to/corp-ca.pem codex`, `rustls-native-certs` treats
that override as a replacement for the platform trust store. The managed
proxy then rewrites child CA variables to its generated bundle, so the
custom root or the ordinary platform roots can be lost. The proxy's
upstream TLS connector must trust the same roots or private and
corporate upstream certificates still fail after interception.

## What

- load platform-native roots without consulting inherited CA override
variables
- append certificates from the existing curated startup CA file
variables and `SSL_CERT_DIR`
- share those platform and startup roots with the MITM upstream rustls
connector
- exclude the Codex managed MITM CA from upstream trust
- normalize OpenSSL `TRUSTED CERTIFICATE` blocks while dropping trailing
trust metadata
- skip an inherited current Codex-managed bundle so nested launches do
not duplicate it
- append the Codex managed MITM CA to the child-facing bundle
- copy certificate material only, so a private key or unrelated text
colocated in a startup file is never exposed through the public bundle

This is intentionally limited to CA paths present when Codex starts. It
does not parse inline shell assignments or add per-command bundle
materialization.

This changes only `codex-network-proxy` and dependency metadata; it does
not touch `codex-core` or sandbox orchestration.

## Validation

- `just test -p codex-network-proxy`
- includes an end-to-end upstream TLS test using a server trusted only
by the startup custom CA
- `just fix -p codex-network-proxy`
- `just bazel-lock-check`
2026-06-22 14:16:48 -07:00
Winston Howes 472619f9fc Add SOCKS5 TCP MITM coverage (#22685)
## Summary
- reuse the MITM HTTPS serving path for raw SOCKS5 TCP streams
- route limited-mode and hooked SOCKS5 TCP requests through MITM before
dialing upstream
- keep SOCKS5 UDP limited-mode behavior unchanged

## Validation
- `just fmt`
- `just test -p codex-network-proxy`
- `just fix -p codex-network-proxy`
- `git diff --check`
2026-06-09 13:08:01 -07:00
evawong-oaiandWinston Howes 3cae84009a Use named MITM permissions config (#18240)
## Stack
1. Parent PR: #18868 adds MITM hook config and model only.
2. Parent PR: #20659 wires hook enforcement into the proxy request path.
3. This PR changes the user facing PermissionProfile TOML shape.

## Why
1. The broader goal is to make MITM clamping usable from the same
permission profile that already controls network behavior.
2. This PR is the config UX layer for the stack. It moves MITM policy
into `[permissions.<profile>.network.mitm]` instead of exposing the flat
runtime shape to users.
3. The named hook and action tables belong here because users need
reusable policy blocks that are easy to review, while the proxy runtime
only needs a flat hook list.
4. This PR validates action refs during config parsing so mistakes in
the user facing policy fail before a proxy session starts.
5. Keeping the lowering here lets the proxy keep its simpler runtime
model and lets PermissionProfile remain the single source of network
permission policy.

## Summary
1. Keep MITM policy inside `[permissions.<profile>.network.mitm]` so the
selected PermissionProfile owns network proxy policy.
2. Use named MITM hooks under
`[permissions.<profile>.network.mitm.hooks.<name>]`.
3. Put host, methods, path prefixes, query, headers, body, and action
refs on the hook table.
4. Define reusable action blocks under
`[permissions.<profile>.network.mitm.actions.<name>]`.
5. Represent action blocks with `NetworkMitmActionToml`, then lower them
into the proxy runtime action config.
6. Reject unknown refs, empty refs, and empty action blocks during
config parsing.
7. Keep the runtime hook model unchanged by lowering config into the
existing proxy hook list.
8. Preserve the #20659 activation fix for nested MITM policy.

## Example
```toml
[permissions.workspace.network.mitm]
enabled = true

[permissions.workspace.network.mitm.hooks.github_write]
host = "api.github.com"
methods = ["POST", "PUT"]
path_prefixes = ["/repos/openai/"]
action = ["strip_auth"]

[permissions.workspace.network.mitm.actions.strip_auth]
strip_request_headers = ["authorization"]
```

## Validation
1. Regenerated the config schema.
2. Ran the core MITM config parsing and validation tests.
3. Ran the core PermissionProfile MITM proxy activation tests.
4. Ran the core config schema fixture test.
5. Ran the network proxy MITM policy tests.
6. Ran the scoped Clippy fixer for the network proxy crate.
7. Ran the scoped Clippy fixer for the core crate.

---------

Co-authored-by: Winston Howes <winston@openai.com>
2026-05-20 17:10:37 -07:00
evawong-oai f6970214d2 Wire MITM hooks into runtime enforcement (#20659)
## Stack
1. Parent PR: #18868 adds MITM hook config and model only.
2. This PR wires runtime enforcement.
3. User facing config follow up: #18240 moves MITM policy into the
PermissionProfile network tree.

## Why
1. After the hook model exists, the proxy needs a separate behavior
change that can be tested at the request path.
2. This PR makes hooked HTTPS hosts require MITM, evaluates inner
requests after CONNECT, mutates headers for matching hooks, and blocks
hooked hosts when no hook matches.
3. It also fixes the activation path so a permission profile with MITM
hook policy starts the managed proxy.
4. Keeping this separate from #18868 lets reviewers focus on runtime
effects, telemetry, and request mutation.

## Summary
1. Store compiled MITM hooks in network proxy state.
2. Require MITM for hooked hosts even when network mode is full.
3. Evaluate inner HTTPS requests against host specific hooks.
4. Apply hook actions by replacing request headers before forwarding.
5. Block hooked hosts when no hook matches and record block telemetry.
6. Treat profile MITM hook policy as managed proxy policy so the proxy
starts when needed.
7. Keep the duplicate authorization header replacement and query
preserving request rebuild in this runtime PR.
8. Add runtime tests and README guidance for hook enforcement.

## Validation
1. Ran the network proxy MITM policy tests.
2. Ran the hooked host CONNECT test.
3. Ran the authorization header replacement test.
4. Ran the core permission profile proxy activation test for MITM hooks.
5. Ran the scoped Clippy fixer for the network proxy crate.
6. Ran the scoped Clippy fixer for the core crate.
2026-05-20 14:08:14 -07:00
viyatb-oaiandCodex e1ba87ccb2 fix(network-proxy): recheck network proxy connect targets (#19999)
## Why
The proxy checks the requested host before opening the upstream
connection, but DNS can resolve an allowed hostname to a loopback,
private, or other non-public address after that first decision. Without
a final check on the actual socket target, a request that looks
acceptable at the hostname layer can still connect to a local service
once resolution completes.

## What changed
- add a shared TCP connector check for direct proxy egress
- use that path for HTTP, `CONNECT`, SOCKS5, and MITM upstream
connections
- keep configured upstream proxy hops on the existing proxy path
- add direct-connector coverage for allowed and rejected local targets

## Security impact
Direct proxy egress now rechecks the resolved socket address before
connecting, closing the gap between hostname policy evaluation and the
final network target.

## Verification
- `cargo test -p codex-network-proxy`

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-28 12:51:43 -07:00
viyatb-oai 8d3d58f992 feat(network-proxy): add MITM support and gate limited-mode CONNECT (#9859)
## Description
- Adds MITM support (CA load/issue, TLS termination, optional body
inspection).
- Adds `codex-network-proxy init` to create
`CODEX_HOME/network_proxy/mitm`.
- Enforces limited-mode HTTPS correctly: `CONNECT` requires MITM,
otherwise blocked with `mitm_required`.
- Keeps `origin/main` layering/reload semantics (managed layers included
in reload checks).
- Centralizes block reasons (`REASON_MITM_REQUIRED`) and removes
`println!`.
- Scope is MITM-only (no SOCKS changes).

gated by `mitm=false` (default)
2026-02-24 18:15:15 +00:00