Improper limitation of a pathname to a restricted directory ('Path Traversal')

Description

Constructing file or path information dynamically, especially from user input, poses a significant security risk. If not handled correctly, attackers could manipulate these paths to access or manipulate sensitive files, leading to data breaches or system compromise. It is crucial to ensure that user input is not used directly to interact with the file system, as this can be exploited to perform path traversal attacks.

Remediations

To mitigate the risks associated with dynamic file path construction from user inputs, apply the following best practices:

✅ Hash or Replace User Input

When dealing with user input for file operations, hash the input or replace it with a system-generated unique identifier to prevent path manipulation.

✅ Use filepath.Base

Extract only the filename from the path, ignoring any directory information, to avoid directory traversal vulnerabilities.

✅ Validate Paths Before Use

Always perform validation on the resolved paths before accessing files to ensure they are within the expected directory.

import (
"crypto/rand"
"encoding/hex"
"io"
"log"
"path/filepath"
"strings"
)

// userData struct holds user-related data with a unique ID for file operations
type userData struct {
id string // Unique identifier for the filename
userFilename string // Original filename from the user, kept for reference
}

// newUserData constructs a new userData instance with a random file ID
func newUserData(userFilename string) userData {
return userData{
id: randomFileID(), // Use a random ID instead of user-provided filename
userFilename: userFilename,
}
}

// randomFileID generates a secure random ID to be used as a filename
func randomFileID() string {
id := make([]byte, 16)
if _, err := io.ReadFull(rand.Reader, id); err != nil {
log.Fatal(err)
}
return hex.EncodeToString(id)
}

func main() {
// Simulated user input, which may be malicious
data := newUserData("../../possibly/malicious")

// Define a safe base path for file operations
const basePath = "/tmp/"

// Resolve the full path using the safe base path and the random ID
resolvedPath, err := filepath.Join(basePath, filepath.Base(data.id))
if err != nil {
log.Fatal(err)
}

// Ensure the resolved path is within our designated base path
if !strings.HasPrefix(resolvedPath, basePath) {
log.Fatal("The resolved path does not start with the expected base path")
}

// The file can now be safely accessed using resolvedPath
// Further file processing code would go here
}

Resources

Associated CWE

OWASP Top 10

Configuration

To skip this rule during a scan, use the following flag

bearer scan /path/to/your-project/ --skip-rule=go_gosec_filesystem_filereadtaint

To run only this rule during a scan, use the following flag

bearer scan /path/to/your-project/ --only-rule=go_gosec_filesystem_filereadtaint

Ready to take the next step? Learn more about Bearer Cloud.