# Setup environment
env = os.environ.copy()
if env_vars:
env.update(env_vars)
backend/app/code/run/job_runner.py:391
That environment is exactly where the provider secrets live: set_runtime_key writes them into the process env (backend/app/core/settings.py:209), and _load_runtime re-injects all persisted keys on boot (backend/app/core/settings.py:283).
Trigger: create a job with command: "env" and start it.
Observed: stdout.log contains OPENAI_API_KEY, ANTHROPIC_API_KEY, MOONSHOT_API_KEY, DATABASE_URL, … and that log is then registered as a downloadable artifact (backend/app/modules/code/code_jobs_api.py:185) and served by GET /{job_id}/logs/download (backend/app/modules/code/code_jobs_api.py:491). The secrets are now readable by anyone who can list jobs.
Expected: build the child environment from an explicit allowlist (PATH, HOME, LANG, PYTHONPATH) plus caller-supplied env_vars, never os.environ.copy().
This is a straightforward fix and it meaningfully reduces the blast radius of issue-09 even before sandboxing lands.
backend/app/code/run/job_runner.py:391That environment is exactly where the provider secrets live:
set_runtime_keywrites them into the process env (backend/app/core/settings.py:209), and_load_runtimere-injects all persisted keys on boot (backend/app/core/settings.py:283).Trigger: create a job with
command: "env"and start it.Observed:
stdout.logcontainsOPENAI_API_KEY,ANTHROPIC_API_KEY,MOONSHOT_API_KEY,DATABASE_URL, … and that log is then registered as a downloadable artifact (backend/app/modules/code/code_jobs_api.py:185) and served byGET /{job_id}/logs/download(backend/app/modules/code/code_jobs_api.py:491). The secrets are now readable by anyone who can list jobs.Expected: build the child environment from an explicit allowlist (
PATH,HOME,LANG,PYTHONPATH) plus caller-suppliedenv_vars, neveros.environ.copy().This is a straightforward fix and it meaningfully reduces the blast radius of issue-09 even before sandboxing lands.