The npm-audit wave

Six advisories blocked three dependabot PRs and the nightly run on main. All six were transitive. None needed a version bump, an override, or an allowlist entry.

The two commands, side by side

$ npm install --no-audit --no-fund
added 99 packages in 967ms

$ npm audit
  1124006 [moderate] @hono/node-server
  1130720 [high]     fast-uri
  1130722 [high]     ip-address
  1130723 [moderate] ip-address
  1130724 [moderate] ip-address
  1130733 [moderate] hono          <-- all six still here

resolved tree:
  @modelcontextprotocol/sdk@1.30.0   <-- SDK DID move (was 1.29.0)
    @hono/node-server@1.19.14        <-- but this stayed
    hono@4.12.31                     <-- and this
    ajv@8.20.0 -> fast-uri@3.1.4     <-- and this
    express-rate-limit@8.5.1 -> ip-address@10.2.0
Why nothing moved

npm install only adds and removes. Any transitive that still satisfies its declared range is left exactly where it is. The SDK itself upgraded 1.29.0 to 1.30.0 because the manifest demanded ^1.30.0 and the lockfile was stale, but every dependency underneath it already satisfied its own range, so npm had no reason to touch them.

$ npm update --no-audit --no-fund
changed 14 packages in 3s      (src/mcp-server)
changed 23 packages in 8s      (src/hooks)

$ npm audit
  (no findings)

resolved tree:
  @modelcontextprotocol/sdk@1.30.0
    @hono/node-server@2.1.0          <-- range was ^1.19.9 || ^2.0.5
    hono@4.13.0                      <-- range was ^4.11.4
    ajv@8.20.0 -> fast-uri@3.1.5     <-- range was ^3.0.1
    express-rate-limit@8.6.1 -> ip-address@10.4.0

$ bash tests/security/test-npm-audit.sh
  Total: 4  |  Passed: 4  |  Failed: 0
Why everything moved

npm update walks each declared range to its newest satisfying version. Every fix already lived inside a range the manifests permitted, so nothing semver-major was involved and no manifest was edited. The fixes had been sitting there, unreachable only because the lockfile pinned older members of the same ranges.

The six advisories

IDSevPackagebeforeafterStatus
1130733moderatehono4.12.314.13.0cleared
1130720highfast-uri3.1.43.1.5cleared
1130722highip-address10.2.010.4.0cleared
1130723moderateip-address10.2.010.4.0cleared
1130724moderateip-address10.2.010.4.0cleared
1124006moderate@hono/node-server1.19.142.1.0cleared
1130709moderatepostcss8.5.188.5.25cleared

Verification actually run

CheckResult
tests/security/test-npm-audit.sh4/4 workspaces, 0 findings, exit 0
src/hooks buildclean, 11 bundles, 670 KB
src/hooks vitest304 files, 7501 passed, 2 skipped
files changed2 lockfiles only, no manifest edits

Two things this does NOT do

The allowlist entry for 1124006 is now stale, but untouched here

Its recorded reason says "no upstream fix yet", which stopped being true the moment @hono/node-server resolved to 2.1.0. Removing it is correct but is a separate concern from the lockfile, and the entry is harmless while it sits unused (it expires 2026-09-01 on its own).

The Dockerfile CodeQL alerts are deliberately left alone

Six of the nine open code-scanning alerts point at three unpinned FROM node:24-alpine lines, counted twice because plugins/ is generated from src/. The file already carries a written rationale for tag-pinning over digest-pinning: a digest freezes the base layer so it can never pick up an upstream security patch. Silently "fixing" that would overturn a documented decision in a skill template. It needs a decision, not a patch.

The gate gap this PR walked into

A lockfile-only security fix is required to ship an interactive playground

The PR Playground gate exempts bot branches and an inert path list (README, CHANGELOG, .github/, vercel.json, *.toml). package-lock.json is not on it, so this PR (two lockfiles, zero user-facing surface) had to author one. That is the same shape as the failure the gate's own comment describes for #3193. Worth a follow-up, not worth gaming the branch prefix to dodge.