{"record":{"id":"0df031a10332a64d","repo":"google-gemini/gemini-cli","slug":"security-violation-null-byte-detected-in-path","errorCode":null,"errorMessage":"Security violation: Null byte detected in path.","messagePattern":"Security violation: Null byte detected in path\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/a2a-server/src/utils/path_utils.ts","lineNumber":29,"sourceCode":"/**\n * Validates a workspace path to prevent path traversal attacks.\n *\n * @param workspacePath The path to validate.\n * @param allowedRoot The root directory the path must be within. Defaults to CWD.\n * @returns The resolved, safe path.\n * @throws An error if the path is invalid or outside the allowed root.\n */\nexport async function validateWorkspacePath(\n  workspacePath?: string,\n  allowedRoot: string = process.cwd(),\n): Promise<string> {\n  const trimmedPath = workspacePath?.trim();\n  if (!trimmedPath) {\n    return resolveToRealPath(allowedRoot);\n  }\n\n  if (trimmedPath.includes('\\0')) {\n    throw new Error('Security violation: Null byte detected in path.');\n  }\n\n  try {\n    const canonicalAllowedRoot = resolveToRealPath(allowedRoot);\n    const resolvedWorkspacePath = path.resolve(\n      canonicalAllowedRoot,\n      trimmedPath,\n    );\n    const canonicalWorkspacePath = resolveToRealPath(resolvedWorkspacePath);\n\n    // Check if the resolved path is within the allowed root directory\n    if (\n      canonicalWorkspacePath !== canonicalAllowedRoot &&\n      !isSubpath(canonicalAllowedRoot, canonicalWorkspacePath)\n    ) {\n      throw new Error(\n        `Security violation: The path \"${trimmedPath}\" is outside the allowed root directory.`,\n      );","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/a2a-server/src/utils/path_utils.ts#L11-L47","documentation":"validateWorkspacePath() rejects any input containing a null byte (\\0). Null bytes can truncate path strings at the C-level syscall boundary in some environments, enabling POISON NULL BYTE attacks that bypass security checks and access unintended files.","triggerScenarios":"Calling validateWorkspacePath(path) where path includes '\\0' anywhere — e.g., 'safe\\0/../../etc/passwd'. This is a classic injection vector or corrupted input from untrusted sources.","commonSituations":"Untrusted user input passed as a workspace path without sanitization; copy-paste artifacts containing embedded control characters; test fixtures with raw null bytes; binary data mistakenly interpreted as a string path.","solutions":["Sanitize all user-supplied path input to strip or reject control characters before calling validateWorkspacePath.","Validate at the API boundary that paths contain only expected filename characters.","Treat the error as a security alert and log the source of the malicious input."],"exampleFix":"// before\nconst safePath = await validateWorkspacePath(userInput); // throws if userInput has \\0\n\n// after\nif (userInput.includes('\\0')) {\n  throw new TypeError('Invalid characters in path');\n}\nconst safePath = await validateWorkspacePath(userInput);","handlingStrategy":"validation","validationCode":"function isSafePath(input: string): boolean {\n  return !input.includes('\\0');\n}\n\n// Before calling validateWorkspacePath:\nif (!isSafePath(userInput)) {\n  throw new TypeError('Path contains illegal null byte characters.');\n}\nconst safe = await validateWorkspacePath(userInput);","typeGuard":"function isNullByteFree(value: string): boolean {\n  return !value.includes('\\0');\n}","tryCatchPattern":null,"preventionTips":["Sanitize all user-supplied or external path input at the API boundary to reject control characters.","Treat null-byte detection as a security incident — log the request source.","Never pass raw binary data or untrusted strings as path parameters."],"tags":["security","path-traversal","validation","null-byte"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}