Skip to content

feat: processes Prax starts never inherit its proxy credential - #255

Merged
praxagent merged 3 commits into
mainfrom
feat/child-env-proxy-identity
Oct 3, 2026
Merged

praxagent merged 3 commits into
mainfrom
feat/child-env-proxy-identity

Conversation

@praxagent

Copy link
Copy Markdown
Owner

Why

Audit of the Prax↔secrets-proxy channel (2026-10-01; the table is in docs/security/secrets-proxy.md):

Listener Caller auth Encryption State
:8785 model path token required (401) TLS, cert SAN includes 127.0.0.1, and Prax never disables verification ✅
:8786 forward proxy none — ❌ any local process (the dev tree, other accounts, Prax's children) gets production's keys injected

The fix is to give every forward-proxy caller its own credential (prax-secrets-proxy #5 and #6). There's a catch:

  • HTTPS_PROXY=http://prax-prod:<token>@… is exported into Prax's environment, so every child would inherit it: git, gh, uv, and plugin subprocesses running third-party code.
  • This PR closes that first, so the token can be switched on safely.

What

  • prax/services/child_env.py: subprocess.Popen hands every child its environment with the proxy URLs stripped of the credential. If CHILD_PROXY_URL is set, children get that URL instead: their own identity (e.g. prax-tools), which egress rules can narrow.
    • This covers subprocess.run/check_output and asyncio subprocesses.
    • An explicitly passed env= is cleaned too.
  • CHILD_ENV_STRIP_PROXY_CREDENTIALS defaults to on. That is deliberate: it is a no-op while the proxy URL carries no credential, which is every deployment today, so it preserves prior behaviour. Once a token is set, off means leaking it.
  • Idea credit: DeepSeek Harness's scrubbed child environments (assessment docs(research): DeepSeek Harness — adopt an enforcement self-check #253).

Verified

Live, with real git ls-remote https://github.com/praxagent/prax run as a child of a parent holding prax-prod's credential, through an authenticating mitmproxy (prax-secrets-proxy #6 code):

Mode Result
unprotected used Prax's credential, exit 0 (the leak)
stripped 407 at CONNECT
own identity exit 0 as prax-tools

Tests: 7 unit tests (stripping, explicit env, own identity, no-op without credentials, asyncio, idempotent install). make ci green: 4017 passed. Four secrets-proxy requests during the run were production's 19:00 scheduled job (3× OpenRouter, then Twilio, all at 02:00 UTC), not tests.

Rollout (after proxy #5/#6 are deployed; production .env is yours)

  1. Create proxy callers prax-prod, prax-dev and, if children need egress, prax-tools.
  2. Set PROXY_FORWARD_AUTH_TOKEN / PROXY_FORWARD_CALLERS on the proxy.
  3. Set HTTPS_PROXY=http://prax-prod:<token>@127.0.0.1:8786 in production and prax-dev in dev, plus optionally CHILD_PROXY_URL.
  4. Check: an unauthenticated curl -x http://127.0.0.1:8786 http://probe.invalid/ must return 407.

Once HTTPS_PROXY carries Prax's forward-proxy credential, every child —
git, gh, uv, plugin subprocesses running third-party code — would inherit it
and spend credentials as Prax. subprocess.Popen now hands children the proxy
URL without it, or their own identity (CHILD_PROXY_URL). On by default:
a no-op while the URL carries no credential. Idea from DeepSeek Harness's
scrubbed child environments.
@praxagent
praxagent merged commit df3ca91 into main Oct 3, 2026
1 check passed
@praxagent
praxagent deleted the feat/child-env-proxy-identity branch October 3, 2026 01:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant