Skip to content

Security: Mode tracker flag file write also vulnerable to symlink-based overwrite#71

Merged
JuliusBrussee merged 1 commit intoJuliusBrussee:mainfrom
tuanaiseo:contribai/fix/security/mode-tracker-flag-file-write-also-vulner
Apr 15, 2026
Merged

Security: Mode tracker flag file write also vulnerable to symlink-based overwrite#71
JuliusBrussee merged 1 commit intoJuliusBrussee:mainfrom
tuanaiseo:contribai/fix/security/mode-tracker-flag-file-write-also-vulner

Conversation

@tuanaiseo
Copy link
Copy Markdown
Contributor

Problem

The UserPromptSubmit hook similarly writes to ~/.claude/.caveman-active without checking whether the path is a symlink. This duplicates the same local file-clobber risk in another execution path.

Severity: medium
File: hooks/caveman-mode-tracker.js

Solution

Apply the same hardening as in the activation hook: validate path components with lstat, refuse symlinks, and write with restrictive permissions and atomic replace semantics.

Changes

  • hooks/caveman-mode-tracker.js (modified)

Testing

  • Existing tests pass
  • Manual review completed
  • No new warnings/errors introduced

The UserPromptSubmit hook similarly writes to `~/.claude/.caveman-active` without checking whether the path is a symlink. This duplicates the same local file-clobber risk in another execution path.

Affected files: caveman-mode-tracker.js

Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com>
@JuliusBrussee JuliusBrussee merged commit 205e537 into JuliusBrussee:main Apr 15, 2026
JuliusBrussee added a commit that referenced this pull request Apr 15, 2026
…ession

Writes were hardened via safeWriteFlag (PRs #70/#71) but readers still
trusted whatever the flag contained. A local attacker with write access
to ~/.claude/ could symlink the flag at a secret file and have the
per-turn reinforcement inject its bytes into model context, or the
statuslines echo ANSI escapes to the terminal on every keystroke.

- caveman-config.js: new readFlag() — lstat symlink refuse, 64-byte cap,
  O_NOFOLLOW, VALID_MODES whitelist. Returns null on any anomaly.
- caveman-mode-tracker.js: per-turn reinforcement routes through
  readFlag() instead of fs.readFileSync.
- caveman-statusline.sh / .ps1: symlink + size refuse, strip to
  [a-z0-9-], whitelist-validate before rendering.
- compress.py (3 synced copies): is_sensitive_path() denylist refuses
  .env*, .netrc, keys/certs, ~/.ssh|.aws|.gnupg|.kube|.docker, and any
  basename containing secret/credential/password/apikey/token/privatekey
  (separator-insensitive). Fails loudly before read — no silent exfil
  of credentials to the Anthropic API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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