mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-05 05:05:08 +02:00
test: add unit tests for path validation helpers
validateOutputPath() and validateReadPath() are security-critical functions with zero test coverage. Adds 14 tests covering safe paths, traversal attacks, and prefix collision edge cases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,7 +38,7 @@ function wrapForEvaluate(code: string): string {
|
||||
// Security: Path validation to prevent path traversal attacks
|
||||
const SAFE_DIRECTORIES = ['/tmp', process.cwd()];
|
||||
|
||||
function validateReadPath(filePath: string): void {
|
||||
export function validateReadPath(filePath: string): void {
|
||||
if (path.isAbsolute(filePath)) {
|
||||
const resolved = path.resolve(filePath);
|
||||
const isSafe = SAFE_DIRECTORIES.some(dir => resolved === dir || resolved.startsWith(dir + '/'));
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import { describe, it, expect } from 'bun:test';
|
||||
import { validateOutputPath } from '../src/meta-commands';
|
||||
import { validateReadPath } from '../src/read-commands';
|
||||
|
||||
describe('validateOutputPath', () => {
|
||||
it('allows paths within /tmp', () => {
|
||||
expect(() => validateOutputPath('/tmp/screenshot.png')).not.toThrow();
|
||||
});
|
||||
|
||||
it('allows paths in subdirectories of /tmp', () => {
|
||||
expect(() => validateOutputPath('/tmp/browse/output.png')).not.toThrow();
|
||||
});
|
||||
|
||||
it('allows paths within cwd', () => {
|
||||
expect(() => validateOutputPath(`${process.cwd()}/output.png`)).not.toThrow();
|
||||
});
|
||||
|
||||
it('blocks paths outside safe directories', () => {
|
||||
expect(() => validateOutputPath('/etc/cron.d/backdoor.png')).toThrow(/Path must be within/);
|
||||
});
|
||||
|
||||
it('blocks /tmpevil prefix collision', () => {
|
||||
expect(() => validateOutputPath('/tmpevil/file.png')).toThrow(/Path must be within/);
|
||||
});
|
||||
|
||||
it('blocks home directory paths', () => {
|
||||
expect(() => validateOutputPath('/Users/someone/file.png')).toThrow(/Path must be within/);
|
||||
});
|
||||
|
||||
it('blocks path traversal via ..', () => {
|
||||
expect(() => validateOutputPath('/tmp/../etc/passwd')).toThrow(/Path must be within/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateReadPath', () => {
|
||||
it('allows absolute paths within /tmp', () => {
|
||||
expect(() => validateReadPath('/tmp/script.js')).not.toThrow();
|
||||
});
|
||||
|
||||
it('allows absolute paths within cwd', () => {
|
||||
expect(() => validateReadPath(`${process.cwd()}/test.js`)).not.toThrow();
|
||||
});
|
||||
|
||||
it('allows relative paths without traversal', () => {
|
||||
expect(() => validateReadPath('src/index.js')).not.toThrow();
|
||||
});
|
||||
|
||||
it('blocks absolute paths outside safe directories', () => {
|
||||
expect(() => validateReadPath('/etc/passwd')).toThrow(/Absolute path must be within/);
|
||||
});
|
||||
|
||||
it('blocks /tmpevil prefix collision', () => {
|
||||
expect(() => validateReadPath('/tmpevil/file.js')).toThrow(/Absolute path must be within/);
|
||||
});
|
||||
|
||||
it('blocks path traversal sequences', () => {
|
||||
expect(() => validateReadPath('../../../etc/passwd')).toThrow(/Path traversal/);
|
||||
});
|
||||
|
||||
it('blocks nested path traversal', () => {
|
||||
expect(() => validateReadPath('src/../../etc/passwd')).toThrow(/Path traversal/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user