Skip to content

fix(security): add symlink resolution to meta-commands validateOutputPath#838

Open
Ziadstr wants to merge 1 commit intogarrytan:mainfrom
Ziadstr:fix/path-validation-bypass
Open

fix(security): add symlink resolution to meta-commands validateOutputPath#838
Ziadstr wants to merge 1 commit intogarrytan:mainfrom
Ziadstr:fix/path-validation-bypass

Conversation

@Ziadstr
Copy link
Copy Markdown

@Ziadstr Ziadstr commented Apr 5, 2026

Summary

meta-commands.ts:validateOutputPath only performed lexical path.resolve checking, while write-commands.ts:validateOutputPath had a full symlink resolution step added in PR #640 (security audit round 2). A symlink inside /tmp pointing outside the safe zone would pass meta-commands validation but be blocked by write-commands.

This brings meta-commands.ts:validateOutputPath to parity with write-commands.ts:validateOutputPath.

The vulnerability

# Create a symlink inside /tmp pointing to /etc
ln -s /etc /tmp/escape-hatch

# meta-commands validateOutputPath passes: /tmp/escape-hatch/passwd resolves
# lexically to /tmp/escape-hatch/passwd which IS within /tmp
# But the real path is /etc/passwd which is NOT within /tmp

Commands using meta-commands.validateOutputPath (screenshot, pdf, responsive) would allow writing to paths outside the safe zone via symlinks.

Fix

Added symlink resolution (identical to the existing write-commands.ts implementation):

  1. Resolve the real path of the nearest existing ancestor directory via fs.realpathSync
  2. Re-validate the real path against safe directories
  3. Fail closed if resolution fails

Testing

Added regression test: creates a symlink inside /tmp pointing to /etc, verifies validateOutputPath blocks join(linkPath, 'passwd').

Follows the exact same test pattern as the existing validateReadPath symlink test (line 67-75 of path-validation.test.ts).

Fixes #707

…Path

meta-commands.ts validateOutputPath only performed lexical path.resolve
checking, while write-commands.ts had a full symlink resolution step
added in the security audit round 2. A symlink inside /tmp pointing to
/etc would pass the meta-commands validation but be blocked by
write-commands.

This brings meta-commands.ts validateOutputPath to parity with
write-commands.ts: resolve the real path of the nearest existing
ancestor directory and re-validate against safe directories.

Adds a regression test for symlink bypass in validateOutputPath.

Fixes garrytan#707
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.

Security: path validation bypass via relative paths in write-commands.ts

1 participant