You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Path traversal in disk file proxies: /files/download can read files outside the proxy root via .. segments #173
resolveFileProxy (lib/utils/resolve-file-proxy.ts) resolves user-controlled path segments against the proxy's disk_path with join(diskPath, relativePath) and no parent-segment or containment check. A request under a configured proxy prefix containing .. makes the server read files anywhere the process can reach (CWE-22).
ctx.db.matchFileProxy only does a plain startsWith(prefix) match, so .. segments survive normalization into relativePath (normalizePath collapses duplicated slashes but not dot segments).
Reproduction (concept)
With a disk proxy { matching_pattern: "local/*", disk_path: "/srv/files-root" } and a secret at /srv/secret.txt (outside the root):
GET /files/download/local/../secret.txt -> relativePath = "../secret.txt" -> join("/srv/files-root", "../secret.txt") = "/srv/secret.txt" -> the secret file is served.
GET /files/download/local/../../etc/passwd -> escapes two levels.
The HTTP proxy flavor forwards the same traversal segments upstream. Impact: read-any-file within the server process privileges on any deployment configuring a disk file proxy.
Proposed fix (small, contained)
In resolveFileProxy: after computing relativePath, refuse requests whose path contains a .. segment -> 400.
In resolveDiskProxy: resolve() the joined path and require that it stays inside resolve(diskPath) (defense in depth across separators/platforms).
Same guard applied to the http flavor so traversal segments are never forwarded upstream.
Tests included with the fix
unit: traversal attempts (single, multi, embedded deeper) -> 400 for both disk and http flavors; legit files inside the root and nested subdirectories still serve; containment check exercised independently of the .. guard
route-level (raw HTTP via node:http, since clients normalize ..) end-to-end: a secret outside the root never appears in a response; a normal proxy file still serves
Activity
9xj89gzrtw-hue commentedon Oct 23, 2026
/attempt #173
darzasassing-hub commentedon Oct 25, 2026
/attempt #173
Submitted PR: #178
Fix:
resolveFileProxywith HTTP 400 (protects both disk and http proxies).resolveDiskProxyviapath.resolve(), returning HTTP 403 if escaped.tests/routes/path-traversal-proxy.test.ts.