feat: add trusted process environment values - #1684
Conversation
🦋 Changeset detectedLatest commit: 3b2202f The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c047a9d02d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
c047a9d to
6e3c2f4
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e3c2f40d7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
6e3c2f4 to
6e5f12f
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e5f12f4f1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
6e5f12f to
fea5d15
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fea5d1504e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fea5d1504e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
fea5d15 to
f201163
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f201163363
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
f201163 to
3d74f41
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3d74f41aa9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
3d74f41 to
9429201
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9429201af8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
9429201 to
d456e8e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d456e8e0c2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
d456e8e to
266282e
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 266282e61f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
b4ccd38 to
7ea1e21
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ea1e21eb9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
7ea1e21 to
579a562
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 579a5626f4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
579a562 to
fd6ed1b
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd6ed1b1ed
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
9615a38 to
2ba2038
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2ba20383a9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
2ba2038 to
f32f3de
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f32f3deac1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
f32f3de to
3b2202f
Compare
ErenAta16
left a comment
There was a problem hiding this comment.
Read this as a security review rather than a style one, and ran the invariant in the description rather than reading for it. The design holds where it matters most: a ProcessEnvValue that was never granted fails closed on both paths.
fresh instance, same variable name, no grant
assertProcessEnvironmentAccessBound throws "The configured sandbox client cannot prepare ProcessEnvValue references..."
resolve() throws "ProcessEnvValue must be resolved through a sandbox client with explicit process environment access."
serialize() returning only {name, description} is the right shape too, and keeping the source in a side table rather than on the object is what makes the persisted marker safe.
One case does not hold: the grant travels with the object, not with the manifest.
processEnvironmentSources is WeakMap<ProcessEnvValue, string>, so once an instance is bound it carries that authority into any other manifest that reuses the same object. Measured on 3b2202f:
A: manifest granted SANDBOX_TOKEN -> HOST_TOKEN
resolve() = super-secret-value expected
B: a second manifest, same ProcessEnvValue instance, no grant configured at all
assertProcessEnvironmentAccessBound(B) PASSED
resolve() = super-secret-value
Neither gate stops B, and for different reasons:
assertProcessEnvironmentAccessBound compares processEnvironmentSources.get(value) against value.name ?? destination. Both are properties of the instance, so a reused instance satisfies it without the second manifest ever being configured. It is the gate on the live path, at runtime/manager.ts:927, runtime/manager.ts:2066 and runtime/sessionState.ts:477.
invalidProtectedProcessEnvironmentReferences is manifest-keyed and would catch it, but it opens with
const bindings = processEnvironmentBindings.get(manifest);
if (!bindings) {
return [];
}so an unbound manifest returns no invalid references rather than flagging every reference in it. It also only runs from manifestPersistence.ts:206, on serialization.
On severity. The manifest is authored by the SDK user, so this is not an externally reachable path, and I would not call it an exploit. It is a hardening gap against an ordinary mistake: hoisting const SANDBOX_TOKEN = new ProcessEnvValue({ name: 'HOST_TOKEN' }) to module scope and reusing it across several sandbox configurations is a natural thing to write, and only some of those configurations need to be granted for all of them to resolve. The description says a reference resolves only when "trusted client configuration grants the exact destination and source pair", and for manifest B no configuration granted anything.
Two shapes that would close it, and I have no preference:
Key the authority on the pair, WeakMap<Manifest, WeakMap<ProcessEnvValue, string>> or an equivalent composite, so a grant cannot outlive the manifest it was issued for.
Or record the granting manifest on the binding and have assertProcessEnvironmentAccessBound check identity, which is a smaller change but leaves the authority conceptually attached to the object.
The second gate is worth a look regardless. if (!bindings) return [] reads as "nothing to validate" when the safer reading for a manifest containing ProcessEnvValue references is "nothing was granted, so every reference is invalid".
Happy to send either as a PR, or a failing test first if you would rather see it pinned before deciding the shape.
Verified on Windows 11 / Node 24.16.0, pnpm exec vitest --project "@openai/agents-core".
This pull request adds trusted process environment references to the JavaScript Agents SDK, bringing the sandbox capability introduced in
openai/openai-agents-python#4408to the Docker and Daytona providers.Background
Sandbox manifests currently support literal environment values and custom environment resolvers. Literal values can be serialized into persisted manifests and session state, while arbitrary resolvers do not provide a safe, provider-neutral contract for accessing the SDK host process environment.
This change introduces
ProcessEnvValue, a serializable reference that identifies a process environment variable without serializing its value or granting access to it. Host-environment authority remains exclusively in trusted runtime configuration.see also: openai/openai-agents-python#4408
Trusted access configuration
Docker and Daytona clients can explicitly authorize process environment access using either:
allowedProcessEnvironmentKeysfor same-name mappings.processEnvironmentBindingsfor destination-to-source mappings.For example, a manifest may declare
SANDBOX_TOKENas a reference toHOST_TOKEN, while the client separately grants the exactSANDBOX_TOKEN -> HOST_TOKENbinding.A reference resolves only when all of the following are true:
Missing, malformed, conflicting, or ungranted bindings fail before provider-side sandbox creation or mutation begins.
Serialization and resume behavior
Serialized manifests and sandbox session state retain only the
ProcessEnvValuereference metadata. They never contain:Deserialized state must be rebound using current trusted client configuration. Docker and Daytona resume protected sessions by creating a replacement resource with the current host values and retiring the previous resource only after the replacement has been created successfully. This supports credential rotation without treating persisted state as a source of host-secret authority.
Run-scoped client options are forwarded through manifest preparation, deserialization, and resume so constructor-scoped and per-run grants follow the same contract.
Provider behavior
Docker passes protected values only through the container creation environment. Daytona passes them only through the provider-native sandbox creation environment.
After creation, protected destinations are removed from ordinary execution paths, including:
Other sandbox providers currently reject manifests containing
ProcessEnvValuebefore invoking their provider APIs. Preconstructed or injected sandbox sessions are also rejected because the SDK cannot verify that those sessions were created through a trusted protected-environment transport.Callers can continue using ordinary explicit manifest environment values when persistence is acceptable or when a provider does not support
ProcessEnvValue.Error and telemetry protection
Once a protected reference has been bound, provider lifecycle failures are converted to generic
SandboxLifecycleErrorinstances. Raw provider errors, cleanup failures, nested causes, response bodies, and process output are not retained in caller-visible error graphs.The redaction boundary is applied before sandbox tracing and event emission, preventing protected values from being recorded by custom spans, JSONL sinks, HTTP event sinks, or downstream error serialization.
Cleanup and replacement paths preserve safe lifecycle facts needed to diagnose incomplete cleanup without retaining the protected value or the original secret-bearing exception graph.
Compatibility
Existing string values, resolver functions, custom
EnvValueReferenceimplementations, manifests, sandbox sessions, mount behavior, and provider configuration remain unchanged when a manifest does not containProcessEnvValue.