A privacy check on every finished form was built as a list of banned outside servers — it only stops names someone hand-wrote onto it. Hamilton’s JotForm caught the gap this week. The fix: flip it to a list of invited servers, so an unknown leak becomes a loud wall instead of a silent ship — for every form tool, including ones we’ve never seen.
Three facts that frame everything below — not up for debate, just the ground you’re standing on.
scripts/il-form-rewrite.ts → validateServedHtml() + LEAK_PATTERNS, currently a 5-entry denylist at ~line 793. This is the gate to flip.scripts/il-form-boundary-verify.ts → ALLOWED_HOSTS (line 18). This one is already a fail-closed allowlist — but its coverage is narrow: one hardcoded form URL, loaded once at networkidle, no interaction.
validateServedHtml with allowlist semantics:
https:// and protocol-relative // references across script/link/iframe/img/form-action/inline-url surfaces (reuse the hostname-anchored, entity-encoding-safe matcher the JotForm-family fix is introducing).FORM_ALLOWED_HOSTS set. Anything else → a violation, build fails closed.FORM_ALLOWED_HOSTS is authored from the fleet census output — each entry carries a role + why-it-must-reach comment so the list stays auditable. Known must-reach so far: challenges.cloudflare.com (Turnstile CAPTCHA) plus the site’s own build origin. Everything else pends the census.LEAK_PATTERNS is asymmetric with the strip/localize logic — some hosts get stripped but aren’t in the validation list, so a leak of them ships silently. The allowlist flip dissolves this class structurally — validation no longer enumerates bad hosts, so there’s nothing to keep in sync.allowlistCandidates[] — every external host any form legitimately reaches across the fleet, tagged allow-must-reach / localize / strip-block. The allow-must-reach set becomes FORM_ALLOWED_HOSTS; this section fills in when the census returns.
il-form-boundary-verify.ts’s ALLOWED_HOSTS:
ALLOWED_HOSTS and FORM_ALLOWED_HOSTS as one shared source so the static check and the runtime check can never disagree.A separate, prevalence-ordered backlog: outside-service form tools with no in-house rebuild path yet (only JotForm has one today). This spec doesn’t build those — it makes them fail loudly instead of shipping silently. Their rebuild paths are future, prioritized work.
make gate / targeted form tests green; tsc clean.For the builder: jump straight to the machinery, grouped by kind.
Files —
il-form-rewrite.ts (per-form check) ·
il-form-boundary-verify.ts (runtime gate)
Gates —
validateServedHtml allowlist flip ·
runtime ALLOWED_HOSTS broadening
Rollout steps —
shadow ·
reconcile ·
enforce
Verification & rollback —
definition of done + rollback