fix: prevent path traversal in S3 custom template downloads#7218
fix: prevent path traversal in S3 custom template downloads#7218sandiyochristan wants to merge 3 commits intoprojectdiscovery:devfrom
Conversation
S3 object keys are attacker-controlled and were used directly in filepath.Join without validation, allowing writes outside the intended template directory (similar to Zip Slip). Added path prefix validation and tightened directory permissions from 0775 to 0750.
Neo - PR Security ReviewNo security issues found Highlights
Hardening Notes
Comment |
WalkthroughAdded path traversal protection and stricter directory permissions to S3 download logic in Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/external/customtemplates/s3.go`:
- Around line 88-92: The current path traversal check using strings.HasPrefix on
the cleaned paths (file := filepath.Clean(filepath.Join(targetDirectory, key)))
can be bypassed by sibling directories with matching prefixes; update the check
to compare against the cleaned target directory with a trailing path separator
(e.g., base := filepath.Clean(targetDirectory) + string(os.PathSeparator)) and
then verify that strings.HasPrefix(file, base); reference the variables file,
targetDirectory, key and the calls to
filepath.Clean/filepath.Join/strings.HasPrefix when making this change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a5e9ac65-3ee3-4897-bc03-dac543969719
📒 Files selected for processing (1)
pkg/external/customtemplates/s3.go
…ctory bypass The strings.HasPrefix check without a trailing separator allows bypass via sibling directories with matching prefixes (e.g., /templates-evil matching /templates). Appending filepath.Separator ensures only true subdirectories pass validation.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pkg/external/customtemplates/s3.go (1)
88-94: Preferfilepath.Relfor containment checks instead ofstrings.HasPrefix.Current logic fixes the sibling-prefix bypass, but
filepath.Relis a more robust path-containment check and avoids edge-case path-form handling via string operations.♻️ Optional refactor
- file := filepath.Clean(filepath.Join(targetDirectory, key)) - // Prevent path traversal - ensure the file stays within targetDirectory - // Append separator to prevent sibling directory bypass (e.g., /templates-evil matching /templates) - cleanTarget := filepath.Clean(targetDirectory) + string(filepath.Separator) - if !strings.HasPrefix(file, cleanTarget) { + cleanTarget := filepath.Clean(targetDirectory) + file := filepath.Clean(filepath.Join(cleanTarget, key)) + relPath, err := filepath.Rel(cleanTarget, file) + if err != nil || relPath == ".." || strings.HasPrefix(relPath, ".."+string(filepath.Separator)) { return fmt.Errorf("path traversal detected in S3 object key: %s", key) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/external/customtemplates/s3.go` around lines 88 - 94, Replace the current string-prefix containment check with a filesystem-aware containment check using filepath.Rel: compute file := filepath.Clean(filepath.Join(targetDirectory, key)), then call rel, err := filepath.Rel(filepath.Clean(targetDirectory), file) and ensure err == nil and that rel does not start with ".." (or equal "." is allowed) to detect path traversal; update the error to return fmt.Errorf("path traversal detected in S3 object key: %s", key) when rel indicates escaping the targetDirectory. Use the existing variables file, targetDirectory and key and remove the strings.HasPrefix / cleanTarget logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@pkg/external/customtemplates/s3.go`:
- Around line 88-94: Replace the current string-prefix containment check with a
filesystem-aware containment check using filepath.Rel: compute file :=
filepath.Clean(filepath.Join(targetDirectory, key)), then call rel, err :=
filepath.Rel(filepath.Clean(targetDirectory), file) and ensure err == nil and
that rel does not start with ".." (or equal "." is allowed) to detect path
traversal; update the error to return fmt.Errorf("path traversal detected in S3
object key: %s", key) when rel indicates escaping the targetDirectory. Use the
existing variables file, targetDirectory and key and remove the
strings.HasPrefix / cleanTarget logic.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ba46475-73fa-4604-bb33-0356525842c8
📒 Files selected for processing (1)
pkg/external/customtemplates/s3.go
Proposed Changes
The S3 custom template download function is vulnerable to path traversal (CWE-22), similar to the well-known "Zip Slip" vulnerability class. S3 object keys are attacker-controlled and were used directly in
filepath.Join()without validation, allowing template files to be written outside the intended download directory.Additionally, directories were created with overly permissive
0775permissions, allowing other local users to modify downloaded templates.Root Cause
In
pkg/external/customtemplates/s3.go, thedownloadToFilefunction constructs the output path by directly joining the target directory with the S3 object key:S3 object keys can contain path separators and traversal sequences. An attacker who controls the contents of an S3 bucket (or compromises one) can create objects with keys like:
../../../etc/cron.d/malicious-job../../.ssh/authorized_keys../../../home/user/.bashrcExploitation Scenario
-aws-bucket-name my-templates../../../home/user/.bashrcfilepath.Join(downloadPath, "../../../home/user/.bashrc")resolves outsidedownloadPath.bashrc→ arbitrary code execution on next shell loginThe Fix
Path Validation — The output path is now cleaned with
filepath.Clean()and validated withstrings.HasPrefix()to ensure it stays withintargetDirectory:Tightened Permissions — Directory permissions changed from
0775to0750, preventing other local users from modifying downloaded template files.Files Changed
pkg/external/customtemplates/s3.go— added path traversal validation indownloadToFile, tightened directory permissions from0775to0750Security Impact
Proof
This follows the same validated pattern already used in
pkg/installer/template.gofor zip extraction path traversal prevention. The fix is a standard defense against Zip Slip-style attacks as recommended by Snyk's research.Checklist
devbranchSummary by CodeRabbit