Skip to content

[Bug]: Codex turns reset sandbox network access to false in Auto and Auto-accept-edits modes #13987

Open

Description

@famesjranko

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. On a Linux T3 server, open Settings > Providers for that environment and set Codex "Launch arguments" to -c sandbox_workspace_write.network_access=true.
  2. Start a new Codex thread in Auto mode.
  3. Ask the agent to run gh api user --jq .login.

Expected behavior

The command runs inside the workspace-write sandbox with network access, because Codex is configured with sandbox_workspace_write.network_access = true.

Actual behavior

The sandbox has no network access. The command fails:

Get "https://api.github.com/user": proxyconnect tcp: dial tcp 127.0.0.1:43117: socket: operation not permitted

The Codex rollout for the turn records "sandbox_policy":{"type":"workspace-write","network_access":false,...}. The codex app-server process does have -c sandbox_workspace_write.network_access=true on its command line.

The thread starts with the correct policy. I sent the same thread/start request that T3 sends (sandbox: "workspace-write", approvalPolicy: "on-request") to a separate codex app-server started with the same -c argument. The response contained "networkAccess": true.

The value changes at the turn. buildTurnStartParams sends sandboxPolicy: runtimeModeToTurnSandboxPolicy(input.runtimeMode) on every turn. For Auto and Auto-accept-edits, that function returns { type: "workspaceWrite" } with no networkAccess field. Codex treats the missing field as false, and the turn policy replaces the thread policy that came from the configuration.

