ALL-35: delegate isolated Exa credentials to workers - #237
Conversation
|
Security review changes are in progress. The initial process-environment inheritance is too broad because worker startup-time MCP configuration and stdio MCP descendants could observe EXA_API_KEY before native-tool admission. I am replacing it with a post-MCP private worker control channel and adding MCP descendant/config-expansion plus durable-store leak regressions. Keep this PR OPEN and unmerged; it is not ready for Gerred review until the follow-up commit and verification land. |
There was a problem hiding this comment.
Stale comment
Security review found one high-severity issue:
EXA_API_KEYis re-injected into the trusted__workerprocess environment, which workerexec_command(brokerless) and host stdio MCP can recover despite child-env stripping and parent stdout/stderr redaction.Sent by Cursor Security Agent: Security Reviewer
|
Security review follow-up is complete in signed commit The worker no longer inherits New regression coverage verifies:
Final local verification is green: focused worker suites, 1,189 nac-core tests (1,180 passed / 9 ignored), and the complete The PR remains open and unmerged for Gerred's explicit review against ALL-22. |
|
Final hosted verification is complete: every PR check is green, including macOS and Linux builds, core/server tests, contract, lint, managed-image quality and build-smoke, CLA, Cursor Bugbot, and Cursor Security Agent. The PR remains open and unmerged for Gerred. |
|
Security follow-up reopened: the current stdin control frame may be recoverable by a same-UID startup-time MCP child through procfs while bytes are buffered. I am replacing it with a dedicated non-inherited channel plus a post-MCP readiness handshake and adversarial procfs coverage. Keep this PR open and unmerged; it is not ready for Gerred review. |
|
The reopened HIGH security follow-up is resolved in signed commit The retired stdin transport has been replaced by an anonymous Unix socketpair. Its inherited worker endpoint is marked close-on-exec before MCP construction, stdin is cancellation-only, and the parent does not write credential bytes until the worker completes MCP construction and sends the readiness frame. The receiver accepts exactly one bounded/versioned frame and requires EOF, rejecting malformed, partial, oversized, trailing, or closed-peer input without echoing payloads. Linux server/worker processes additionally set Adversarial regressions cover environment, argv, stdin, inherited descriptors, Local verification is green, including the complete |
d1bc89b to
eaf1ffb
Compare
|
Final review repairs are pushed in signed commit
Post-rebase local |
|
Exact-head verification for
The branch is signed and clean. This PR remains intentionally open and unmerged pending all hosted checks, a fresh exact-head security review, and Gerred's explicit review. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit df43a6e. Configure here.



Summary
web_searchandweb_fetchEXA_API_KEYat managed-server startup, remove it from the generic environment before configuration/MCP/background construction, and reserve the snapshot for direct native web plus worker dispatchSO_PEERCRED; send the bounded credential frame only after post-MCP readinessSecurity boundary
${EXA_API_KEY}expansion, MCP descendants, and model-controlled commandsno_new_privsbefore opening the authenticated parent endpointCAP_SYS_PTRACEappears inCapInh,CapPrm,CapEff,CapBnd, orCapAmb, or if those fields cannot be parsed exactlyOrdinary local/unmanaged servers and workers do not receive these irreversible process controls or delegated credential channels. A same-UID Linux process can still discover, unlink, or flood the socket path and cause denial of service, but cannot authenticate as either peer to read or inject the credential. The boundary assumes an unprivileged deployment without
CAP_SYS_PTRACE, privileged-container escape, weakened host inspection controls, kernel compromise, or a compromised NAC process. macOS retains the inherited socket/readiness protections but has no equivalent Linuxprctl/procfs isolation guarantee. Stronger mutual isolation requires separate privileges or an external credential broker.Verification at
df43a6e4e26efe3a835513a4c9142c5cc98e64fdmake ci— formatting, clippy, source size, 1,215 nac-core tests (1,206 passed, 9 ignored), 162 nac-server library tests, 24 binary tests, 286 web tests, API contract, typecheck, production web build, and static managed-image contractmake test-durabilitymake test-managed-image— fresh Linux/amd64 release build plus readiness, restart, SIGTERM, runtime inventory, and Git LFS smoke__worker→ native Exaweb_search/web_fetch, direct native web, cancellation during a hanging search, malformed Exa JSON, worker cleanup, generic stdio/HTTP MCP isolation, and canary absence from logs, snapshots, transcripts, files, and durable storeReview and rollout
Leave this PR OPEN and unmerged for Gerred's explicit review. Gerred should confirm this NAC worker boundary matches the ALL-22 Kubernetes
Secret/secretKeyRefdelivery before merge or managed-runtime publication.No real Exa key was requested or used. Tests and E2E use obvious fake canaries and isolated local HTTPS doubles. Platform projection, rotation, restart, shared throttling/429 policy, and enablement remain outside this PR under ALL-22.
Note
High Risk
Changes authentication-adjacent credential handling, process hardening, and worker/MCP startup ordering; mistakes could leak keys to untrusted MCP descendants or break managed deployments.
Overview
Managed NAC orchestrator workers can now get native
web_search/web_fetchwhen the server has a usable Exa key, without putting that key in the worker environment or MCP expansion paths.The agent replaces a single
web_retrieval_eligibleflag withNativeWebCapabilities(direct vs worker vs disabled) and a newworker_credentialspath: on managed startup the server snapshotsEXA_API_KEY, strips it from the process environment before config/MCP/background work, and uses the snapshot only for direct native web and worker dispatch. Managed hosts spawn workers with a private Unix channel (Linux: mode-0600 socket + mutualSO_PEERCRED; other Unix: inherited close-on-exec fd); credentials are sent only after the worker signals post-MCP readiness, then applied viaset_worker_web_credential. Worker stdout/stderr and debug output are redacted; ordinary local workers stay unchanged.Hardening and ops: Linux managed server/worker processes opt into
no_new_privsand non-dumpable mode; the managed image entrypoint rejectsCAP_SYS_PTRACE. Docs, contract scripts, debug-only Exa TLS/proxy hooks, an E2E Exa double, and broad adversarial/integration tests cover MCP isolation, framing, cancellation, and canary absence from retained state.Reviewed by Cursor Bugbot for commit cf5914b. Bugbot is set up for automated code reviews on this repo. Configure here.