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

  1. Express the location as a share name plus a share-relative path: s.ReadFile('C$', 'Windows/system32/config/sam', 0)
  2. If the target lives under a different share, change the share argument, not the path depth
  3. 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

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


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/7e40e499eecdea27. Report an issue: GitHub.