From e23188bfaf6d0ab084712ad13455a0bea227a827 Mon Sep 17 00:00:00 2001 From: Stephen Baker Date: Sun, 19 Apr 2026 11:46:35 -0700 Subject: [PATCH] Fix path traversal in GET /api/chat-modes/:modeId The modeId route parameter was joined into a filesystem path without validation. Express decodes URL-encoded characters in route params, so a request like GET /api/chat-modes/..%2F..%2Fsome-file would escape the prompts directory and read any .json file the backend process can access. Validate modeId against a strict allowlist regex before constructing the path; reject anything else with 400. Co-Authored-By: Claude Opus 4.7 --- backend/src/routes/chatModes.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/routes/chatModes.js b/backend/src/routes/chatModes.js index 2d88676..ddd2020 100644 --- a/backend/src/routes/chatModes.js +++ b/backend/src/routes/chatModes.js @@ -95,9 +95,14 @@ router.get('/chat-modes', async (req, res) => { * GET /api/chat-modes/:modeId * Returns a specific chat mode configuration */ +const VALID_MODE_ID = /^[a-z0-9][a-z0-9-]{0,63}$/ + router.get('/chat-modes/:modeId', async (req, res) => { try { const { modeId } = req.params + if (!VALID_MODE_ID.test(modeId)) { + return res.status(400).json({ error: 'Invalid mode id' }) + } const filePath = path.join(PROMPTS_DIR, `${modeId}.json`) const mode = await loadModeConfig(filePath)