Skip to content

[Bug]: Linux AppImage env (ARGV0, ELECTRON_RUN_AS_NODE) still leaks into provider agent sessions #16456

Open

Description

@dubonzi

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 Linux, launch the T3 Code AppImage. The user's login shell is zsh.
  2. Start a Codex thread and ask the agent to run:
    env | grep -E '^(ARGV0|APPIMAGE|APPDIR|OWD|ELECTRON_RUN_AS_NODE)='
    python3 -c 'import sys; print(sys.executable)'
  3. Optional, to see the failure it causes. Ask the agent to run:
    d=$(mktemp -d)
    python3 -c "import sys; open('$d/s','w').write('#!'+sys.executable+'\nimport json,os\nprint(1)\n')"
    chmod +x "$d/s" && "$d/s"

The leak also shows on the host, outside any agent: tr '\0' '\n' < /proc/<pid>/environ for the T3 server process (t3code --require …/app.asar…) and for each provider process it spawns (claude …).

Expected behavior

Provider sessions get the host environment, the same way the integrated terminal does since #3108. ARGV0, APPIMAGE, APPDIR, OWD and ELECTRON_RUN_AS_NODE are not set, and PATH/LD_LIBRARY_PATH have no /tmp/[.mount_T3-*](https://github.com/tmp/.mount_T3-*) entries. sys.executable is /usr/bin/[python3](https://github.com/usr/bin/python3).

Actual behavior

#3108 strips the AppImage runtime env in apps/server/src/terminal/[Manager.ts](https://github.com/home/eduardo/.t3/scratch/2026-10-06-retro-lets-run-it-on-9c849431/apps/server/src/terminal/Manager.ts), but only for terminal sessions. Provider sessions still inherit the server's environment unchanged:

  • ARGV0, APPIMAGE, APPDIR and OWD are set, PATH has /tmp/[.mount_T3-*](https://github.com/tmp/.mount_T3-*) and /tmp/.mount_T3-*/usr/[sbin](https://github.com/tmp/.mount_T3-*/usr/sbin), and the server has LD_LIBRARY_PATH=/tmp/.mount_T3-*/usr/lib.
  • ELECTRON_RUN_AS_NODE=1 is set as well.

Codex runs commands through the user's login shell. zsh uses an exported ARGV0 as argv[0] for every external command it starts, the same way as in #2509. So every program the agent runs gets the AppImage path as argv[0]. Python derives sys.executable from argv[0], so sys.executable is the AppImage. Because ELECTRON_RUN_AS_NODE=1 is set too, anything that execs sys.executable runs Node, not Python. The step 3 script fails with a JavaScript SyntaxError.

We hit this in a project's test suite: a test fixture wrote a #!{sys.executable} shim, and under a Codex agent in T3 the test failed with the error below. The same suite passes in a normal terminal. Every delegated Codex agent hit it again until we added a workaround.

Shell check of the mechanism, outside T3:

env ARGV0=/path/to/T3.AppImage zsh -c "python3 -c 'import sys; print(sys.executable)'"   # /path/to/T3.AppImage
env ARGV0=/path/to/T3.AppImage bash -c "python3 -c 'import sys; print(sys.executable)'"  # /usr/bin/python3

Suggested fix: apply the #3108 environment sanitizer to provider and agent process spawns too, and remove ELECTRON_RUN_AS_NODE there.

Impact

Minor bug or occasional failure

Version or commit

0.0.46-nightly.20261004.2652 (first seen). Still present in 0.0.46-nightly.20261005.2702.

Environment

Fedora 44, kernel 7.2.8, T3 Code Linux AppImage, zsh 5.9, Python 3.14.7. Codex CLI 0.160.0. The Claude provider process has the same variables.

Logs or stack traces

# inside the Codex agent shell
$ python3 -c 'import sys; print(sys.executable)'
/home/<user>/Downloads/T3-Code-0.0.46-nightly.20261004.2652-x86_64.AppImage

$ env | grep -E '^(ELECTRON|PATH)'
ELECTRON_RUN_AS_NODE=1
PATH=…:/tmp/.mount_T3-CodffXPwV:/tmp/.mount_T3-CodffXPwV/usr/sbin:/usr/local/bin:/usr/bin:/bin

# test fixture that execs a '#!{sys.executable}' script
file:///tmp/fedora%20review%20fixes%209w3635e1/bin/python3:2
import json,os,pathlib,sys
           ^
SyntaxError: Unexpected token ','
    at compileSourceTextModule (node:internal/modules/esm/utils:320:16)
    at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:89:18)

Screenshots, recordings, or supporting files

No response

Workaround

