fix(web): normalize PDF attachment filenames safely - #175
Conversation
|
🦞👀 Pull request received. I will update this pull request when review starts. |
|
Codex review: needs maintainer review before merge. Reviewed August 28, 2026, 5:07 PM ET / 21:07 UTC. ClawSweeper reviewWhat this changesThe PR replaces chained PDF.js worker slash substitutions with a single filename-normalization scan, adds the pnpm patch to Docker dependency setup, and regenerates embedded web assets. Merge readinessCurrent main still has the vulnerable PDF.js filename-normalization chain. This MEMBER-authored PR remains relevant, but its draft head is dirty after the web-toolchain refresh and needs a rebased, regenerated artifact plus maintainer approval of the local dependency patch strategy. Priority: P1 Review scores
Verification
How this fits togetherClickClack’s web artifact viewer loads PDF.js to read PDF attachments, then the built web bundle is embedded in the Go API and served to browser clients. The changed worker converts PDF file-spec metadata into attachment names used by the viewer. flowchart LR
PDF[PDF attachment] --> Worker[PDF.js worker]
Worker --> Normalize[Filename normalization]
Normalize --> Viewer[Web artifact viewer]
Viewer --> Bundle[Embedded web assets]
Bundle --> API[Go API]
API --> Browser[Browser client]
Decision needed
Why: Choosing to maintain a local override for an upstream dependency that parses untrusted PDF metadata is a repository security-policy decision. Before merge
Findings
Agent review detailsSecurityNeeds attention: This is a targeted security remediation, but the locally patched PDF.js worker must be reviewed and verified on a rebased mergeable head. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Carry a narrowly documented temporary PDF.js patch only after rebasing it onto current main, regenerating the embedded assets, and verifying the exact artifact and Docker build. Do we have a high-confidence way to reproduce the issue? Yes, at source level: current main’s production PDF worker retains the three-stage replacement chain and the web viewer imports that worker. The reviewed snapshot does not include a malicious-PDF runtime trace. Is this the best way to solve the issue? Unclear pending maintainer direction: this is a narrow remediation, but permanently carrying a local security patch to PDF.js requires explicit repository approval and a current-main rebase. AGENTS.md: found, but no applicable review policy affected this item. Codex review notes: model internal, reasoning high; reviewed against 486fd23545af. LabelsLabel changes:
Label justifications:
EvidenceSecurity concerns:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
History |
54da493 to
e64f5a2
Compare
e64f5a2 to
546754c
Compare
Additional instructions
MUST: Keep Allow edits from maintainers enabled for this PR so maintainers
can help update the branch when needed.
What Problem This Solves
Fixes a double-escaping path in the bundled PDF worker reported by CodeQL alert 8. The path came from
pdfjs-dist@6.2.108, including its current upstream source.Why This Change Was Made
There is no newer
pdfjs-distrelease carrying a fix. A pinned pnpm patch replaces the dependency's ordered replacement chain with one explicit filename-normalization scan, preserving the upstream contract while removing the vulnerable pattern. Both modern and legacy worker builds are patched, and checked-in web assets are regenerated from that dependency.User Impact
PDF attachment filenames keep the same slash-normalization behavior without passing through a double-escaping replacement chain.
Evidence
node v26.7.0withpnpm 11.20.0pnpm install --frozen-lockfilepnpm buildruns with byte-identical embedded web assetsnode --check apps/api/internal/webassets/dist/_app/immutable/assets/pdf.worker.D3ahraH8.mjsdocker buildafter copying the pnpm patch into the dependency-install stageCoordination
PR #169's web source changes remain separate and retain their contributor ownership. This PR regenerates assets from current
main; it does not copy or supersede that source work.