Skip to content

Commit d329f1f

Browse files
committed
docs(fix-vulnerability skill): require Node 8-25 testing floor
Adds a "Multi-Node-version testing" subsection to step 7 plus a matching row in the step-11 checklist. The fix must pass `npm test` on every Node major from 8 through the latest release; older Nodes catch syntax/API choices the latest V8 silently accepts. Documents guarding rules for fix code (no post-Node-8 syntax in lib/*.js; feature-probe gated host APIs) and test code (use it.cond for feature-gated tests; the .js file itself must parse on Node 8). Provides an nvm sweep command.
1 parent 64f3547 commit d329f1f

1 file changed

Lines changed: 23 additions & 0 deletions

File tree

  • .claude/skills/fix-vulnerability

.claude/skills/fix-vulnerability/SKILL.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,28 @@ Apply the fix with minimal, self-contained diff. Comment every security-critical
162162
- **Adversarial probing**: write a small harness that enumerates `Object.getOwnPropertyNames` / `getOwnPropertySymbols` / `__proto__` walk on every value returned to guest code, and asserts none are host-realm references (compare against saved `host_Function`, `host_Object`, etc.).
163163
- **Existing suite**: `npm test` must pass. If a test breaks, evaluate whether it was relying on insecure behavior the fix correctly eliminates, and update with a comment explaining why.
164164

165+
#### Multi-Node-version testing
166+
167+
The fix must pass `npm test` on **every Node major from 8 through the latest release**. Older Nodes lack `SuppressedError`, `using` declarations, `WebAssembly.JSTag`, `Promise.try`, `Array.fromAsync`, top-level await, private class fields, optional chaining (pre-14), nullish coalescing (pre-14), etc. — a fix that uses any of these without guards crashes the load on older runtimes and silently breaks every embedder still on an LTS-extended tree.
168+
169+
Run the full sweep before considering the fix done. With `nvm`:
170+
171+
```bash
172+
for v in 8 10 12 14 16 18 20 22 24 25; do
173+
nvm use $v && npm test 2>&1 | tail -3
174+
done
175+
```
176+
177+
If any version fails, fix it before push. Do not assume "passes on the latest Node" means "passes everywhere" — older Nodes catch syntax/API choices that the latest V8 silently accepts.
178+
179+
**Guarding rules for the fix code** (`lib/*.js`):
180+
181+
- New syntax must be a strict subset of what Node 8's V8 understands. No `?.`, no `??`, no `Promise.try`, no top-level `await`, no `using`, no private class fields, no static class blocks. The transformer's Acorn parser is pinned at `ecmaVersion: 2022` for sandbox code; the bridge itself can be more conservative since it loads on the embedder's Node.
182+
- Feature-gated host APIs (`SuppressedError`, `AggregateError`, `WebAssembly.JSTag`, `Reflect`, `globalThis`, `BigInt`, `Promise.allSettled`, `Promise.any`) must be probed at module load (`typeof SuppressedError === 'function'`) and skipped, not blindly referenced. The codebase already does this — match the existing pattern at the install site.
183+
- Test code in `test/ghsa/<GHSA-id>/repro.js` may use newer syntax inside the sandbox-side string template, but the JS file itself must parse on Node 8. Use `it.cond(name, condition, fn)` for tests that require a newer feature (`HAS_WASM_STREAMING`, `HAS_USING`, `HAS_SUPPRESSED_ERROR`, etc.). See `test/ghsa/GHSA-v6mx-mf47-r5wg/repro.js` for the canonical shape.
184+
185+
If a Node version reveals a failure that was not in the original PoC, that is a **separate finding** — either widen the fix to cover it, or open a follow-up advisory if it surfaces a new escape class.
186+
165187
**Iterate with `/hacker`**: run the red-team skill against the patched tree. A bypass means the structural invariant is wrong, not that you need a tighter patch on the same line. Loop steps 5–7 until `/hacker` finds nothing.
166188

167189
### 8. Commit to the temporary private fork
@@ -293,6 +315,7 @@ Answer every question with evidence:
293315
- [ ] **Are variant tests written and passing?** At least one per related path from step 4.
294316
- [ ] **Are composition tests written and passing?** Combined with at least 3 primitives from ATTACKS.md.
295317
- [ ] **Does the full test suite pass?** No regressions.
318+
- [ ] **Does `npm test` pass on every Node major from 8 through the latest release?** Run the full local sweep before push. (Step 7 → "Multi-Node-version testing".)
296319
- [ ] **Do new tests fail without the patch?** Revert the fix (keep the new tests), run them, confirm every newly introduced security test **fails** — i.e., the exploit succeeds. Then re-apply the fix. **A security test that passes even without the patch proves nothing.** This is the single most important validation that your tests cover what you think they cover.
297320
- [ ] **Is `docs/ATTACKS.md` updated?** New entry follows the format, references the relevant Invariant, cross-referenced.
298321
- [ ] **Is `CHANGELOG.md` updated?**

0 commit comments

Comments
 (0)