Run commands with env -u ELECTRON_RUN_AS_NODE, or resolve the interpreter with shutil.which('python3') instead of sys.executable. Neither fixes argv[0] for other programs.

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Oct 6, 2026
  2. juliusmarminge commented on Oct 6, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks @dubonzi for tracking this down so precisely, the zsh ARGV0 detail made it easy to follow. Reading current main, this looks like the provider-session half of the AppImage leak that #1699, #2509, and #5059 addressed for integrated terminals only.

    What I found

    • fix(terminal): strip AppImage runtime env from spawned terminals #3108 (stripAppImageRuntimeEnv in apps/server/src/terminal/Manager.ts) is scoped to createTerminalSpawnEnv, so agent CLIs stay on the server's environment.
    • The desktop backend starts the server with extendEnv: true and ELECTRON_RUN_AS_NODE=1 (apps/desktop/src/backend/DesktopBackendConfiguration.ts). That part is needed, since the packaged server runs as Electron-as-Node, so the server process itself showing APPIMAGE, APPDIR, ARGV0, OWD, and ELECTRON_RUN_AS_NODE is expected.
    • Provider sessions copy that environment through unchanged. HostProcessEnvironment is process.env, mergeProviderInstanceEnvironment spreads it, and both providers hand the result to the child:
      • Codex (CodexAdapterV2.layerAppServerClientFactory) spawns codex with that object as env.
      • Claude (createClaudeAdapterV2 → makeClaudeEnvironment) only overlays CLAUDE_CONFIG_DIR and passes the rest to the Agent SDK.
    • Nothing on those paths removes ARGV0 / APPIMAGE / APPDIR / OWD, drops /tmp/.mount_T3-* segments from PATH, LD_LIBRARY_PATH, XDG_DATA_DIRS, or GSETTINGS_SCHEMA_DIR, or removes ELECTRON_RUN_AS_NODE. The terminal path does both (stripAppImageRuntimeEnv, plus ELECTRON_RUN_AS_NODE on TERMINAL_ENV_BLOCKLIST).
    • That matches the zsh failure: Codex runs commands through the login shell, zsh uses an exported ARGV0 as argv[0] for external commands (same mechanism as [Bug]: Ubuntu 26.04 - AppImage ARGV0 leak corrupts zsh integrated terminal - causes coreutils crashes #2509), Python sets sys.executable from it, and with ELECTRON_RUN_AS_NODE=1 still set the re-exec'd AppImage runs as Node. Bash doesn't do the ARGV0 rewrite.

    Likely fix area

    One option is to reuse the terminal scrub on the environment that provider agents and their shells inherit, rather than on the server process itself. A few places set ELECTRON_RUN_AS_NODE deliberately, which may matter for how broadly it's removed:

    • Antigravity strips an inherited ELECTRON_RUN_AS_NODE and sets it back to "1" so its browser helper can run the packaged binary as Node (antigravityEnvironment in apps/server/src/provider/antigravityAuthSupport.ts). It still copies ARGV0 / APPIMAGE from the base env.
    • The ACP stdio bridge sets ELECTRON_RUN_AS_NODE=1 only on the t3 acp-mcp-bridge server entry (AcpAdapterV2).
    • The Linux cgroup wrapper sets it on the wrapper shell and unsets it before exec of the agent (wrapCommandForLinuxCgroup), but that doesn't remove the other AppImage variables, and Codex and Claude don't go through that wrapper.

    A maintainer will decide on the fix direction.

  3. added
    via-triageFiled through npx t3 triage
    and removed
    needs-triageIssue needs maintainer review and initial categorization.
    on Oct 6, 2026
  4. Jord-JD commented on Oct 16, 2026

    @Jord-JD
    Contributor

    One more path leaks ELECTRON_RUN_AS_NODE=1, and it isn't covered by the terminal fix on main or by #16679: the server's external launcher, which opens browsers, editors and the file manager.

    launchAndUnref in apps/server/src/process/externalLauncher.ts spawns xdg-open (or an editor) with the server's full environment. A file manager opened that way passes ELECTRON_RUN_AS_NODE=1 to everything started from it. For example, Open in file manager → Dolphin → open a Konsole there.

    Repro on Linux (desktop app):

    1. Open a project folder in the file manager from T3 Code.
    2. In that file manager, open a terminal and run env | grep ELECTRON_RUN_AS_NODE. It prints ELECTRON_RUN_AS_NODE=1.
    3. Launch any Electron app or Electron AppImage from that terminal. It starts as plain Node and exits, for example:
      $ ./my-electron-app.AppImage
      /tmp/.mount_XXXX/my-electron-app: bad option: --no-sandbox
      

    Workaround: env -u ELECTRON_RUN_AS_NODE ./my-electron-app.AppImage.

    The desktop main process doesn't have the variable. The backend process does, because it is launched with it on purpose, and every child it spawns inherits it. That includes agent sessions (covered by #16679) and launched apps. VS Code handles this by deleting ELECTRON_RUN_AS_NODE from the environment of what it launches (sanitizeProcessEnvironment in src/vs/base/common/processes.ts and src/vs/code/node/cli.ts).

    I'll open a small PR that only covers the external launcher, so it doesn't overlap with #16679.

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