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

  1. Reject or strip control characters (< 0x20) in path fields client-side before sending
  2. Treat occurrences as hostile input (log/WAF), not as something to retry unchanged
  3. 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

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


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/d6adf862f857a629. Report an issue: GitHub.