abhigyanpatwari/GitNexus · error · BadRequestError
Path must not contain null bytes
Error message
Path must not contain null bytes
What it means
NUL bytes are rejected before path resolution because C-based syscalls truncate at NUL — the classic 'safe.txt\0../../etc/passwd' injection trick — and Node itself fails with an opaque ERR_INVALID_ARG_VALUE on such paths. assertSafePath converts that into a clean, named 400 so file-serving endpoints never hand a NUL-bearing path to fs.
Source
Thrown at gitnexus/src/server/validation.ts:82
return value;
}
/**
* Resolve a user-supplied relative path against an allowed root and verify it
* stays inside that root. Mirrors the existing guard at api.ts:1067-1077.
*
* Returns the absolute resolved path. Rejects empty paths, null bytes, and
* paths that resolve outside the root (e.g., `../../../etc/passwd`).
*
* @throws BadRequestError when the path is empty or contains a null byte
* @throws ForbiddenError when the resolved path escapes the root
*/
export function assertSafePath(rawPath: string, root: string): string {
if (rawPath.length === 0) {
throw new BadRequestError('Path must not be empty');
}
if (rawPath.includes('\0')) {
throw new BadRequestError('Path must not contain null bytes');
}
const resolvedRoot = path.resolve(root);
const fullPath = path.resolve(resolvedRoot, rawPath);
const safePrefix = resolvedRoot.endsWith(path.sep) ? resolvedRoot : resolvedRoot + path.sep;
if (fullPath !== resolvedRoot && !fullPath.startsWith(safePrefix)) {
throw new ForbiddenError('Path traversal denied');
}
return fullPath;
}
/**
* Escape regex metacharacters in a user-supplied string so it can be safely
* embedded as a literal in `new RegExp(...)`. Used by /api/grep's literal mode
* and any future endpoint that constructs a regex from caller input.
*/
export function escapeRegExp(input: string): string {
return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}View on GitHub (pinned to aac7515d2a)
Solutions
- Reject or strip control characters (< 0x20) in path fields client-side before sending
- Treat occurrences as hostile input (log/WAF), not as something to retry unchanged
- Keep assertSafePath as the server-side last line of defense — never decode user input and pass it raw to fs
Example fix
// before
sendPath(userPath); // userPath = 'docs\u0000/../../etc/passwd'
// after
const CTRL = /[\u0000-\u001f]/;
if (CTRL.test(userPath)) throw new Error('control characters in path');
sendPath(userPath); Defensive patterns
Strategy: validation
Validate before calling
const CTRL = /[\u0000-\u001f]/;
if (CTRL.test(userPath)) {
throw new Error('control characters in path — rejecting');
} Type guard
function isCleanPath(p: string): boolean {
return p.length > 0 && !/[\u0000-\u001f]/.test(p);
} Prevention
- Reject control characters (< 0x20) in every path field at the client boundary
- Treat NUL-bearing input as hostile (log it), never as a retry candidate
- Never decode user input and pass it directly to fs APIs — keep assertSafePath as the last line of defense
When it happens
Trigger: URL-encoded nulls in a path parameter: ?path=docs%00/../../etc/passwd; binary junk or control characters pasted into the field; fuzzer-generated payloads.
Common situations: Deliberate path-traversal probes against file endpoints; scripts concatenating Buffers into strings; input from sources that don't strip control characters.
Related errors
- ${source} entry "${trimmed}" must be an identifier or member
- argument contains NUL/CR/LF, unsafe for the Windows shell: $
- argument contains a double quote, unsafe for the Windows she
- Path traversal blocked: ${filePath}
- Invalid upload path
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/d6adf862f857a629.
Report an issue: GitHub.