From f264538db1d669c7b5b2a0ae29e6228a13200acc Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 10:35:47 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20path=20traversal=20in=20file=20uploads?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: adihex <82704954+adihex@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ apps/zettel/src/index.ts | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..e95791b --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2026-09-04 - [Path Traversal bypass via path.basename in POSIX env] +**Vulnerability:** Path traversal in file upload endpoints handling `file.name` via `path.basename`. +**Learning:** In Node.js running on POSIX systems (Linux/macOS), `path.basename` only strips `/`, but an attacker can provide a Windows-style path traversal payload (e.g. `..\..\etc\passwd`). Node's `path.basename` considers the entire string as the file name, meaning `path.join` will parse it and traverse directories. +**Prevention:** Thoroughly sanitize file names using strict regex matching (e.g., `file.name.replace(/[^a-zA-Z0-9.-]/g, "_")`) instead of relying on `path.basename` across mixed OS environments. diff --git a/apps/zettel/src/index.ts b/apps/zettel/src/index.ts index 332788e..b318650 100644 --- a/apps/zettel/src/index.ts +++ b/apps/zettel/src/index.ts @@ -265,9 +265,10 @@ const routes = api const arrayBuffer = await file.arrayBuffer(); const data = Buffer.from(arrayBuffer); + const safeFileName = file.name.replace(/[^a-zA-Z0-9.-]/g, "_"); const tmpPath = path.join( os.tmpdir(), - `zettel-audio-${Date.now()}-${path.basename(file.name)}`, + `zettel-audio-${Date.now()}-${safeFileName}`, ); fs.writeFileSync(tmpPath, data);