fullshield 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  All notable changes to FullShield are documented here.
4
4
 
5
+ ## 1.6.0 — 2026-10-25
6
+
7
+ ### New/changed stable findings — may change CI results; use --update-baseline
8
+
9
+ - Phase 507: `SAST-SQLI-001` also fires for `node:sqlite` `DatabaseSync.exec` / `prepare` and `bun:sqlite` `exec` / `prepare` when request data is concatenated or interpolated. A literal with placeholders and a separate bound argument does not fire. `child_process.exec` stays a command finding.
10
+ - Phase 508: `SAST-CMDI-001` also fires for `Bun.spawn`, `Bun.spawnSync`, a Bun `$` template, and `Deno.Command` when the command or args are request data. A literal argv does not fire.
11
+ - Phase 509: `SAST-EVAL-001` also fires for `evaluate` on `mathjs`, `expr-eval`, or `vm2`, and for `vm2` `VM` / `NodeVM` when the code argument is not a string literal. An unrelated `evaluate()` does not fire. `mathjs.eval('1 + 2')` stays silent.
12
+
13
+ ### Experimental
14
+
15
+ - Phase 510: `DEPS-RSC-001` behind `FULLSHIELD_EXPERIMENTAL_RSC` (`scan --experimental-rsc`). Exact React Server Components versions 19.0.0, 19.1.0, 19.1.1, and 19.2.0 in a lockfile. A canary does not fire. Off by default.
16
+ - Phase 511: `CONFIG-COOLDOWN-001` behind `FULLSHIELD_EXPERIMENTAL_COOLDOWN` (`scan --experimental-cooldown`). A release-age gate shorter than three days, in that tool's unit. No cooldown file means no finding. Off by default.
17
+ - Phase 512: `SUPPLY-IMPLANT-001` behind `FULLSHIELD_EXPERIMENTAL_IMPORTIMPLANT` (`scan --experimental-import-implant`). `setup_bun.js` or `bun_environment.js`, including install scripts and `node_modules` up to 2000 manifests. Off by default.
18
+ - Phase 513: `DEPS-VERINFLATE-001` behind `FULLSHIELD_EXPERIMENTAL_VERINFLATE` (`scan --experimental-ver-inflate`). Lockfile major 9999+ or patch 999 or 9999. Off by default.
19
+ - Phase 514: `AGENT-UNICODE-001`, `AGENT-INJECT-001`, `AGENT-EXFIL-001`, and `AGENT-SHELL-001` behind `FULLSHIELD_EXPERIMENTAL_AGENTRULES` (`scan --experimental-agent-rules`). Named agent instruction files only. Off by default.
20
+ - Phase 515: `SAST-AGENTSPAWN-001` behind `FULLSHIELD_EXPERIMENTAL_AGENTSPAWN` (`scan --experimental-agent-spawn`). A coding agent launched with a permission bypass in the same call. Off by default.
21
+ - Phase 516: `MCP-006`, `MCP-007`, and `MCP-008` behind `FULLSHIELD_EXPERIMENTAL_MCPPOISON` (`scan --experimental-mcp-poison`). Secret elicitation, a shell or instruction default, and a duplicated tool name. `MCP-001`–`MCP-005` are unchanged. Off by default.
22
+ - Phase 517: `CONFIG-VITEFS-001` behind `FULLSHIELD_EXPERIMENTAL_VITEFS` (`scan --experimental-vite-fs`). `server.fs.strict: false` or a filesystem root in `server.fs.allow`. Off by default.
23
+ - Phase 518: `SAST-HOST-001` behind `FULLSHIELD_EXPERIMENTAL_HOSTPOISON` (`scan --experimental-host-poison`). Host or X-Forwarded-Host copied into an absolute redirect or mail URL. Off by default.
24
+ - Phase 519: `SAST-MARKUP-001` behind `FULLSHIELD_EXPERIMENTAL_MARKUP` (`scan --experimental-markup`). markdown-it `html: true` or marked, rendering request data. Off by default.
25
+ - Phase 520: `SAST-TRUSTHOST-001` behind `FULLSHIELD_EXPERIMENTAL_TRUSTHOST` (`scan --experimental-trust-host`). Auth.js `trustHost: true`. Off by default.
26
+
27
+ ## 1.5.0 — 2026-10-24
28
+
29
+ ### New/changed stable findings — may change CI results; use --update-baseline
30
+
31
+ - Phase 503: one object field and one nested function are part of the default scan. The nested function carries request data, not `process.argv`. A field counts on a read after the assignment. `FULLSHIELD_EXPERIMENTAL_FLOW2` and `scan --experimental-flow2` stay accepted and do not turn this off. Against 1.4.0, NodeGoat gains `SAST-XSS-001` at `app/views/allocations.html:15` and `app/views/login.html:110`. vulnerable-app stays 38, clean-app stays 0, and juice-shop, dvna, goof, and vulnerable-node stay the same.
32
+ - Phase 504: ORM raw queries, `` exec(`…${x}`) ``, `spawn` of `sh -c`, execa `shell: true`, and zx `$.raw` are part of the default scan. `FULLSHIELD_EXPERIMENTAL_SAST_GAPS` and `scan --experimental-sast-gaps` stay accepted and do not turn this off. No new rule id.
33
+
34
+ ### Experimental
35
+
36
+ - Phase 505: `SAST-LDAP-001` behind `FULLSHIELD_EXPERIMENTAL_LDAP` (`scan --experimental-ldap`). A string-literal filter does not fire. Off by default.
37
+ - Phase 506: `CONFIG-CORS-002` behind `FULLSHIELD_EXPERIMENTAL_CORSREFLECT` (`scan --experimental-cors-reflect`). A fixed origin does not fire. `origin: '*'` with credentials stays `CONFIG-CORS-001`. Off by default.
38
+
5
39
  ## 1.4.0 — 2026-10-24
