reservedSandboxKeys is consulted only by buildSandboxEnvLines (internal/cli/run.go), so it stops a harness env.sandbox entry shadowing a runner-owned export and nothing else. Two other harness-controlled routes reach the same variables.
First, bootstrapEnv sources .env.d/*.env partway through the generated script, so any host_files entry with expand: true landing a file there overwrites every export written above that line. FULLSEND_ROLE and FULLSEND_SLUG are written above it today.
Second, host_files entries have an unvalidated dest, and .env is uploaded before them, so dest: /sandbox/workspace/.env replaces the runner's file wholesale regardless of ordering.
This is trusted harness config rather than an untrusted-input path — the harness is as trusted as the runner invoking it — so the impact is that the reserved-key guarantee is narrower than it reads, not that an attacker gets in.
Proposed change
Either source harness-controlled files before every runner-owned export, or reject a host_files dest that targets the runner's own .env.
Validation criteria
A harness that sets FULLSEND_ROLE through an .env.d file, and one that targets /sandbox/workspace/.env with host_files, both fail or are ignored rather than replacing the runner's value.
Context
Found while reviewing #7007, which moved that PR's two run facts below the .env.d line and closes the first route for those two keys only. The general gap remains.
reservedSandboxKeysis consulted only bybuildSandboxEnvLines(internal/cli/run.go), so it stops a harnessenv.sandboxentry shadowing a runner-owned export and nothing else. Two other harness-controlled routes reach the same variables.First,
bootstrapEnvsources.env.d/*.envpartway through the generated script, so anyhost_filesentry withexpand: truelanding a file there overwrites every export written above that line.FULLSEND_ROLEandFULLSEND_SLUGare written above it today.Second,
host_filesentries have an unvalidateddest, and.envis uploaded before them, sodest: /sandbox/workspace/.envreplaces the runner's file wholesale regardless of ordering.This is trusted harness config rather than an untrusted-input path — the harness is as trusted as the runner invoking it — so the impact is that the reserved-key guarantee is narrower than it reads, not that an attacker gets in.
Proposed change
Either source harness-controlled files before every runner-owned export, or reject a
host_filesdest that targets the runner's own.env.Validation criteria
A harness that sets
FULLSEND_ROLEthrough an.env.dfile, and one that targets/sandbox/workspace/.envwithhost_files, both fail or are ignored rather than replacing the runner's value.Context
Found while reviewing #7007, which moved that PR's two run facts below the
.env.dline and closes the first route for those two keys only. The general gap remains.