function runtimeModeToTurnSandboxPolicy(
input: RuntimeMode,
): EffectCodexSchema.V2TurnStartParams__SandboxPolicy {
switch (input) {
case "approval-required":
return {
type: "readOnly",
};
case "auto-accept-edits":
case "auto":
return {
type: "workspaceWrite",
};
case "full-access":
default:
return {
type: "dangerFullAccess",
};
}
}
function buildCodexTurnInstructions(input: {
readonly interactionMode?: ProviderInteractionMode;

sandboxPolicy: runtimeModeToTurnSandboxPolicy(input.runtimeMode),

As a result, the documented Codex setting and T3's own Launch arguments field have no effect in sandboxed modes. The only mode with network access is Full access, which removes the sandbox and all approvals. gh auth status also reports this failure as "The token in ... is invalid", which is misleading.

A possible fix is to build the turn policy from the thread's effective sandbox value, which thread/start returns, and change only its type. Another option is to send sandboxPolicy only when the runtime mode changes. Either option keeps the user's Codex settings for network access and writable roots.

Impact

Major degradation or frequent failure

Version or commit

T3 server 0.0.42; same code on main at 6391be2

Environment

T3 server on Debian 13 as a systemd user service; T3 desktop 0.0.42 on Windows as a remote client; Codex CLI 0.157.0; Auto mode

Logs or stack traces

Codex rollout turn_context for the failing turn:

"approval_policy": "on-request",
"approvals_reviewer": "auto_review",
"sandbox_policy": {"type": "workspace-write", "network_access": false, "exclude_tmpdir_env_var": false, "exclude_slash_tmp": false}

Screenshots, recordings, or supporting files

No response

Workaround

None in a sandboxed mode. Escalated commands can reach the network after approval.

Related: #6415, which asked for Codex sessions to inherit configured permission profiles and was moved to Discussions.

Activity

  1. juliusmarminge commented on Sep 27, 2026

    @juliusmarminge
    Member

    Triage

    Confirmed on current main. This is a bug, and it is not a duplicate of #6415 (that request was to inherit named Codex permission profiles and now lives in discussion #6976).

    thread/start and thread/resume only send a sandbox mode. For Auto and Auto-accept-edits that mode is "workspace-write", so Codex resolves sandbox_workspace_write.network_access (and writable roots) from config and launch arguments. That matches the networkAccess: true result from a standalone thread/start with the same -c flag.

    Every turn/start then replaces that resolved policy. buildTurnStartParams always sends sandboxPolicy: runtimeModeToTurnSandboxPolicy(runtimeMode), and for both of those modes the policy is only { type: "workspaceWrite" }:

    function runtimeModeToTurnSandboxPolicy(
      input: RuntimeMode,
    ): EffectCodexSchema.V2TurnStartParams__SandboxPolicy {
      switch (input) {
        case "approval-required":
          return { type: "readOnly" };
        case "auto-accept-edits":
        case "auto":
          return { type: "workspaceWrite" };
        // ...
      }
    }

    turn/start's sandboxPolicy is defined as an override for this turn and subsequent turns. On workspaceWrite, networkAccess defaults to false and writableRoots defaults to [], so the omitted fields wipe the config Codex had already applied. The rollout value "network_access": false is that override, not the launch argument failing to reach codex app-server. Full access is unaffected because dangerFullAccess has no network flag. The gh auth status "token invalid" line is gh misreading the denied proxy dial (127.0.0.1:43117: operation not permitted).

    The policy is resent on purpose so a runtime-mode change sticks. A fix should keep that, and preserve the config-resolved workspace-write fields (networkAccess, writableRoots, and the tmp exclusions) instead of hardcoding networkAccess: true. CodexSessionRuntime.test.ts currently expects the bare { type: "workspaceWrite" } policy, so those assertions need to move with the fix.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Sep 27, 2026
  3. highmanphil commented on Oct 13, 2026

    @highmanphil

    Still present on 0.0.46-nightly.20261012.3010. The turn defaults now live in codexRuntimeModeTurnDefaults in apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts, which still returns { type: "workspaceWrite" } for Auto and Auto-accept-edits. Configured writable_roots get dropped the same way as network_access.

    For scale: across about 330 Codex threads in Auto on one Linux server, 169 commands failed on DNS or connect (gh, git fetch, npm, PyPI, App Store Connect). Another 60 failed with EROFS when writing to worktrees outside the cwd. SSH also fails inside the sandbox with Bad owner or permissions on /etc/ssh/ssh_config.d/....

    Until this is fixed, I added an AGENTS.md rule that tells Codex to request escalation on the first try for network commands. The auto reviewer approves those, so it works around the problem but costs an approval round per command.

  4. nsoliven commented on Oct 16, 2026

    @nsoliven

    Bump. Still the same issue.

  5. poroburu commented on Oct 20, 2026

    @poroburu

    Reproduced with T3 0.1.0, Codex 0.163.0, and a fresh delegated child in Auto mode.

    We confirmed Codex loaded the intended config. A named profile extending :workspace, with network enabled and features.network_proxy = true, activated the managed proxy:

    CODEX_NETWORK_PROXY_ACTIVE=1
    CODEX_NETWORK_ALLOW_LOCAL_BINDING=1
    

    However, after T3's bare workspaceWrite turn override, the effective policy omitted an additional profile workspace root. That made our shared test limiter unwritable. A configured filesystem deny entry remained in the effective policy, but runtime read denial was not tested.

    We stopped verification and reverted the config. We are not claiming successful network, VSTest, or SSH execution.

    PR #18344's explicit named-profile exclusion therefore leaves this use case unresolved. Should preserving named-profile permissions while enforcing runtime-mode changes be tracked separately under discussion #6976?

  6. porointern commented on Oct 25, 2026

    @porointern

    Follow-up to the earlier report, 2026-10-25. To unblock our own use, we built v0.1.2 + #18344 (merged as-is, original commits) plus a small local follow-up, and qualified it on Linux with Codex 0.164.0: isolated T3 home and CODEX_HOME, Auto mode, real sandboxed commands. Sharing what we found in case it helps scope a follow-up to #18344. We're not asking for a merge.

    Named profiles. Sending turn/start.permissions = "<profile>" (with no sandboxPolicy) instead of the bare workspaceWrite fixes the profile case, as long as you respect managed allowedPermissionProfiles and the documented sandbox_mode precedence over default_permissions. permissions is an experimental field that the generated stable turn/start encoder drops, so we send it over the raw transport. T3 already enables experimentalApi. Results with a profile extending :workspace (an extra writable root, a denied directory, a domain allowlist, network_proxy):

    bare policy (v0.1.2) profile sent
    extra profile writable root read-only writable
    denied directory denied denied
    allowlisted HTTPS / gh api ok (via proxy) ok
    non-allowlisted host n/a blocked by proxy
    loopback listen+connect not tested ok
    Full access → Auto (live) n/a profile restored on the Auto turn

    A second issue in the same area: commits from T3 worktrees. Even with the correct profile, a sandboxed Codex agent can't git commit in a T3 thread worktree. Codex protects the resolved gitdir: of a writable root's .git file (.git/worktrees/<id>) as read-only unless an explicit rule names that exact path (default_read_only_subpaths_for_writable_root in codex-rs/protocol/src/permissions.rs, rust-v0.164.0). The id changes per worktree, so user config can't express it.

    We worked around it with a per-thread config override at thread/start and resume: permissions.<profile>.filesystem grants write access to that one gitdir and to each module gitdir under it. config, config.worktree, hooks and info stay read-only, because git runs those outside the sandbox. This loosens a deliberate Codex protection, so it's opt-in on our side and probably wants a design discussion rather than a PR.

    Happy to share the patch and the replay tests if that's useful.

  7. porointern commented on Oct 26, 2026

    @porointern

    Update, 2026-10-26: the named-profile route described in our previous comment now supports our ordinary Codex engineering workflow, including the public-resource access that originally blocked us.

    This is our patched v0.1.2 build with Codex 0.164.0, not a claim that stock T3 or current upstream main is fixed. We retained #18344's original commits and the existing local adapter follow-up; those local repairs were implemented with Claude Opus. Codex development and an Astra consult helped reconcile the later tests and narrow the landing. This round required no additional T3 production code: we used the corrected adapter and an ordinary owner-managed named permission profile with managed-proxy TCP networking enabled.

    The generic adapter requirement remains configuration fidelity: preserve the selected named profile on sandboxed turns (turn/start.permissions, without a simultaneous bare sandboxPolicy that replaces it), while respecting runtime-mode changes and managed restrictions. Deployment-specific domain/address policy should stay in Codex configuration. An opt-in per-thread overlay catalog, approval database or fresh-thread admission chain was unnecessary for this connectivity fix. This result does not establish correct selector precedence across every layered configuration combination.

    Actual ordinary Codex command checks demonstrated:

    • Public documentation and a roughly 31 MB textbook download; Node release metadata and GitHub Actions log downloads also worked.
    • HTTP write methods and public TCP through CONNECT/SOCKS.
    • IPv4/IPv6 parent-child loopback compatibility and four VSTest cases under the adopted configuration.
    • Two bounded managed-proxy private-literal refusal observations, with separate native blocked-private-address events and independently supervised pre/post liveness plus zero challenge deliveries. Generic SOCKS refusal/connection EOF alone was not treated as policy attribution.

    We retained filesystem, privilege and reviewer restrictions and did not switch to Full access to obtain networking. The accepted goal is functional public-resource usability comparable to our Claude workflow; it is not a claim that the two providers have identical security boundaries. Live DNS-rebinding/final-routing, exhaustive private-network topology, global UDP and cross-provider/host guarantees remain unverified. A later successful PDF text extraction was separate local tooling, not evidence of a T3 networking feature or completion of a textbook-grounded audit.

    Our configuration change has completed its normal review/CI/merge process and we are keeping the tested configuration. The original bare-policy bug and named-profile inheritance remain distinct upstream concerns; this comment reports a working local route and its limits, not an upstream merge or a universal security certification.

  8. TommyBez commented on Nov 2, 2026

    @TommyBez

    Also reproducible on v0.1.6 (macOS arm64, Codex adapter V2, runtime mode auto), with git writes inside T3 thread worktrees:

    • git merge in a thread worktree:
      fatal: update_ref failed for ref 'ORIG_HEAD': cannot lock ref 'ORIG_HEAD': Unable to create '<repo>/.git/worktrees/<name>/ORIG_HEAD.lock': Operation not permitted
    • git show --remerge-diff in a read-only review thread:
      error: unable to create temporary object directory

    The worktree's .git is a gitdir: pointer and git rev-parse --git-common-dir resolves to <repo>/.git, outside the turn's cwd. codexRuntimeModeTurnDefaults("auto") still sends a bare { type: "workspaceWrite" } on every turn/start (same on main at 8657eec), so no writableRoots survive.

    Note for whoever picks this up: Codex also keeps each writable root's .git (and a resolved worktree gitdir) read-only by design, so preserving the config (#18344) may not be enough for git metadata writes on its own. See #26865 for the same mechanism with delegate_task children and why a plain writableRoots fix was withdrawn.

    Workaround on our side for now: git writes (merge/commit) go through Claude threads; Codex threads stay read-only for git.

  9. junkovich commented on Nov 4, 2026

    @junkovich

    I can reproduce this on Linux with T3 server 0.1.7-nightly.20261103.4138 and Codex CLI 0.166.0, using Auto.

    My config has network_access = true under [sandbox_workspace_write], but commands expose CODEX_SANDBOX_NETWORK_DISABLED=1. Running gh api rate_limit fails with "error connecting to api.github.com". The same command succeeds when run with approval outside the sandbox. Neither GitHub API quota is exhausted.

    This also affects scheduled read-only audits: a run can finish with its GitHub lookups unsuccessful unless it requests an approved retry.

    I haven't tested #18344. Thanks for working on this.

  10. prrtzt-agents commented on Nov 5, 2026

    @prrtzt-agents

    Still present in the latest stable, v0.1.7, on macOS with Codex 0.163.0.

    • RuntimePolicyV2.layerFromProjectStore builds the runtime policy from runtimeMode, interactionMode and cwd only, so no setting, provider instance config or t3 thread start option can supply a sandboxPolicy.
    • codexRuntimeModeTurnDefaults("auto") then sends { type: "workspaceWrite" }, and networkAccess defaults to false. [sandbox_workspace_write] network_access = true in ~/.codex/config.toml has no effect, and Codex launchArgs (-c ...) don't help either, because the turn override replaces the config-resolved policy.

    The effect: Codex review threads in Auto can't resolve proxy.golang.org or registry.npmjs.org, so they can't run go test or pnpm install. The same reviewer through plain codex exec -c sandbox_mode="workspace-write" downloads modules and runs the tests. We're waiting for #18344 rather than switching review threads to Full access.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions