From 3d51c6e7c80182dd8d7368af70bfdc3a77c7635d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 22 Jan 2026 05:30:33 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20path=20traversal=20in=20job=20filename?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 Severity: CRITICAL 💡 Vulnerability: The `startJob` API endpoint allowed filenames with path traversal characters (e.g., `../../etc/passwd`), potentially exposing the file system. 🎯 Impact: Attackers could potentially read or manipulate arbitrary files on the system if the printer backend logic allows it. 🔧 Fix: Added Zod schema refinement to `JobStartRequestSchema` and `JobStartDataSchema` to strictly reject filenames containing `..` path segments. ✅ Verification: Added `src/main/webui/schemas/__tests__/web-api.schemas.test.ts` to verify that `..` patterns are rejected while valid filenames are accepted. Verified using a standalone script. --- .jules/sentinel.md | 5 +++ .../schemas/__tests__/web-api.schemas.test.ts | 34 +++++++++++++++++++ src/main/webui/schemas/web-api.schemas.ts | 10 ++++-- 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/main/webui/schemas/__tests__/web-api.schemas.test.ts diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 501ee8f..03026c1 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -7,3 +7,8 @@ **Vulnerability:** The application used a hardcoded string ('ffui-webui-2025') as a salt for HMAC signatures on session tokens. This makes session tokens predictable if the password is known or weak, and allows rainbow table attacks if the source code is public. **Learning:** Hardcoded salts in open-source projects defeat the purpose of salting. Even if combined with a password, they don't provide per-installation uniqueness. **Prevention:** Use a random secret generated at runtime (or installation time) and persist it in the application configuration. + +## 2026-01-22 - Path Traversal in API Schemas +**Vulnerability:** The `JobStartRequestSchema` validated filenames only by length (`min(1)`), allowing path traversal characters (e.g., `../../etc/passwd`). If the backend naively concatenates this filename to a path, it allows arbitrary file read/write. +**Learning:** Zod's string validation is basic. For file paths, explicit validation against directory traversal (e.g., forbidding `..`) is essential, especially when inputs are passed to filesystem operations. +**Prevention:** Use `.refine()` in Zod schemas to reject strings containing `..` path segments: `/(^|[\/])\.\.([\/]|$)/`. diff --git a/src/main/webui/schemas/__tests__/web-api.schemas.test.ts b/src/main/webui/schemas/__tests__/web-api.schemas.test.ts new file mode 100644 index 0000000..8b08c4a --- /dev/null +++ b/src/main/webui/schemas/__tests__/web-api.schemas.test.ts @@ -0,0 +1,34 @@ + +import { JobStartRequestSchema } from '../web-api.schemas'; + +describe('JobStartRequestSchema', () => { + it('should accept valid filenames', () => { + const validInputs = [ + { filename: 'test.gcode' }, + { filename: 'folder/test.gcode' }, + { filename: 'my_print_job.gcode' }, + { filename: 'job.gcode', startNow: false }, + ]; + + validInputs.forEach((input) => { + const result = JobStartRequestSchema.safeParse(input); + expect(result.success).toBe(true); + }); + }); + + it('should reject path traversal attempts', () => { + const invalidInputs = [ + { filename: '../system.conf' }, + { filename: '../../etc/passwd' }, + { filename: 'folder/../hack.txt' }, + { filename: '/../root.txt' }, + { filename: '..\\windows\\system32' }, + ]; + + invalidInputs.forEach((input) => { + const result = JobStartRequestSchema.safeParse(input); + // We expect validation to fail for these insecure inputs + expect(result.success).toBe(false); + }); + }); +}); diff --git a/src/main/webui/schemas/web-api.schemas.ts b/src/main/webui/schemas/web-api.schemas.ts index acff167..6bd918f 100644 --- a/src/main/webui/schemas/web-api.schemas.ts +++ b/src/main/webui/schemas/web-api.schemas.ts @@ -65,7 +65,10 @@ export const TemperatureDataSchema = z.object({ * Job start data validation */ export const JobStartDataSchema = z.object({ - filename: z.string().min(1), + filename: z + .string() + .min(1) + .refine((val) => !/(^|[\\/])\.\.([\\/]|$)/.test(val), 'Path traversal characters (..) are not allowed'), leveling: z.boolean().optional().default(false), startNow: z.boolean().optional().default(true), }); @@ -93,7 +96,10 @@ const MaterialMappingSchema = z.object({ }); export const JobStartRequestSchema = z.object({ - filename: z.string().min(1, 'Filename is required'), + filename: z + .string() + .min(1, 'Filename is required') + .refine((val) => !/(^|[\\/])\.\.([\\/]|$)/.test(val), 'Path traversal characters (..) are not allowed'), leveling: z.boolean().optional().default(false), startNow: z.boolean().optional().default(true), materialMappings: z