[GH-ISSUE #8973] [Bug] JavaScript analysis treats uppercase loader suffixes as explicit module modes #7870

Open
opened 2026-11-05 06:45:36 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @xu91102 on GitHub (Nov 5, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/8973

Before submitting

  • I searched related open and closed issues and read the relevant production diffs.
  • The reproducer uses only owned, benign local fixtures; private paths and credentials are omitted.

Area

JavaScript artifact analysis; parser-owned runtime context and module graph.

Observed behavior

On main 71f680d7c1aa7a45ba0325fe87b104744b0c105f, the public analyze-javascript-application CLI reports a source-module row with path: "main.MJS", module_format: "esm" for a CommonJS-style file with no import/export declaration. The stock Node 24.22.1 executable successfully runs that same file as CommonJS and prints 42. Lowercase .mjs with the same bytes is an explicit ES module and fails because require is unavailable; lowercase .cjs successfully prints 42 and REA correctly calls it CommonJS. Each test used a separate directory, including on this case-insensitive filesystem.

Reproduction

Create an otherwise empty directory with these three files:

{"type":"commonjs","main":"main.MJS"}
// main.MJS
const value = require('./dep.cjs');
console.log(value);
// dep.cjs is a separate file containing: module.exports = 42;

Run stock node /absolute/fixture/main.MJS, then from the built main checkout run node scripts/rea.mjs analyze-javascript-application /absolute/fixture --json. Native execution of this owned fixture exits 0 and prints 42; REA exits 0 but its source-module observation for main.MJS declares esm. Repeat in separate directories with .mjs and .cjs as controls. Three public CLI analyses and four native suffix controls were executed; source hashes stayed unchanged. No external application or target was executed by REA.

Expected behavior

A case-folded spelling of .mjs or .cjs must not by itself establish the exact suffix's loader mode or strictness. Preserve the exact path and inert syntax facts. When the surrounding observations do not establish a loader, retain unknown rather than declaring an ES module or CommonJS wrapper. This report does not ask REA to assume that every uppercase suffix runs as CommonJS, to introduce a fallback loader, or to execute the selected application.

Impact and scope

False positive module-format evidence on a valid benign Node entrypoint. Parser-owned context is also consumed by strictness and require-origin interpretation; the base incorrectly gives main.MJS the same explicit-ESM classification as main.mjs. The normalized requirement relation was unresolved on both, while the .cjs control retained CommonJS facts. This does not establish every uppercase suffix's loader on every host or any exploitation/security claim.

REA version and runtime

Main 71f680d7, manifest 6.8.0; macOS arm64, Node 24.22.1. Public compiled CLI and stock Node were run. MCP, Windows/Linux runtime and performance are not yet verified. The initial fixture script used case-only directory names on a case-insensitive filesystem and stopped with FileExistsError; it was corrected to separate numbered directories before collecting the final evidence.

Earliest failure stage

Source-derived: javascriptSourceParser.ts tests the explicit loader suffixes with case-insensitive regular expressions before recording the shared runtime context. This is separate from allowing a best-effort JavaScript grammar for inventoried text. Related #7883 adds observed package/preload context and retains the same case-folded suffix tests; #8960 changes lexical-this ownership, and #2986 changes ambient TypeScript namespaces. Their relevant production hunks were read; no foreign head was executed.

Originally created by @xu91102 on GitHub (Nov 5, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/8973 ### Before submitting - [x] I searched related open and closed issues and read the relevant production diffs. - [x] The reproducer uses only owned, benign local fixtures; private paths and credentials are omitted. ### Area JavaScript artifact analysis; parser-owned runtime context and module graph. ### Observed behavior On main `71f680d7c1aa7a45ba0325fe87b104744b0c105f`, the public `analyze-javascript-application` CLI reports a source-module row with `path: "main.MJS", module_format: "esm"` for a CommonJS-style file with no import/export declaration. The stock Node 24.22.1 executable successfully runs that same file as CommonJS and prints `42`. Lowercase `.mjs` with the same bytes is an explicit ES module and fails because `require` is unavailable; lowercase `.cjs` successfully prints `42` and REA correctly calls it CommonJS. Each test used a separate directory, including on this case-insensitive filesystem. ### Reproduction Create an otherwise empty directory with these three files: ```json {"type":"commonjs","main":"main.MJS"} ``` ```js // main.MJS const value = require('./dep.cjs'); console.log(value); // dep.cjs is a separate file containing: module.exports = 42; ``` Run stock `node /absolute/fixture/main.MJS`, then from the built main checkout run `node scripts/rea.mjs analyze-javascript-application /absolute/fixture --json`. Native execution of this owned fixture exits 0 and prints `42`; REA exits 0 but its source-module observation for `main.MJS` declares `esm`. Repeat in separate directories with `.mjs` and `.cjs` as controls. Three public CLI analyses and four native suffix controls were executed; source hashes stayed unchanged. No external application or target was executed by REA. ### Expected behavior A case-folded spelling of `.mjs` or `.cjs` must not by itself establish the exact suffix's loader mode or strictness. Preserve the exact path and inert syntax facts. When the surrounding observations do not establish a loader, retain unknown rather than declaring an ES module or CommonJS wrapper. This report does **not** ask REA to assume that every uppercase suffix runs as CommonJS, to introduce a fallback loader, or to execute the selected application. ### Impact and scope False positive module-format evidence on a valid benign Node entrypoint. Parser-owned context is also consumed by strictness and require-origin interpretation; the base incorrectly gives `main.MJS` the same explicit-ESM classification as `main.mjs`. The normalized requirement relation was unresolved on both, while the `.cjs` control retained CommonJS facts. This does not establish every uppercase suffix's loader on every host or any exploitation/security claim. ### REA version and runtime Main `71f680d7`, manifest 6.8.0; macOS arm64, Node 24.22.1. Public compiled CLI and stock Node were run. MCP, Windows/Linux runtime and performance are not yet verified. The initial fixture script used case-only directory names on a case-insensitive filesystem and stopped with FileExistsError; it was corrected to separate numbered directories before collecting the final evidence. ### Earliest failure stage Source-derived: `javascriptSourceParser.ts` tests the explicit loader suffixes with case-insensitive regular expressions before recording the shared runtime context. This is separate from allowing a best-effort JavaScript grammar for inventoried text. Related #7883 adds observed package/preload context and retains the same case-folded suffix tests; #8960 changes lexical-this ownership, and #2986 changes ambient TypeScript namespaces. Their relevant production hunks were read; no foreign head was executed.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#7870
No description provided.