Skip to content

fix(supply-chain): detect indirect CommonJS loaders in packed bundles #289

Description

@seonghobae

Current canonical ownership

Draft PR #290 / branch fix/indirect-commonjs-authority-289 is the sole active Inkspan writer for scripts/javascript-runtime-authority.mjs and its dedicated regressions. Protected shipped truth remains exact main@3b38ead2d00f44eb578d0689087b9293b3dabe1e; current exact Draft head is 097ffbd230aaeaf9ceec978e66bab723b119f23d. Active-PR source/tests and live GitHub state are higher-authority than this issue snapshot; refetch exact head/base, reviews/threads, governance, and all applicable workflows immediately before any lifecycle action.

The active lane strengthens only deterministic packed-artifact/release evidence. Inkspan's production Markdown adapter remains standalone and network-free; no runtime loader, network, credential, persistence, tenancy, model, deployment, or durable-audit authority is added.

Required runtime-authority contract

The AST verifier must fail closed on statically recognizable executable module authority while remaining syntax-bounded and non-evaluating. The current active lane covers static imports/re-exports, dynamic import(...), direct/comma-indirected CommonJS require, module.require, require.main.require, require.resolve, .call, .apply, Reflect.apply, retained .bind capabilities and composed .bind invocation, constructor invocation through new, Reflect.construct when the target is already recognized CommonJS authority, and Node built-in loads through exact ambient process.getBuiltinModule(...) / globalThis.process.getBuiltinModule(...) expressions.

For those exact ambient Node built-in loader expressions, current branch behavior includes direct invocation, syntax-only comma indirection whose right operand remains one of those exact ambient loader expressions, exact-receiver .call(...) and .apply(...), Reflect.apply(...), retained .bind(...) capabilities, and immediately invoked bound capabilities. Literal module specifiers remain actionable evidence. Computed/missing specifiers remain unknown rather than guessed. Static string-literal element access may identify an already-supported member spelling; dynamic computed member names, arbitrary aliases/receivers, ordinary object methods, comments, strings, and template text remain outside the syntax-bounded model. The verifier never executes artifact code or performs whole-program alias evaluation.

module.main.require(...) is intentionally outside the recognized CommonJS authority model because Node's documented module object does not define module.main; require.main.require(...) remains recognized.

Latest test-first extension and false-green correction

  • predecessor exact source head 5750e638aa96e5b8a51312967dc87ec506fddd81 recognized direct/call/apply/bind ambient Node built-in authority but did not recognize (0, process.getBuiltinModule)('node:fs');
  • runtime/AST reproduction established the defect: the supported Node runtime executes (0, process.getBuiltinModule)('node:path') as real built-in loading authority, while the predecessor predicate saw a comma BinaryExpression callee and returned false;
  • test-only a0eaac01e392ea8a3e4dec987b330c141cfc3e80 added the regression as src/javascriptRuntimeAuthorityNodeBuiltin.test.mjs. Hosted CI 32304348109 checked out that exact SHA, but Vitest did not discover the .test.mjs file. Its apparently green test step was therefore vacuous evidence for this regression and is explicitly non-passing;
  • narrow source repair 55cf0f0e1b4829d6cc7d845f2bdd2207892cd0f9 extends only the exact ambient Node built-in predicate through syntax-only comma expressions, matching the existing CommonJS treatment without alias evaluation or arbitrary receiver inference;
  • doctoring convergence c7436b447f80a952cf330b925f0ff560bb8dd4d4 records the same bounded contract;
  • discovery repair 7d7926e4e7149c6cb2bd40b785ced27e4a360e1b adds repository-standard src/javascriptRuntimeAuthorityNodeBuiltin.test.ts, invokes the scanner through a child Node process like adjacent runtime-authority tests, and includes real runtime proof plus ordinary-object negative controls; and
  • current exact head 097ffbd230aaeaf9ceec978e66bab723b119f23d removes the undiscovered .test.mjs copy so later evidence cannot accidentally rely on a dead test path.

Exact-current-head evidence

Fresh refetch for unchanged exact head 097ffbd230aaeaf9ceec978e66bab723b119f23d now supersedes the earlier queued Security/SAST snapshot:

  • CI 32304869702: completed / success;
  • build-and-test 96235551581: completed / success after exact-head checkout; its Vitest output actually discovers and passes src/javascriptRuntimeAuthorityNodeBuiltin.test.ts, so the prior test-discovery false-green defect is repaired;
  • Cross-engine Clipboard / Playwright 1.62.0 96235551334: completed / success;
  • Office Python 3.11 96235551568, 3.12 96235551606, 3.13 96235551720, and 3.14 96235551626: completed / success with dependency consistency, 100% docstring/branch-coverage, wheel, and packaged schema/license gates;
  • Security Scan 32304869555: completed / success;
  • SAST Semgrep 32304869676: completed / success;
  • formal submitted reviews: one historical Cursor COMMENTED review, not approval;
  • its sole inline thread is resolved and outdated;
  • qualifying approving reviews: 0;
  • unresolved inline review threads: 0.

All three repository exact-current-head workflow generations are terminal success. That technical success still does not substitute for qualifying independent approval or separately applicable central/live-governance gates. Pending, queued, skipped, cancelled, absent, neutral, failed, stale, predecessor, vacuous, status-only, or model-only evidence remains non-passing.

Test-first / assurance acceptance

  • Preserve positive and negative controls for every supported syntax family.
  • Preserve ordinary-object require / resolve / getBuiltinModule negative boundaries.
  • Invalid emitted JavaScript fails closed.
  • Any extension to recognized syntax must be test-first and preserve source-order diagnostics, frozen results, and the no-execution/no-alias-evaluation invariant.
  • Release verification must scan the exact packed artifact produced from the exact candidate head.
  • Maintain applicable exact-head CI, Security Scan, SAST, packed-consumer, browser/Office, coverage, package, SBOM/provenance, and review evidence under then-live governance.

Integration boundary

Keep #290 Draft/unmerged while #118 owns the protected v0.6.0 publication/provenance boundary and until qualifying independent approval plus every then-live gate is satisfied. Do not reopen duplicate #358, create another scanner writer, self-approve, transfer predecessor evidence, force-push, destructively rebase, weaken gates, move protected main, or fabricate release identity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiAPI, protocol, event, or external contractarea: authAuthentication, authorization, identity, or tenant isolationarea: ci-cdCI, GitHub Actions, checks, release, or supply chainarea: securitySecurity boundary, hardening, or vulnerability preventionpriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: bugDefect or incorrect behavior

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions