From 7ea9e6d53bde1ccca766f7537112150f58a03c07 Mon Sep 17 00:00:00 2001 From: Darrell van Swinderen Date: Wed, 23 Sep 2026 12:54:39 +0200 Subject: [PATCH] fix(security): the three code scanning alerts 3.5.0 raised - **Stream Deck routes are looked up as own properties** (alert 17). The key is built from the request, and a bare `ROUTES[key]` also finds what every object inherits. `Object.hasOwn` first. - **A batch log line keeps the clip id out of its format string** (alert 18), where a `%s` would be read as a directive. - Alert 19 is `tagPatternRules.ts` compiling a tag rule the user wrote, which is the feature, and is dismissed as won't fix the same way alert 15 was; that file is the mitigation. `npm run check` 866; `streamdeck-check.mjs` exit 0. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/main/routes/clips.ts | 5 ++++- src/main/services/streamdeck/server.ts | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/routes/clips.ts b/src/main/routes/clips.ts index 7c55990..4450ec0 100644 --- a/src/main/routes/clips.ts +++ b/src/main/routes/clips.ts @@ -329,8 +329,11 @@ clipsRouter.post('/batch/compress-published', asyncHandler(async (req, res) => { await new CompressPublishedClipAction().execute({ clipId }); } catch (error) { failed += 1; + // The id is from the request, so it is an argument, never part of the + // format string, where a `%s` would be read as a directive. console.error( - `[batch] compressing the published copy of clip ${clipId} failed:`, + '[batch] compressing the published copy of clip %s failed: %s', + String(clipId), error instanceof Error ? error.message : String(error), ); } diff --git a/src/main/services/streamdeck/server.ts b/src/main/services/streamdeck/server.ts index 06f1bc2..0475c5a 100644 --- a/src/main/services/streamdeck/server.ts +++ b/src/main/services/streamdeck/server.ts @@ -90,7 +90,10 @@ export async function startStreamDeck(): Promise { }; const path = (req.url ?? '').split('?')[0]; - const route = ROUTES[`${req.method} ${path}`]; + // An own property only: the key comes from the request, and a bare lookup + // would also find what every object inherits. + const key = `${req.method} ${path}`; + const route = Object.hasOwn(ROUTES, key) ? ROUTES[key] : undefined; if (!route) return send(404, { error: 'No such key' }); void readBody(req)