6
40
 
7
41
  ### Experimental
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # FullShield
2
2
 
3
- **v1.4.0.** One install for Node.js/TypeScript backends: detect → classify → report → notify → fix → gate (CI `--fail-on` + runtime monitor). It does not stop attacks by itself.
3
+ **v1.6.0.** One install for Node.js/TypeScript backends: detect → classify → report → notify → fix → gate (CI `--fail-on` + runtime monitor). It does not stop attacks by itself.
4
4
 
5
5
  **Headline: dependency reachability.** A lockfile CVE is not the same as an unused package. FullShield classifies each OSV hit as `reachable` (imported and called), `imported-not-called` (−1), `reachable-via-dependency` (lockfile path from an imported direct dep — **severity kept**, path shown, e.g. `express > body-parser > qs`), `not-imported` (−2, only when no such path exists), or `reachability-unknown` (severity kept) when the lockfile format has no parsed dependency edges. DevDependency-only vulns are `info` with a `dev-only` note unless production sources import the package. Pair it with `fullshield sbom --format cyclonedx`.
6
6
 
@@ -10,7 +10,7 @@ npx fullshield scan --json --fail-on high
10
10
  npx fullshield scan --sarif fullshield.sarif
11
11
  ```
12
12
 
13
- 1.4.0 is the version of this tree. The stable contract is [docs/stability.md](docs/stability.md). The 1.0.1 release moved values that only experimental flags produce out of Stable. Experimental flags stay off unless you set them. Do not treat a scan as a penetration test. Reviewed recall for untouched apps is not published. The stored Next.js cold scan is 71.7 seconds, above the 60-second target.
13
+ 1.6.0 is the version of this tree. The stable contract is [docs/stability.md](docs/stability.md). The 1.0.1 release moved values that only experimental flags produce out of Stable. Experimental flags stay off unless you set them. Do not treat a scan as a penetration test. Reviewed recall for untouched apps is not published. The stored Next.js cold scan is 71.7 seconds, above the 60-second target.
14
14
 
15
15
  **Supported runtime is Node.js >= 22.13.** `package.json` `engines` and `doctor` enforce that floor. `node:sqlite` runs without `--experimental-sqlite` from 22.13.0 (the module is still experimental and is loaded only by history/confirm, not by `--import` register).
16
16
 
@@ -85,7 +85,7 @@ Experimental RASP structure-change scoring on the vendored PayloadsAllTheThings
85
85
 
86
86
  Path 51/51 and SSRF 39/39 on the same corpus. Benign corpus stays 0 blocked. Prefer `mode: 'monitor'`.
87
87
 
88
- These fixtures are self-authored. Numeric SQL (`WHERE id = ` + input), ORM raw-query APIs (Prisma/Sequelize/Knex/TypeORM/Drizzle/`$where`), and template-literal shell (`exec(\`…${x}\`)`, `spawn('sh', ['-c', …])`, execa `shell: true`, zx `$.raw`) are covered in the attack corpus. Extra SAST sinks for those ORM / `sh -c` / execa / zx shapes stay behind `FULLSHIELD_EXPERIMENTAL_SAST_GAPS=1` (or `scan --experimental-sast-gaps`) so default `scan` behavior does not change. Mongo `$where` strings are **stable** SAST (Juice Shop track-order / reviews).
88
+ These fixtures are self-authored. Numeric SQL (`WHERE id = ` + input), ORM raw-query APIs (Prisma/Sequelize/Knex/TypeORM/Drizzle/`$where`), and template-literal shell (`exec(\`…${x}\`)`, `spawn('sh', ['-c', …])`, execa `shell: true`, zx `$.raw`) are covered in the attack corpus. Those ORM and shell sinks are part of the default scan. `FULLSHIELD_EXPERIMENTAL_SAST_GAPS` and `scan --experimental-sast-gaps` stay accepted and do not turn them off. Mongo `$where` strings are **stable** SAST (Juice Shop track-order / reviews).
89
89
 
