Path Traversal via HTTP Input

HIGH

User-controlled HTTP input reaches file system operations without path validation — filepath.Clean() alone is insufficient; filepath.Join("/uploads", "/etc/passwd") returns "/etc/passwd" in Go.

Rule Information

Language
Go
Category
Security
Author
Shivasurya
Shivasurya
Last Updated
2026-04-13
Tags
gosecuritypath-traversaldirectory-traversalzip-slipfile-systemCWE-22OWASP-A01
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset golang/GO-PATH-001 --project .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Cross-file analysis: 3 files

About This Rule

Understanding the vulnerability and how it is detected

Path traversal occurs when user-controlled input is used in file system operations without properly restricting the resulting path to an intended directory. Attackers inject sequences like `../../etc/passwd`, `../../../etc/shadow`, or `%2e%2e%2f` to read or write files outside the intended base directory.

**Go-specific pitfall — filepath.Join with absolute paths**: `filepath.Join("/var/uploads", "/etc/passwd")` returns `/etc/passwd` in Go. This is documented behavior: if an element is an absolute path, all preceding elements are discarded. A user supplying `/etc/passwd` as a filename completely bypasses the base directory constraint.

**filepath.Clean() is necessary but NOT sufficient**: `filepath.Clean("../../../etc/passwd")` returns `../../etc/passwd` — it resolves redundant separators and dots but does not anchor to any base directory. Clean must be followed by a `strings.HasPrefix(clean, baseDir)` check with a trailing separator.

**The correct pattern**: ```go clean := filepath.Join(baseDir, filename) clean = filepath.Clean(clean) if !strings.HasPrefix(clean, baseDir+string(filepath.Separator)) { // path traversal attempt } ``` Note the trailing separator — without it, `baseDir = "/uploads"` and `clean = "/uploads-secret/file.txt"` would pass the prefix check.

**Zip Slip vulnerability**: Archive extraction (zip, tar) is a common path traversal vector. A malicious archive contains entries with paths like `../../etc/cron.d/backdoor`. When extracted without path validation, files are written outside the extraction directory. Go's archive/zip and archive/tar packages provide the raw filename from the archive without sanitization — developers must validate each entry's path before extraction.

**Null byte injection**: In some contexts, filenames containing null bytes (`filename\x00.jpg`) may be truncated at the null byte by underlying C library functions. Go's os package handles null bytes safely (returns an error), but third-party or CGO code may not.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Sensitive File Read

Attackers read `/etc/passwd`, `/etc/shadow` (Unix), `C:\Windows\System32\config\SAM` (Windows), application configuration files containing database credentials, TLS private keys, or cloud credential files (~/.aws/credentials).

2

Application Source Code Disclosure

Reading `../../app/main.go`, `../../.env`, or `../../config.yaml` exposes application secrets, database passwords, API keys, and business logic.

3

Malicious File Write (Remote Code Execution)

Write access enables persistence: write to `/etc/cron.d/`, `~/.ssh/authorized_keys`, or executable paths. In web contexts, writing a server-side script to a web-accessible directory enables RCE.

4

Zip Slip — Archive Extraction RCE

A malicious archive entry `../../.ssh/authorized_keys` writes the attacker's SSH public key to the server's authorized_keys file during archive extraction. Demonstrated against multiple Go-based archive tools.

How to Fix

Recommended remediation steps

  • 1Always use filepath.Clean() after filepath.Join() to resolve remaining .. components.
  • 2After Clean, verify the path has the expected base directory prefix WITH a trailing separator.
  • 3Never trust user-supplied filenames from archives — validate each entry path during extraction.
  • 4Use os.OpenFile with appropriate flags; consider os.O_EXCL to prevent overwrite attacks.
  • 5Reject filenames containing null bytes, path separators, or explicit .. components.
  • 6Serve static files through http.FileServer with a restricted http.Dir, not by path construction.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

Tracks taint from HTTP framework sources (net/http.Request, gin.Context, echo.Context, fiber.Ctx) to os package file operations (os.Open, os.ReadFile, os.Create, os.WriteFile, os.OpenFile) and filepath operations (filepath.Join, filepath.Abs) with global inter-procedural scope.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A01:2021 — Broken Access Control
CWE Top 25 (2024)
CWE-22 — Path Traversal (ranked #8)
PCI DSS v4.0
Requirement 6.2.4 — Protect against path traversal attacks
NIST SP 800-53 Rev 5
SI-10 — Information Input Validation

References

External resources and documentation

Similar Rules

Explore related security rules for Go

Frequently Asked Questions

Common questions about Path Traversal via HTTP Input

Path traversal occurs when user-controlled input is used in file system operations without properly restricting the resulting path to an intended directory. Attackers inject sequences like `../../etc/passwd`, `../../../etc/shadow`, or `%2e%2e%2f` to read or write files outside the intended base directory. **Go-specific pitfall — filepath.Join with absolute paths**: `filepath.Join("/var/uploads", "/etc/passwd")` returns `/etc/passwd` in Go. This is documented behavior: if an element is an absolute path, all preceding elements are discarded. A user supplying `/etc/passwd` as a filename completely bypasses the base directory constraint. **filepath.Clean() is necessary but NOT sufficient**: `filepath.Clean("../../../etc/passwd")` returns `../../etc/passwd` — it resolves redundant separators and dots but does not anchor to any base directory. Clean must be followed by a `strings.HasPrefix(clean, baseDir)` check with a trailing separator. **The correct pattern**: ```go clean := filepath.Join(baseDir, filename) clean = filepath.Clean(clean) if !strings.HasPrefix(clean, baseDir+string(filepath.Separator)) { // path traversal attempt } ``` Note the trailing separator — without it, `baseDir = "/uploads"` and `clean = "/uploads-secret/file.txt"` would pass the prefix check. **Zip Slip vulnerability**: Archive extraction (zip, tar) is a common path traversal vector. A malicious archive contains entries with paths like `../../etc/cron.d/backdoor`. When extracted without path validation, files are written outside the extraction directory. Go's archive/zip and archive/tar packages provide the raw filename from the archive without sanitization — developers must validate each entry's path before extraction. **Null byte injection**: In some contexts, filenames containing null bytes (`filename\x00.jpg`) may be truncated at the null byte by underlying C library functions. Go's os package handles null bytes safely (returns an error), but third-party or CGO code may not.
Use Code Pathfinder to scan your codebase: pathfinder scan --ruleset golang/GO-PATH-001 --project .
This vulnerability is rated as HIGH severity.
Yes! Code Pathfinder allows you to customize rules. Modify detection patterns, adjust severity levels, add custom sanitizers, and configure the rule to fit your organization's security policies.

New feature

Get these findings posted directly on your GitHub pull requests

The Path Traversal via HTTP Input rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works