Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions internal/util/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,23 @@ func SanitizePath(p string) (string, error) {
// where a path could be validated before the directory exists and then exploited
// after creation by a malicious symlink or directory structure.
func SafeJoinPath(basePath, relativePath string) (string, error) {
// Verify base path is an existing directory
info, err := os.Stat(basePath)
// Resolve symlinks in basePath to mitigate TOCTOU race conditions (CWE-367).
// By resolving before validation, we ensure the stat check and path join
// operate on the same physical directory.
resolvedBase, err := filepath.EvalSymlinks(basePath)
if err != nil {
return "", fmt.Errorf("cannot resolve base path: %w", err)
}

// Verify resolved base path is an existing directory
info, err := os.Stat(resolvedBase)
if err != nil {
return "", fmt.Errorf("cannot access base path: %w", err)
}
if !info.IsDir() {
return "", errors.New("base path must be a directory")
}
basePath = resolvedBase

if relativePath == "" {
return "", errors.New("empty relative path")
Expand Down
Loading