90
90
  In-scope public-bench patterns we still do not claim (one line each):
91
91
 
@@ -226,9 +226,22 @@ app.use(shieldGuard({ mode: 'monitor', authRoutes: ['/login'] }));
226
226
  | `agent` | **Experimental** remediation agent (`FULLSHIELD_EXPERIMENTAL_AGENT=1`). Mock/localhost GitHub API + local git remote only — never a real network. Never merges, never pushes to `main`/`master`. `--max-prs` (default 3). |
227
227
  | `scan --changed` / `--since` | **Experimental** incremental scan (`FULLSHIELD_EXPERIMENTAL_PLATFORM=1`). |
228
228
  | `scan --diff` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_DIFFSCAN=1` or `--experimental-diffscan`). Scans git-changed JS/TS files, the files they import by a relative literal, and the files that import them the same way. One hop. A sink in an unchanged importer still reports when the changed file returns the request value. A git failure is `FS-E018` and does not scan the rest of the tree. Off, or `scan` without `--diff`, matches today's scan. |
229
- | `scan --experimental-flow2` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_FLOW2=1`). Existing injection rules also fire when request data reaches the sink through one object field (`obj.a`) or one nested function that closes over the tainted name. `obj.b` stays clean. `JSON.parse` does not clear taint. Handlebars `{{ }}`, `res.json`, and a `url.includes` allowlist helper stay unflagged. |
229
+ | `scan --experimental-flow2` | **Stable.** One object field (`obj.a`) and one nested function are part of the default scan. `FULLSHIELD_EXPERIMENTAL_FLOW2` and this flag stay accepted and do not turn that off. `obj.b` stays clean. `JSON.parse` does not clear taint. Handlebars `{{ }}`, `res.json`, and a `url.includes` allowlist helper stay unflagged. |
230
230
  | `dev` | **Experimental** save loop (`FULLSHIELD_EXPERIMENTAL_DEV=1`). Watches the project and prints only new and resolved findings. |
