diff --git a/.claude/rules/implementation.md b/.claude/rules/implementation.md index c6235e44a..bf9b44b8a 100644 --- a/.claude/rules/implementation.md +++ b/.claude/rules/implementation.md @@ -58,6 +58,21 @@ Before writing a new helper, check `#v0/utilities`. Available today: All helpers carry `/* #__NO_SIDE_EFFECTS__ */` and are tree-shakeable. Module-level allocating constants (e.g., a top-level `new Set([...])`) carry `/* @__PURE__ */` instead — see `utilities/helpers.ts` (the `UNSAFE_KEYS` set) and `utilities/instance.ts` (the `INSTANCE_KEY` literal) for the placement convention. Never add a new utility that introduces a top-level side effect — the barrel cannot absorb it. [PHILOSOPHY §2.7] +## Security primitives — reuse, never reinvent + +A headless lib exposes a small, fixed set of injection / DoS sinks, and v0 already ships the guard for each. When you write code in one of these shapes, reach for the existing primitive. Every gap found in the 2026-06-04 security audit was a sibling that missed the guard its twin already had. [user-feedback:2026-06-04] + +| When you… | Guard | Has it / missed it | +|-----------|-------|--------------------| +| Build a plain object keyed by caller- or registry-supplied strings | Skip keys in `UNSAFE_KEYS` (`#v0/utilities`) — `__proto__` / `constructor` / `prototype` | `mergeDeep` has it; `usePermissions` didn't | +| Interpolate a value into a CSS string or `