Skip to content

Do not follow a .py symlink out of the scan root - #11

Merged
bitWarrior merged 1 commit into
mainfrom
fix/symlink-escape
Sep 3, 2026
Merged

Do not follow a .py symlink out of the scan root#11
bitWarrior merged 1 commit into
mainfrom
fix/symlink-escape

Conversation

@bitWarrior

Copy link
Copy Markdown
Owner

os.walk does not follow directory symlinks, but a file symlink is yielded and
read through. A tree containing src/x.py -> ~/.ssh/id_rsa therefore had that
file opened by codesnake check src/, which SECURITY.md already lists as in
scope: reading files outside the analyzed paths.

The read is not the whole of it. A parse failure becomes SYN001 and the text
report prints the offending source line, so content from the target reaches
the output. Reproduced with a benign stand-in: pointing at a config file whose
first two lines are valid Python printed the third verbatim, credential and
all. On a public repository that lands in the CI log, and the attacker chooses
the target, so they choose which line fails to parse.

The walk now skips a symlink whose resolved path leaves the root. Symlinks
that stay inside it are followed as before -- this is containment, not a ban
on symlinks -- and an explicit file argument is still read as given, since
naming a file is a deliberate act.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_0114gUUe4CxYr8W8oC95ffmD

os.walk does not follow directory symlinks, but a file symlink is yielded and
read through. A tree containing `src/x.py -> ~/.ssh/id_rsa` therefore had that
file opened by `codesnake check src/`, which SECURITY.md already lists as in
scope: reading files outside the analyzed paths.

The read is not the whole of it. A parse failure becomes SYN001 and the text
report prints the offending source line, so content from the target reaches
the output. Reproduced with a benign stand-in: pointing at a config file whose
first two lines are valid Python printed the third verbatim, credential and
all. On a public repository that lands in the CI log, and the attacker chooses
the target, so they choose which line fails to parse.

The walk now skips a symlink whose resolved path leaves the root. Symlinks
that stay inside it are followed as before -- this is containment, not a ban
on symlinks -- and an explicit file argument is still read as given, since
naming a file is a deliberate act.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0114gUUe4CxYr8W8oC95ffmD
@bitWarrior
bitWarrior merged commit 8115dd2 into main Sep 3, 2026
4 checks passed
@bitWarrior
bitWarrior deleted the fix/symlink-escape branch September 3, 2026 20:17
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.

1 participant