projectdiscovery/nuclei · warning
share path escapes share root: %q
Error message
share path escapes share root: %q
What it means
After NormalizeSharePath cleans the input, the result must stay inside the share: if it is '..' or starts with '../' the path would traverse out of the share root and is rejected. SMB paths in this library are always share-relative, so traversal has no valid use — it signals a wrong path or hostile input.
Source
Thrown at pkg/js/libs/smbsession/path.go:42
return "", user
}
// NormalizeSharePath converts an SMB share-relative path to a clean form
// (forward slashes, no leading slash, "." for share root). Rejects ".." escapes.
func NormalizeSharePath(p string) (string, error) {
p = strings.TrimSpace(p)
p = strings.ReplaceAll(p, `\`, `/`)
p = strings.Trim(p, `/`)
if p == "" || p == "." {
return ".", nil
}
if strings.ContainsRune(p, 0) {
return "", fmt.Errorf("share path contains NUL")
}
clean := path.Clean(p)
clean = strings.TrimPrefix(clean, "/")
if clean == ".." || strings.HasPrefix(clean, "../") {
return "", fmt.Errorf("share path escapes share root: %q", p)
}
if clean == "." {
return ".", nil
}
return clean, nil
}
// RequireShareName validates a share name (no path separators).
func RequireShareName(share string) error {
share = strings.TrimSpace(share)
if share == "" {
return fmt.Errorf("share name cannot be empty")
}
if strings.ContainsAny(share, `/\`) {
return fmt.Errorf("share name must not contain path separators: %q", share)
}
if strings.ContainsRune(share, 0) {
return fmt.Errorf("share name contains NUL")View on GitHub (pinned to 265b3a3dec)
Solutions
- Express the location as a share name plus a share-relative path: s.ReadFile('C$', 'Windows/system32/config/sam', 0)
- If the target lives under a different share, change the share argument, not the path depth
- Strip or reject '..' segments from untrusted input before passing it
Example fix
// before
s.ReadFile('C$', '../../../Windows/system32/config/sam', 0) // escapes share root
// after
s.ReadFile('C$', 'Windows/system32/config/sam', 0) Defensive patterns
Strategy: validation
Validate before calling
// Collapse traversal before calling
for _, seg := range strings.Split(p, "/") {
if seg == ".." { return errors.New("path escapes share root") }
} Type guard
func isShareRelative(p string) bool {
c := path.Clean(strings.ReplaceAll(strings.Trim(p, "/"), "\\", "/"))
return c != ".." && !strings.HasPrefix(c, "../")
} Try / catch
normalized, err := smbsession.NormalizeSharePath(p)
if err != nil && strings.Contains(err.Error(), "escapes share root") {
// re-anchor the path inside the share instead of retrying as-is
return nil, err
} Prevention
- Build paths from trusted constants plus sanitized relative segments
- Never pass raw traversal payloads from HTTP parameters into SMB paths
- Remember paths are share-relative; change the share argument to reach elsewhere
When it happens
Trigger: Calling s.ReadFile('C$', '../../../etc/passwd', 0); passing Windows backslash traversal '..\\..\\x' (normalized to forward slashes first); building paths by concatenating untrusted directory names.
Common situations: Templates that try Unix-style absolute paths against an SMB share; path arguments copied from URL traversal payloads; walking up from a subdirectory with a computed prefix of '..'.
Related errors
- no input provider found
- share path contains NUL
- share name cannot be empty
- share name must not contain path separators: %q
- share name contains NUL
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/7e40e499eecdea27.
Report an issue: GitHub.