You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
Copy file name to clipboardExpand all lines: .claude/skills/fix-vulnerability/SKILL.md
+23Lines changed: 23 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -162,6 +162,28 @@ Apply the fix with minimal, self-contained diff. Comment every security-critical
162
162
-**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.).
163
163
-**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.
164
164
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
+
forvin 8 10 12 14 16 18 20 22 24 25;do
173
+
nvm use $v&& npm test2>&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
+
165
187
**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.
166
188
167
189
### 8. Commit to the temporary private fork
@@ -293,6 +315,7 @@ Answer every question with evidence:
293
315
-[ ]**Are variant tests written and passing?** At least one per related path from step 4.
294
316
-[ ]**Are composition tests written and passing?** Combined with at least 3 primitives from ATTACKS.md.
295
317
-[ ]**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".)
296
319
-[ ]**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.
297
320
-[ ]**Is `docs/ATTACKS.md` updated?** New entry follows the format, references the relevant Invariant, cross-referenced.
0 commit comments