Rules / GRN-C011

diffinfoimplemented

GRN-C011 new-js-capability

Default severity info
Kind diff rule: fires only when the trusted version had the property and the new version lost it, or the new version gained a risky property the trusted version lacked.
Status Implemented in 0.2 (npm)

What it checks

Garnet reads the JavaScript an npm package loads and lists what it reaches for:

The files are the ones a program loads: those package.json names in main (index.js when it names none), module, browser, bin and exports, and every file they load through a relative require or import, as deep as that goes. Files nothing loads, such as build scripts and tests, aren't read.

The rule compares the new version with the trusted one by name, across the whole package, and reports each module or global the trusted version didn't use. A call that moved from one file to another is not new. The evidence shows one place each name is used, and says whether that code runs when the file loads or sits in a function that waits to be called.

Why it matters

Code added to a module runs when the package is required, by the app, its tests or a build tool. npm install scripts (GRN-C002) don't cover it. chalk 5.6.1 and debug 4.4.2 (September 2025) changed only index.js, adding an obfuscated line that rewrote browser network calls. Garnet reports both through the missing git tag (GRN-T004), and the files are gone from the registry, so the replay can't read them; this rule reads the file itself when it is there.

Example finding

Illustrative; not from a real release.

examplelib 2.6.1 → 2.6.2: PASS
  info  GRN-C011 new-js-capability: 2.6.2's JavaScript uses child_process, which 2.6.1's didn't
           - lib/telemetry.js:3 loads child_process (when the file loads)

An info finding doesn't change the verdict; it puts the line in front of the reviewer.

How to resolve it

  1. Open the line the evidence names.
  2. Find the commit that added it in the project's repository. A package that never reached the network or started processes rarely starts in a patch release, and obfuscated code has no ordinary place in a published library.
  3. If the repository explains it, merge. If the repository doesn't have the code, or the code is obfuscated, don't merge, and tell the maintainers.

Allowlisting

The rule reports at info, so it never fails a check on its own. To make it a warning for every package:

[garnet.rules]
"GRN-C011" = "warn"   # "off" | "info" | "warn" | "block"

After raising it, ignore it for a package and version range you've reviewed. Every ignore needs a reason and an expiry date; after until it stops applying and the report notes that it expired.

[[garnet.ignore]]
package = "examplelib"
ecosystem = "npm"
versions = "==2.6.2"
rules = ["GRN-C011"]
reason = "2.6.2 adds a CLI that runs git, see the commit that added lib/telemetry.js"
until = "2027-06-30"

Suppressed findings still appear in JSON and SARIF output, marked with the ignore that matched. How to write one is in the policy guide; the format is in SPEC §7.

What it doesn't check

See also