{"record":{"id":"981358013decc25b","repo":"abhigyanpatwari/GitNexus","slug":"label-must-not-contain-a-nul-character","errorCode":null,"errorMessage":"${label} must not contain a NUL character.","messagePattern":"(.+?) must not contain a NUL character\\.","errorType":"validation","errorClass":"InvalidStoragePathError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/storage/storage-resolver.ts","lineNumber":188,"sourceCode":"  return code ? `${code}: ${(error as Error)?.message ?? String(error)}` : String(error);\n};\n\nconst resolveRepoPath = (value: string): string => {\n  if (typeof value !== 'string' || value.length === 0) {\n    throw new InvalidStoragePathError('Repository path must be non-empty.');\n  }\n  if (value.includes('\\0')) {\n    throw new InvalidStoragePathError('Repository path must not contain a NUL character.');\n  }\n  return path.resolve(value);\n};\n\nconst validateAbsolutePath = (value: string, label: string): string => {\n  if (typeof value !== 'string' || value.length === 0) {\n    throw new InvalidStoragePathError(`${label} must be an absolute, non-empty path.`);\n  }\n  if (value.includes('\\0')) {\n    throw new InvalidStoragePathError(`${label} must not contain a NUL character.`);\n  }\n  if (!path.isAbsolute(value)) {\n    throw new InvalidStoragePathError(`${label} must be an absolute path.`);\n  }\n  return path.resolve(value);\n};\n\n// Mirror registry lookup semantics without importing repo-manager and creating a cycle.\nconst canonicalRegistryPath = (value: string): string => {\n  const resolved = path.resolve(value);\n  try {\n    return stripWindowsLongPathPrefix(fs.realpathSync.native(resolved));\n  } catch {\n    return stripWindowsLongPathPrefix(resolved);\n  }\n};\n\nconst canonicalRepoPath = (repoPath: string): string =>","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/ac9a4e9abd8fd3058c070b72c23402a4f887929a/gitnexus/src/storage/storage-resolver.ts#L170-L206","documentation":"validateAbsolutePath rejects labeled absolute-path values that contain a NUL character, mirroring the repo-path check. NUL bytes terminate C-string paths and are a classic injection marker, so the resolver fails closed before any filesystem API runs.","triggerScenarios":"Calling resolved()/root()/readOwnershipMetadata() with a storage path containing '\\0' — from unsanitized user input, wrong-encoding buffer decodes, or corrupted config/ownership metadata files.","commonSituations":"Ownership metadata files (.gitnexus) hand-edited or truncated at a NUL; HTTP-supplied storage paths passed straight through; byte-padded Windows path conversions.","solutions":["Sanitize at the boundary: reject any value containing '\\0' with a clear caller-side error.","If from a Buffer, decode correctly (utf8) and strip trailing NULs before use.","Regenerate corrupted metadata/config files instead of patching the tainted string."],"exampleFix":"// before\nroot(userSuppliedPath);\n// after\nif (userSuppliedPath.includes('\\0')) throw new Error('storage root must not contain NUL');\nroot(userSuppliedPath);","handlingStrategy":"validation","validationCode":"if (typeof value !== 'string' || value.includes('\\0')) {\n  throw new Error(`${label} must not contain NUL characters`);\n}","typeGuard":"const isNulFreeString = (v: unknown): v is string => typeof v === 'string' && !v.includes('\\0');","tryCatchPattern":"try {\n  return readOwnershipMetadata(value);\n} catch (e) {\n  if (e instanceof InvalidStoragePathError && e.message.includes('NUL')) {\n    throw new Error(`${label} contained a NUL byte — regenerate the metadata file`);\n  }\n  throw e;\n}","preventionTips":["Never pass raw Buffer slices or wide-encoded strings as paths without re-decoding.","Validate all externally sourced paths for control characters.","Regenerate corrupted ownership metadata instead of patching strings."],"tags":["validation","nul-byte","path-injection"],"backgroundTag":"path-traversal-blocked","analyzedSha":"ac9a4e9abd8fd3058c070b72c23402a4f887929a","analyzedAt":"2026-09-15T23:29:44.066Z","contentChangedAt":"2026-09-15T23:29:44.066Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}