lang/nodejs

Free catalog · v0.0.23

Reviews JavaScript projects for security hazards, lifecycle cleanup leaks, and configured project-linter diagnostics.

Node.js adversary

Reviews JavaScript projects for security hazards, lifecycle cleanup leaks, and configured project-linter diagnostics.

Goals

The adversary is designed to produce a small number of high-confidence, actionable findings grounded in concrete repository evidence. Its review should be deterministic where possible, explicit about impact, and quiet when the available evidence does not justify a finding.

Scope

It evaluates Node.js source for command execution, dynamic evaluation, TLS, path confinement, weak randomness, VM isolation, and shared listener cleanup.

The complete detector or review inventory is maintained in CHECKS.md.

Boundaries

It owns framework- or language-specific review in this domain. Infrastructure, CI, dependency-manager, and unrelated application concerns remain with specialist adversaries.

Project lint

lang/nodejs owns the package-lint phase for JavaScript, JSX, TypeScript, and TSX projects, including React and Next.js. Framework adversaries do not duplicate it. Node.js detection includes these source extensions, package manifests, and supported linter configuration. The CLI's existing composition deduplicates this adversary when it is selected more than once.

For each discovered package.json with a nonempty scripts.lint, the phase recognizes these project-installed tools:

ToolSupported commandsStructured output
ESLinteslint ...Built-in JSON formatter
Biomebiome lint ..., biome check ..., biome ci ...GitLab Code Quality; inject --max-diagnostics=none unless explicitly set
Oxlintoxlint ...JSON formatter

Direct commands work regardless of whether the project's package manager is npm, Yarn, pnpm, or Bun. npm exec, yarn exec, pnpm exec, and bun exec wrappers (with an optional --) resolve to the same local tool without lifecycle hooks or downloads. npx, bunx, and bun x (optionally --no-install) likewise resolve only installed local tool packages. Package/version requests, installer options, and --bun runtime switches remain unsupported. Exact same-package npm run NAME, pnpm run NAME, yarn run NAME, and bun run NAME aliases are followed with cycle detection and an eight-alias depth bound; argument forwarding and workspace selection are not inferred. All original scripts remain recorded in check observations. Quoted paths, supported config and ignore options, rule selectors, severity overrides, and tool-specific check options retain their order. Unknown flags are skipped rather than guessed. Output-format options are replaced with the adapter's built-in structured reporter; Biome colors are disabled for CI. The executable is resolved from installed dependencies inside the scanned repository (including ancestor workspace installs); nothing is downloaded or installed.

Biome receives --max-diagnostics=none by default so its implicit console limit of 20 is not carried into the invocation. An explicit --max-diagnostics VALUE or --max-diagnostics=VALUE is preserved without injecting a duplicate. Reporter behavior varies: Biome 2.5.15's GitLab reporter emits all diagnostics even with an explicit finite limit. The SDK's separate final-finding ranking/count policy still applies; collecting all tool diagnostics does not mean every diagnostic becomes a presented finding. Time and output limits still bound execution.

Each package runs at most once per review. Root workspace delegation scripts are unsupported and skipped; supported scripts in child packages run independently. Identical diagnostics from overlapping runs of the same tool are deduplicated. Full scans report source diagnostics. Source-only change reviews intersect existing changed files with the script's directory, file, or glob targets and invoke the tool on that intersection, retaining config and rule options. Empty intersections are explicit skips. Config/dependency or other non-source edits, ambiguous targets, and ESLint's version-dependent implicit target retain the original script invocation. Check observations record executionScope as changed-files or full-script. Findings still retain only changed files and lines. Errors are medium severity and warnings are low severity. Biome check and ci also report source-located formatting/assist diagnostics according to the project's settings; file-level formatting diagnostics use the reporter's line 1 anchor. Check observations retain the tool and exit status, including nonzero exits without eligible source diagnostics. Skipped and unavailable checks never fabricate code findings.

Mixed-tool command chains (including prettier --check . && eslint .), shell operators, environment assignments, workspace/Turbo delegation, arbitrary wrappers, next lint, other linters, and unknown options are unsupported. The runner does not partially execute a chain and then call the overall script a success. Prettier plugins/configuration loaded by ESLint remain supported; the standalone Prettier CLI is not a tool adapter. Benign ESLint flags include --no-color, --report-unused-disable-directives-severity, legacy --rulesdir and --resolve-plugins-relative-to, and compact -fjson formatter syntax. The installed ESLint version must support the original flags. Fixing, caching, suppression writes, initialization, file output, daemon use, and watch options are rejected. Yarn Plug'n'Play installs without a resolvable repository tool package are skipped. PnP archive/cache resolution requires a loader and a different dependency boundary; missing tool resolution in a PnP project records pnp-unsupported. Bun wrappers change command discovery, not runtime selection: all installed CLI wrappers run under the adversary's Node 22 runtime for consistent behavior. No prelint or postlint hooks are invoked.

Adapters validate each tool's output schema. Unsupported installed versions or malformed output become unavailable checks. Biome and Oxlint fixtures include captured output from Biome 2.5.15 and Oxlint 1.86.0, with volatile Oxlint timing and thread metadata removed. See the Biome CLI and Oxlint output formats for the reporter contracts.

Execution boundary

Unlike bundled actionlint, this phase runs repository-provided tool code, configuration, and plugins. It uses a direct argument array, a five-minute timeout, a 64 MiB output limit, and a minimal environment without inherited credentials. These limits are not a sandbox: config and plugins can execute arbitrary code, write files, or access the network. The production host must supply filesystem, process, and network isolation for untrusted repositories. The manifest's advisory permissions do not enforce that isolation. Missing dependencies, configuration failures, invalid output, and exceeded limits are reported as skipped or unavailable check observations. Timeouts and output-limit failures retain distinct reasons and limit values, rather than an undifferentiated failure. The low-level runner accepts per-invocation limit overrides for integrations.

SDK source coverage

This release uses SDK 0.1.43. This reviewer uses deterministic prepared evidence rather than repository-tool model retrieval, so it has no model coverage result to reinterpret. Existing evidence gates and deterministic findings are preserved.

SDK 0.1.43

This release rebuilds with SDK 0.1.43. SDK PR #73 adds a tested neutral fallback to formatOpinionAsync when concern wording validation is exhausted, preserving completed findings and the ship decision. Reviewers that do not call this API retain their existing opinion behavior. Provider and transport failures remain errors. Domain rules and evidence requirements are unchanged.

More from the registry