wavetermdev/waveterm · warning

potential path traversal detected for path %s

Error message

potential path traversal detected for path %s

What it means

ExpandHomeDir expands a leading ~ to the user's home directory, then verifies the result (after Clean/Abs) still resides under homeDir. If filepath.Abs fails or the absolute path escapes the home prefix, it rejects the input as a path traversal attempt (e.g. ~/../etc).

Source

Thrown at tsunami/util/util.go:56

	homeVar, err := os.UserHomeDir()
	if err != nil {
		return "/"
	}
	return homeVar
}

func ExpandHomeDir(pathStr string) (string, error) {
	if pathStr != "~" && !strings.HasPrefix(pathStr, "~/") && (!strings.HasPrefix(pathStr, `~\`) || runtime.GOOS != "windows") {
		return filepath.Clean(pathStr), nil
	}
	homeDir := GetHomeDir()
	if pathStr == "~" {
		return homeDir, nil
	}
	expandedPath := filepath.Clean(filepath.Join(homeDir, pathStr[2:]))
	absPath, err := filepath.Abs(filepath.Join(homeDir, expandedPath))
	if err != nil || !strings.HasPrefix(absPath, homeDir) {
		return "", fmt.Errorf("potential path traversal detected for path %s", pathStr)
	}
	return expandedPath, nil
}

func ExpandHomeDirSafe(pathStr string) string {
	path, _ := ExpandHomeDir(pathStr)
	return path
}

func ChunkSlice[T any](slice []T, chunkSize int) [][]T {
	if len(slice) == 0 {
		return nil
	}
	chunks := make([][]T, 0)
	for i := 0; i < len(slice); i += chunkSize {
		end := i + chunkSize
		if end > len(slice) {
			end = len(slice)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Remove the .. traversal from the path; reference files genuinely under the home directory.
  2. Use ExpandHomeDirSafe if you want the empty-string-on-failure behavior rather than an error, but validate the result.
  3. If HOME is unset in your environment, set it so os.UserHomeDir returns a real home directory instead of the "/" fallback.

Example fix

// before
p, err := util.ExpandHomeDir("~/../etc/config") // traversal error
// after
p, err := util.ExpandHomeDir("~/.config/myapp/config")
Defensive patterns

Strategy: validation

Validate before calling

func isSafeHomePath(p string) bool {
    if !strings.HasPrefix(p, "~/") && p != "~" { return true }
    rest := strings.TrimPrefix(strings.TrimPrefix(p, "~"), "/")
    return rest == "" || !strings.HasPrefix(rest, "..") && !strings.Contains("/"+rest, "/../")
}

Try / catch

expanded, err := util.ExpandHomeDir(userPath)
if err != nil {
    return fmt.Errorf("refusing unsafe path %q: %w", userPath, err)
}

Prevention

When it happens

Trigger: Calling ExpandHomeDir with a path like "~/../../etc/passwd" or "~/../secrets" where Clean+Join escapes the home directory; also when homeDir itself is odd (GetHomeDir returns "/" on UserHomeDir error) making prefix checks behave unexpectedly.

Common situations: User-supplied config values containing ~/..; sanitizing untrusted path input in tools; environments with no HOME set so homeDir falls back to "/" and any relative-looking expansion trips the prefix check.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/1426c5b09949abe0. Report an issue: GitHub.