Skip to content

fix(ns-api-server): guard file endpoints against path traversal#1797

Merged
gsanchietti merged 1 commit into
mainfrom
improve_api_security
Jul 15, 2026
Merged

fix(ns-api-server): guard file endpoints against path traversal#1797
gsanchietti merged 1 commit into
mainfrom
improve_api_security

Conversation

@gsanchietti

@gsanchietti gsanchietti commented Jul 14, 2026

Copy link
Copy Markdown
Member

Summary

Adds explicit path-containment validation to DownloadFile and DeleteFile in packages/ns-api-server/files/src/methods/files.go. A new safeFilePath() helper resolves the path with filepath.Join and verifies it stays under the configured download directory (trailing-separator prefix check); traversal attempts now return HTTP 400. UploadFile is unchanged (it already ignores the client-supplied name and generates a UUID).

SonarCloud issues addressed

Clears three BLOCKER findings (rule gosecurity:S2083, CWE-22), all on files.go:

  • AZ9aszoIS1IsCbTKZ7OU — line 77 (os.Open)
  • AZ9aszoIS1IsCbTKZ7OS — line 118 (c.File)
  • AZ9aszoIS1IsCbTKZ7OT — line 129 (os.Remove)

⚠️ This is NOT a real exploitable vulnerability

This is defense-in-depth hardening, not a security incident:

  • The routes are administrator-authenticated (JWT, /files/:filename inside authGroup). An attacker would already need an admin token — and an admin has root-equivalent control by other means.
  • gin's default path cleaning collapses ../ and decoded %2f before the handler runs. On a live device every crafted traversal request (..%2fsecret_jwt, ../../../etc/shadow, double-encoded variants, direct-to-backend on 127.0.0.1:8090) returned 404/400 — no traversal was reachable through the nginx + gin stack.
  • Realistic CVSS 3.1: base ~7.1 (High) on the code alone, but adjusted for the mitigations (E:U, admin-only) it drops to ~2–4 (Low).

The value of the change is removing the reliance on undocumented framework behavior: a future gin upgrade, UseRawPath toggle, or route refactor could otherwise re-expose the sink. It also clears the static-analysis blocker.

Verification

  • gofmt clean, go vet clean.
  • New unit test methods/files_test.go (go test ./methods/ → ok): rejects .., ../secret_jwt, ../../../etc/shadow, ../downloads-evil (prefix-sibling); allows legit / subdir / contained-absolute names.
  • Live device: legit download (backend + via nginx) and delete still work — no regression. Device restored to its original binary afterwards.

Validate the resolved path in DownloadFile and DeleteFile stays within the
configured download directory before any filesystem access, and reject with
HTTP 400 otherwise. UploadFile is unaffected (it ignores the client name and
generates a UUID).

Addresses SonarCloud issues AZ9aszoIS1IsCbTKZ7OU, AZ9aszoIS1IsCbTKZ7OS and
AZ9aszoIS1IsCbTKZ7OT (rule gosecurity:S2083, CWE-22), all on files.go.

NOTE: this is a defense-in-depth hardening, not a real exploitable flaw. The
routes are administrator-authenticated (JWT), and gin's default path cleaning
already collapses "../" and decoded "%2f" before the handler runs, so no
traversal could be triggered through the deployed nginx+gin stack (verified on
a live device: every crafted request returned 404/400). The fix removes the
reliance on that framework behavior so a future gin/config/route change cannot
re-expose it, and clears the static-analysis blocker.

Assisted-by: Claude Code:claude-opus-4-8
@sonarqubecloud

Copy link
Copy Markdown

@gsanchietti gsanchietti requested a review from Tbaile July 14, 2026 09:32
@gsanchietti gsanchietti merged commit f4ee4ac into main Jul 15, 2026
4 checks passed
@gsanchietti gsanchietti deleted the improve_api_security branch July 15, 2026 05:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants