Conversation
The username, lineId and productionId path params on the WHIP/WHEP POST
routes were URL-decoded and interpolated into log messages without any
sanitization, allowing newline/CR/ANSI injection to forge log entries.
Add restrictive TypeBox patterns: numeric-only (^[0-9]+$) for productionId
and lineId (consistent with api_productions.ts), and ^[\w .-]{1,200}$ for
username. A literal space is used instead of \s so control chars such as
\n and \r are rejected. Adds regression tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
code-reviewer verdict: LGTM Code ReviewSummary: Fixes the log-injection in #287 by replacing permissive Blocking: None. Warnings:
Suggestions:
CI green, mergeable, no human changes-requested. NOTE: this account ( |
birme
left a comment
There was a problem hiding this comment.
code-reviewer (daily-backlog-pr Phase 3):
Code Review
Verdict: Needs Changes
Summary: The core sanitization on the WHIP/WHEP POST routes is correct and effectively blocks CRLF/ANSI log injection while still accepting legitimate values, but the fix is incomplete: the DELETE routes still log a user-controlled path param unsanitized (the same #287 vector), and the WHEP change ships with no test coverage.
Blocking
-
src/api_whip.tsDELETE/whip/:productionId/:lineId/:sessionIdandsrc/api_whep.tsDELETE/whep/:productionId/:lineId/:sessionId— The DELETE handlers logsessionIddirectly (Log().info(\Received WHIP DELETE request - sessionId: ${sessionId}, IP: ${request.ip}`)) **before** any DB lookup, and their params schema is stillType.String({ maxLength: 200 })with nopattern.sessionId,productionIdandlineIdare all fully user-controlled path params, soDELETE /api/v1/whip/1/1/evil%0aINJECTED-LOG-LINEreproduces exactly the CRLF log injection this PR claims to close for #287. The error path also logssessionId. Apply the same^[0-9]+$constraint toproductionId/lineIdand a control-char-rejecting pattern (a UUID pattern is ideal, since sessionId is generated as a UUIDv4) tosessionId` on both DELETE routes. -
src/api_whep.tsPOST params schema (WHEP) — The WHEP POST change is identical to WHIP but has zero test coverage: there is noapi_whep.test.tsinsrc/, and the two new regression tests were added only toapi_whip.test.ts. Per the testing criteria a security fix must be exercised by a test on the affected path. Add a WHEP test file mirroring the WHIP regression tests (control-char username -> 400, non-numeric productionId -> 400) so the WHEP fix is not silently unverified.
Warnings
-
src/api_whip.test.ts— This test file does not mock./log(jest.mock('./log', () => ({ Log: () => ({ info, error, debug, warn }) }))). This is a pre-existing gap not introduced by this PR, but since the PR adds tests that specifically trigger log-injection code paths, mocking./loghere would both silence noisy output and let you assert the sanitized value never reaches the logger. -
src/api_whip.ts/src/api_whep.tsPOST params —usernamecarries bothmaxLength: 200andpattern: '^[\\w .-]{1,200}$'; the{1,200}quantifier already bounds length, somaxLengthis redundant. Harmless, but consider dropping one to avoid two sources of truth on the bound.
Suggestions
- The username pattern
[\w .-]is intentionally narrow. Confirm with product that broadcast operator display names never legitimately contain non-ASCII letters (e.g. accented characters) or characters like+ @ ( ); if they can, a control-char denylist would be a less surprising constraint than an ASCII allowlist while still closing the injection vector. Not blocking — the current allowlist is safe and matches the PR's stated intent.
Domain Note
This change affects WHIP/WHEP session lifecycle (ingest/egress route params). Consider consulting the intercom-expert agent to confirm the numeric-only productionId/lineId and the [\w .-] username allowlist match all real-world broadcast client behavior.
Positive verification: The regex reasoning is sound — TypeBox pattern compiles to a JS RegExp without the m/s flags, so ^...$ anchors to the whole string, . does not match a newline, and $ does not tolerate a trailing newline; the \w/space/dot/dash class excludes newline, carriage-return and ESC. Using a literal space instead of \s (which matches newline/CR/tab) is correct, as the PR body notes. Legitimate numeric ids and alphanumeric usernames pass.
Next steps: pass Blocking items to bug-fixer -> once resolved, use pr-author to open the PR.
Code Review — PR #306: fix(security): constrain WHIP/WHEP path params to prevent log injectionCloses #287. Adds TypeBox What's correct
BlockingB1 — Test file does not WarningsW1 — WHEP has no dedicated regression test. The two new tests were added only to W2 — DELETE/PATCH routes still log an unconstrained path param. W3 — VerdictNeeds Changes — 1 Blocking (missing |
Code ReviewVerdict: Needs Changes Summary: The core fix is correct — constraining Blocking
Warnings
Suggestions
Domain NoteAffects WHIP/WHEP session lifecycle (path-param validation). Confirm Posted by daily-backlog-pr Phase 3; moving back to Ready. |
Code Review — Verdict: NEEDS CHANGES(Posted as a comment: GitHub blocks a formal request-changes review on a self-authored PR under this automation account. Treat this as the review of record.) Summary: The fix is well-targeted — it replaces the permissive Blocking
Warnings
Moving back to Ready for the missing WHEP tests and |
|
Automated code-reviewer verdict (daily-backlog-pr Phase 3): NEEDS CHANGES
The POST-path fix is sound (anchored TypeBox High
Medium
Nits
|
|
Automated code-reviewer verdict (daily-backlog-pr Phase 3): NEEDS CHANGES The core fix is sound: TypeBox Blocking
Warnings
Either the blocking item alone or the 3 warnings require changes. Moving issue #287 back to Ready.
|
daily-backlog-pr Phase 3 — automated review (verdict: Needs Changes)
Findings
Numeric-only |
Code ReviewVerdict: Needs Changes Summary: The POST WHIP/WHEP username/lineId/productionId log-injection vector is correctly closed via strict TypeBox pattern validation, but the fix is incomplete — the DELETE routes still log an attacker-controlled Blocking
Warnings
Suggestions
|
Summary
username,lineIdandproductionIdpath params onPOST /api/v1/whip/:productionId/:lineId/:usernameand the WHEP equivalent were URL-decoded by Fastify and interpolated directly into log messages with no sanitization, allowing newline (%0a), carriage-return (%0d) and ANSI-escape (%1b[...) injection to forge or corrupt log entries.patternconstraints on both routes: numeric-only^[0-9]+$forproductionIdandlineId(matching the existing convention inapi_productions.ts, and correct since line/production ids are generated as numeric strings), and^[\w .-]{1,200}$forusername.\s, because\salso matches\n/\r/\t— the exact control characters this fix must reject. Requests carrying control chars now fail schema validation with a 400 before anything is logged.Test plan
npm test) — 245 passed (2 new)npm run typecheck)npm run lint) — 0 errorsCloses #287
🤖 Generated with Claude Code
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com