fix(security): validateOutputPath bypassed via existing symlinks in safe directories#921
Open
Hybirdss wants to merge 1 commit intogarrytan:mainfrom
Open
Conversation
…links
A symlink at /tmp/evil.png → /etc/crontab passes validateOutputPath because
the function only resolves the parent directory (/tmp is safe), never checking
if the target file itself is a symlink pointing outside safe directories.
Every output command is affected: screenshot, pdf, download, scrape, archive.
Fix: before the parent-dir check, lstatSync the resolved path. If it exists
and is a symlink, realpathSync the target and verify it's within SAFE_DIRECTORIES.
ENOENT (file doesn't exist yet) falls through to the existing parent-dir check.
Fixes the pre-existing test failure in path-validation.test.ts
("blocks symlink inside /tmp pointing outside safe dirs").
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
validateOutputPath()only resolves the parent directory — if the target file already exists as a symlink pointing outside safe directories, the write follows the symlink.Every output command is affected:
screenshot,pdf,download,scrape,archive.Reproduction
Root cause
File:
browse/src/path-security.ts:33-56validateOutputPathresolves the parent directory viarealpathSync(dir)but never checks the file itself. This is correct for new files (they don't exist yet), but misses the case where the target already exists as a symlink.Compare with
validateReadPath(line 59-80) which doesrealpathSync(resolved)on the file itself — that function is not vulnerable.Fix
Before the parent-directory check,
lstatSyncthe resolved path. If it exists and is a symlink,realpathSyncthe target and verify it's withinSAFE_DIRECTORIES.ENOENT(file doesn't exist yet) falls through to the existing parent-dir check.1 file, 20 lines added. All 6 output commands protected through the single shared function.
Related
Test plan
"blocks symlink inside /tmp pointing outside safe dirs"now passes (was failing since the test was written)bun test browse/test/path-validation.test.ts— 29 pass, 0 fail (was 29 pass, 1 fail)bun test— full suite passes, 0 failuresln -s /etc/crontab /tmp/test.png+validateOutputPath('/tmp/test.png')→ throws/tmpwrites still pass (no regression)Generated with Claude Code