Skip to content

fix(security): path validation bypass in upload and cookie-import commands#920

Open
Hybirdss wants to merge 1 commit intogarrytan:mainfrom
Hybirdss:fix/path-validation-bypass-upload-cookie-import
Open

fix(security): path validation bypass in upload and cookie-import commands#920
Hybirdss wants to merge 1 commit intogarrytan:mainfrom
Hybirdss:fix/path-validation-bypass-upload-cookie-import

Conversation

@Hybirdss
Copy link
Copy Markdown

@Hybirdss Hybirdss commented Apr 8, 2026

Summary

upload and cookie-import commands use inline path validation (path.normalize().includes('..') + manual isAbsolute check) while all newer commands already use the shared validateReadPath/validateOutputPath from path-security.ts.

The inline check is weaker — path-security.ts does path.resolve()fs.realpathSync() → boundary check against SAFE_DIRECTORIES, catching symlink traversal and normalized-path bypass vectors that includes('..') misses.

Before (inline, bypassable):

// upload — 10 lines of manual validation
if (path.isAbsolute(fp)) {
  let resolvedFp: string;
  try { resolvedFp = fs.realpathSync(path.resolve(fp)); } catch { resolvedFp = path.resolve(fp); }
  if (!SAFE_DIRECTORIES.some(dir => isPathWithin(resolvedFp, dir))) { throw ... }
}
if (path.normalize(fp).includes('..')) { throw ... }

// cookie-import — 8 lines of manual validation
if (path.isAbsolute(filePath)) {
  const safeDirs = [TEMP_DIR, process.cwd()];
  const resolved = path.resolve(filePath);
  if (!safeDirs.some(dir => isPathWithin(resolved, dir))) { throw ... }
}
if (path.normalize(filePath).includes('..')) { throw ... }

After (shared module, 1 line each):

// upload
validateReadPath(fp);

// cookie-import
validateReadPath(filePath);

Same validateReadPath that eval command already uses — resolve, realpath, boundary check, symlink resolution. Single source of truth.

What's fixed

  • upload: 10-line inline validation → validateReadPath(fp)
  • cookie-import: 8-line inline validation → validateReadPath(filePath)
  • Removed unused SAFE_DIRECTORIES and isPathWithin imports from write-commands.ts

Context

path-security.ts was introduced in #907 to consolidate path validation that was "duplicated across 3 files." This PR catches the 4th instance — upload and cookie-import were not migrated at that time.

Test plan

  • Updated upload command path validation tests — verify validateReadPath usage, verify inline checks removed
  • Added cookie-import command path validation tests — verify validateReadPath usage, verify inline checks removed
  • bun test browse/test/path-validation.test.ts — 29 pass, 1 pre-existing fail (symlink test, unrelated to this change)
  • bun test — full suite passes (same 1 pre-existing failure only)

Closes #707

Generated with Claude Code

… with path-security module

upload and cookie-import commands used inline path validation (includes('..')
+ manual isAbsolute check) while newer commands (screenshot, download, scrape,
archive) already use the shared validateOutputPath/validateReadPath from
path-security.ts. The inline check is bypassable — path.normalize().includes('..')
misses several traversal vectors that validateReadPath catches via
path.resolve() + fs.realpathSync() + boundary check.

Changes:
- upload: replace 10-line inline validation with validateReadPath(fp)
- cookie-import: replace 8-line inline validation with validateReadPath(filePath)
- Import validateReadPath alongside existing validateOutputPath
- Remove now-unused SAFE_DIRECTORIES and isPathWithin references

Tests:
- upload: verify validateReadPath usage, verify inline checks removed
- cookie-import: new test — verify validateReadPath usage, verify inline checks removed
- 29 pass, 1 pre-existing fail (symlink test, unrelated)

Closes 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