Skip to content

Fix symlink attack via predictable /tmp path in write_raw_config_to_disk - #358

Merged
technicalpickles merged 1 commit into
mainfrom
secure-raw-config-tmpfile
Jul 28, 2026
Merged

Fix symlink attack via predictable /tmp path in write_raw_config_to_disk#358
technicalpickles merged 1 commit into
mainfrom
secure-raw-config-tmpfile

Conversation

@technicalpickles

Copy link
Copy Markdown
Member

Summary

  • write_raw_config_to_disk wrote the serialized raw config to /tmp/scope/config-{run_id}.json via plain File::create, which follows symlinks
  • run_id is attacker/user-controllable via --run-id or SCOPE_RUN_ID, making the exact path predictable ahead of time; on a shared multi-user box or CI runner, an attacker could pre-plant a symlink there to have scope overwrite an arbitrary file
  • Replaced with tempfile::Builder to create a securely-generated, unpredictable file under /tmp/scope, persisted via NamedTempFile::keep() so it survives past this function (it's read by a child process spawned right after in exec_sub_command)
  • Moved tempfile from [dev-dependencies] to [dependencies] in Cargo.toml since it's now needed at runtime

DryRun Security finding surfaced during review of #356 (that PR's own diff is untouched here; this fixes a pre-existing issue in the surrounding file that the security scanner flagged while scanning the whole changed file).

Test plan

  • cargo build
  • cargo test (full suite, 195+ tests pass)
  • cargo fmt --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • Manually verified: ran scope external against the tests/test-cases/command-paths fixture with an instrumented script; confirmed $SCOPE_CONFIG_JSON points to a randomly-named file (not run_id-derived), created with 0600 permissions, containing valid config JSON readable by the child process

write_raw_config_to_disk wrote the serialized raw config to a path
derived solely from run_id, which is attacker/user-controllable via
--run-id or SCOPE_RUN_ID. Combined with plain File::create following
symlinks, this let anyone who could predict the path pre-plant a
symlink and have scope clobber an arbitrary file on write.

The file is purely transient IPC to a child process spawned right
after, so swap it for a securely-generated unique tempfile instead of
a run_id-derived name. Move tempfile from dev-dependencies to
dependencies since it's now needed at runtime.

DryRun Security finding from PR #356 review.
@dryrunsecurity

Copy link
Copy Markdown

DryRun Security

This pull request introduces a low-severity security issue where the application creates a temporary directory with default permissions, potentially allowing a local attacker to manipulate the configuration file. The finding is non-blocking and does not exceed the risk threshold.

Insecure Temp Directory in src/shared/config_load.rs (drs_94577f7e)
Vulnerability Insecure Temp Directory
Description The application creates a directory at '/tmp/scope' using fs::create_dir_all, which relies on the system umask and does not explicitly set secure permissions (e.g., 0o700). While the application uses tempfile to create the configuration file within this directory, the directory itself is created with default permissions. A local attacker could pre-create /tmp/scope with world-writable permissions, potentially allowing them to delete or replace the configuration file before the application consumes it, if the application does not verify the directory's ownership or permissions.

fs::create_dir_all("/tmp/scope")?;
let mut file = tempfile::Builder::new()
.prefix("config-")
.suffix(".json")


Comment to provide feedback on these findings.

Report false positive: @dryrunsecurity fp [FINDING ID] [FEEDBACK]
Report low-impact: @dryrunsecurity nit [FINDING ID] [FEEDBACK]

Example: @dryrunsecurity fp drs_90eda195 This code is not user-facing

All finding details can be found in the DryRun Security Dashboard.

@technicalpickles
technicalpickles merged commit abcafe3 into main Jul 28, 2026
12 checks passed
@technicalpickles
technicalpickles deleted the secure-raw-config-tmpfile branch July 28, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants