fix(cli): prevent code injection via filenames in loader/section codegen - #461
Open
0xcucumbersalad wants to merge 1 commit into
Open
fix(cli): prevent code injection via filenames in loader/section codegen#4610xcucumbersalad wants to merge 1 commit into
0xcucumbersalad wants to merge 1 commit into
Conversation
generate-loaders.ts and generate-sections.ts built the emitted `.gen.ts`
by interpolating filename-derived values (entry.key, importPath, rel)
directly into string literals:
` "${entry.key}": createLoaderEntry("${entry.key}", () => import("${entry.importPath}")),`
Those values were pasted raw, so a repo file whose NAME contained `"`,
`)` or `;` broke out of the string literal into executable generated
code — run on the next `dev`/`build` (RCE on the dev/CI machine that
builds an untrusted repo).
Fix: emit every filename-derived value via JSON.stringify (proper string
quoting + escaping) in both generators — loader/action keys and import
specifiers, and section meta keys, static import specifiers, and the
--registry sectionImports map. For ordinary paths the output is
byte-identical to the previous double-quoted form, so existing shape
tests are unchanged.
Adds codegen-injection.test.ts: writes a loader and a section whose
FILENAME carries a quote/paren breakout payload, runs each real
generator, and asserts the emitted quote is escaped and the raw
breakout never appears.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
generate-loaders.tsandgenerate-sections.tsbuild the emitted.gen.tsby interpolating filename-derived values (entry.key,importPath,rel) directly into string literals:` "${entry.key}": createLoaderEntry("${entry.key}", () => import("${entry.importPath}")),`Those values were pasted raw — no escaping.
Impact
A repo file whose name contains
",)or;breaks out of the string literal into executable generated code, which runs on the nextdev/build. Feeding an untrusted repo (or a merged PR adding such a file) through codegen = code execution on the dev/CI machine.Example file committed to a site:
lands in
.deco/loaders.gen.tsas live TypeScript. (POSIX filenames can't contain/or NUL, but");(are all legal — enough to break out.)Fix
Emit every filename-derived value through
JSON.stringify(correct string quoting + escaping) in both generators:.tsalias key, and everyimport(...)specifier;sectionMetakeys + meta values,syncComponents/loadingFallbackskeys, the staticimport * as _syncN/import { LoadingFallback as _fbN }specifiers, and the--registrysectionImportsmap (./sections/<rel>+import(...)).For ordinary paths
JSON.stringify("a/b")==="a/b", so output is byte-identical for normal inputs — the 17 existing shape tests pass unchanged.Tests
New
codegen-injection.test.ts(2 tests): writes a loader and a section whose filename carries azz");PWN;(breakout payload, runs each real generator, and asserts the emitted quote is escaped (zz\");PWNpresent) and the raw breakout never appears (zz");PWNabsent). Full codegen suite:Scope
Finding F6 from the source audit. Companion PRs: #459 (F5 git-clone command injection), #460 (F4 Supabase SQLi). Same class — untrusted input reaching a raw sink (shell / SQL / generated code) without escaping; each fixed by encoding at the boundary (argv array / validation+quote-escape /
JSON.stringify).🤖 Generated with Claude Code
Summary by cubic
Fixes code injection in CLI codegen by escaping all filename-derived values in
generate-loaders.tsandgenerate-sections.ts. Malicious filenames could previously break out of string literals and execute code during dev/build.JSON.stringifyfor loader/action keys,.tsalias keys, and all dynamicimport(...)specifiers.JSON.stringifyforsectionMetakeys/values, static import specifiers,syncComponents/loadingFallbackskeys, and--registryimport map keys/specifiers.Written for commit bd44575. Summary will update on new commits.