231
- | `scan --experimental-sast-gaps` | **Experimental** extra SAST sinks: ORM raw SQL, mongoose `$where`, `spawn('sh', ['-c'])`, execa `shell: true`, zx `$.raw` (`FULLSHIELD_EXPERIMENTAL_SAST_GAPS=1`). |
231
+ | `scan --experimental-sast-gaps` | **Stable.** ORM raw SQL, `spawn('sh', ['-c'])`, execa `shell: true`, and zx `$.raw` are part of the default scan. `FULLSHIELD_EXPERIMENTAL_SAST_GAPS` and this flag stay accepted and do not turn that off. |
232
+ | `scan --experimental-ldap` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_LDAP=1`). `SAST-LDAP-001`: `search`, `compare`, `modify`, or `bind` on an LDAP client when the filter or DN is request data. A string-literal filter does not fire. Off by default. |
233
+ | `scan --experimental-cors-reflect` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_CORSREFLECT=1`). `CONFIG-CORS-002`: `Access-Control-Allow-Origin` is the request `Origin` and credentials are allowed on that response. A fixed origin does not fire. `origin: '*'` with credentials stays `CONFIG-CORS-001`. Off by default. |
234
+ | `scan --experimental-rsc` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_RSC=1`). `DEPS-RSC-001`: a lockfile resolves `react-server-dom-webpack`, `react-server-dom-parcel`, or `react-server-dom-turbopack` to 19.0.0, 19.1.0, 19.1.1, or 19.2.0. A canary or any other version does not fire. No lockfile means no finding. Off by default. |
235
+ | `scan --experimental-cooldown` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_COOLDOWN=1`). `CONFIG-COOLDOWN-001`: `.npmrc`, `pnpm-workspace.yaml`, `.yarnrc.yml`, or `bunfig.toml` is present and the release-age gate is missing or shorter than three days. npm is days, pnpm is minutes, yarn is a duration, bun is seconds. A project with none of those four files does not fire. Off by default. |
236
+ | `scan --experimental-import-implant` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_IMPORTIMPLANT=1`). `SUPPLY-IMPLANT-001`: `setup_bun.js` or `bun_environment.js` is in the scan, named by a preinstall/install/postinstall script, or present under `node_modules` (capped at 2000 manifests, no symlinks). Off by default. |
237
+ | `scan --experimental-ver-inflate` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_VERINFLATE=1`). `DEPS-VERINFLATE-001`: a lockfile version whose major is 9999 or greater, or whose patch is 999 or 9999. `1.2.3` does not fire. Off by default. |
238
+ | `scan --experimental-agent-rules` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_AGENTRULES=1`). `AGENT-UNICODE-001`, `AGENT-INJECT-001`, `AGENT-EXFIL-001`, and `AGENT-SHELL-001` on `AGENTS.md`, `CLAUDE.md`, `.github/copilot-instructions.md`, `.cursor/rules/**`, `.windsurf/rules/**`, and `SKILL.md` under `.cursor/`, `.claude/`, or `.agents/`. A short guideline with none of those markers does not fire. Off by default. |
239
+ | `scan --experimental-agent-spawn` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_AGENTSPAWN=1`). `SAST-AGENTSPAWN-001`: `exec`, `execSync`, `spawn`, `spawnSync`, `Bun.spawn`, `Bun.spawnSync`, or `new Deno.Command` launches `claude`, `codex`, or `gemini` with `--dangerously-skip-permissions`, `--permission-mode bypassPermissions`, or `--yolo` in the same call. The program without the flag does not fire. Off by default. |
240
+ | `scan --experimental-mcp-poison` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_MCPPOISON=1`). JSON that contains `mcpServers`. `MCP-006` asks for a password, token, secret, or API key. `MCP-007` puts `ignore previous` or a shell marker in a schema default. `MCP-008` repeats one tool name on two servers in one file. One server with a literal description does not fire. `MCP-001`–`MCP-005` stay on `FULLSHIELD_EXPERIMENTAL_MCPCFG`. Off by default. |
241
+ | `scan --experimental-vite-fs` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_VITEFS=1`). `CONFIG-VITEFS-001`: a Vite config sets `server.fs.strict` to false or `server.fs.allow` to `/` or a drive root. Omitted `server.fs` does not fire. Off by default. |
242
+ | `scan --experimental-host-poison` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_HOSTPOISON=1`). `SAST-HOST-001`: `Host` or `X-Forwarded-Host` is copied into an absolute URL passed to `redirect`, `location`, `sendMail`, or a `Location` header. A fixed host does not fire. Off by default. |
243
+ | `scan --experimental-markup` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_MARKUP=1`). `SAST-MARKUP-001`: `markdown-it` is constructed with `html: true` and `render` is called with request data, or `marked` / `marked.parse` is called with request data. The file must import that package. Literal markdown does not fire. Off by default. |
244
+ | `scan --experimental-trust-host` | **Experimental** (`FULLSHIELD_EXPERIMENTAL_TRUSTHOST=1`). `SAST-TRUSTHOST-001`: a file that mentions `next-auth`, `@auth/`, or `NextAuth` sets `trustHost: true`. `false` or omitted does not fire. Off by default. |
232
245
  | `scan --experimental-frameworks` | **Experimental** Next.js / NestJS / Hono / Koa taint sources and AUTH (`FULLSHIELD_EXPERIMENTAL_FRAMEWORKS=1`). Default `scan` is unchanged. Runtime adapters: `fullshield/runtime/koa`, `fullshield/runtime/hono` (optional peers). |
233
246
  | `scan --experimental-classes` | **Experimental** extra vuln classes: ReDoS, deser, XXE, upload, cookies, CSRF, mass assignment, timing compare, hash cost, GraphQL, trust-proxy (`FULLSHIELD_EXPERIMENTAL_CLASSES=1`). Default `scan` is unchanged. |
234
247
  | `scan` crypto v2 | **Experimental** (`FULLSHIELD_EXPERIMENTAL_CRYPTO2=1`). `SAST-CIPHER-001`, `SAST-CIPHER-002`, `SAST-RSA-001`, and `SAST-JWT-002`: ECB and deprecated ciphers, literal IVs, literal symmetric keys, short RSA or secp192 keys, and JWTs with no expiry or a short HMAC secret. Off by default. |