{"record":{"id":"aeba121a998fafb6","repo":"projectdiscovery/nuclei","slug":"share-path-contains-nul","errorCode":null,"errorMessage":"share path contains NUL","messagePattern":"share path contains NUL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/js/libs/smbsession/path.go","lineNumber":37,"sourceCode":"\t\treturn user[:i], user[i+1:]\n\t}\n\tif i := strings.LastIndexByte(user, '@'); i > 0 {\n\t\treturn user[i+1:], user[:i]\n\t}\n\treturn \"\", user\n}\n\n// NormalizeSharePath converts an SMB share-relative path to a clean form\n// (forward slashes, no leading slash, \".\" for share root). Rejects \"..\" escapes.\nfunc NormalizeSharePath(p string) (string, error) {\n\tp = strings.TrimSpace(p)\n\tp = strings.ReplaceAll(p, `\\`, `/`)\n\tp = strings.Trim(p, `/`)\n\tif p == \"\" || p == \".\" {\n\t\treturn \".\", nil\n\t}\n\tif strings.ContainsRune(p, 0) {\n\t\treturn \"\", fmt.Errorf(\"share path contains NUL\")\n\t}\n\tclean := path.Clean(p)\n\tclean = strings.TrimPrefix(clean, \"/\")\n\tif clean == \"..\" || strings.HasPrefix(clean, \"../\") {\n\t\treturn \"\", fmt.Errorf(\"share path escapes share root: %q\", p)\n\t}\n\tif clean == \".\" {\n\t\treturn \".\", nil\n\t}\n\treturn clean, nil\n}\n\n// RequireShareName validates a share name (no path separators).\nfunc RequireShareName(share string) error {\n\tshare = strings.TrimSpace(share)\n\tif share == \"\" {\n\t\treturn fmt.Errorf(\"share name cannot be empty\")\n\t}","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/smbsession/path.go#L19-L55","documentation":"NormalizeSharePath sanitizes share-relative paths for smbsession operations (ListDir, ReadFile, ListTree). A NUL byte (U+0000) cannot travel in an SMB path and would silently truncate it, so any path containing one is rejected outright before network I/O. This is a pure input-validation error on the caller's string.","triggerScenarios":"Passing a path assembled from binary response data (e.g. bytes read off a socket) that contains \\x00; template strings sourced from a mangled file listing; Deliberate injection attempts through share paths.","commonSituations":"Paths extracted from protocol responses without decoding/stripping control bytes; mis-encoded UTF-16 to UTF-8 conversions leaving NULs; fuzzed template variables.","solutions":["Strip NUL bytes from the path before calling: strings.ReplaceAll(p, \\\"\\\\x00\\\", \\\"\\\")","Validate extracted paths contain only printable characters","Skip the entry and log instead of passing raw bytes through"],"exampleFix":"// before\npath := string(rawBytes) // rawBytes ends with ...\\\\x00\\\\x00\nentries, err := s.ListDir(share, path) // share path contains NUL\n\n// after\npath := strings.TrimRight(string(rawBytes), \\\"\\\\x00\\\")\nentries, err := s.ListDir(share, path)","handlingStrategy":"validation","validationCode":"if strings.ContainsRune(p, 0) {\n    p = strings.ReplaceAll(p, \"\\\\x00\", \"\")\n    // or reject: return errors.New(\"path has NUL bytes\")\n}","typeGuard":"func hasNoNUL(s string) bool { return !strings.ContainsRune(s, 0) }","tryCatchPattern":"normalized, err := smbsession.NormalizeSharePath(p)\nif err != nil && strings.Contains(err.Error(), \"contains NUL\") {\n    p = strings.ReplaceAll(p, \"\\\\x00\", \"\")\n    normalized, err = smbsession.NormalizeSharePath(p)\n}","preventionTips":["Sanitize paths decoded from binary protocols before SMB calls","Use proper UTF-16 decoding for Windows-originated strings","Reject control characters in path inputs at template boundaries"],"tags":["validation","input","smb","path"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}