Threat model: site pages
Scope: the static HTML tool, guide, hub and disclosure pages served from ainumbers.co. Written from the repository on . All threat models.
Assets
- Visitor inputs. Numbers and text typed or pasted into a tool. They exist in the tab's memory only.
- Page integrity. A visitor must get the code the repository published. A tampered page that reads inputs is the main way this surface could harm anyone.
- Output correctness. A calculator that silently returns a wrong number is a harm of its own; it is covered by the kernel and parity gates, not by this page.
Trust boundaries
- Repository to static host: files are copied by the deploy workflow (
.github/workflows/deploy-to-dreamhost.yml), which writes a per-file checksum list. - Static host to visitor, through the Cloudflare edge, which can rewrite HTML in transit.
- The visitor's browser to the page: each page carries its own Content-Security-Policy as a meta tag.
- Page to the outside: only the ledger and the MCP playground are allowed any network call at all (see the ledger and MCP endpoint pages).
Adversaries
- S1. A contributor or dependency that adds a network call or a script to a page.
- S2. An attacker or a misconfigured edge feature that injects markup between the host and the visitor.
- S3. An attacker who changes files on the origin host after deploy.
- S4. A hostile page or link that feeds crafted data into a tool through a URL fragment or import.
In scope and out of scope
In scope: unintended network egress from a page; injected third-party scripts; origin tampering; weakened page CSP; client-side storage of inputs.
Out of scope: a compromised visitor browser or extension; the correctness of the regulation a calculator models; denial of service against the static host; the Helm daemon.
Controls
| Threat | Control | Where it lives |
|---|---|---|
| S1: new network call in tool, guide or chaingraph JS | Static scan for network-capable APIs, baseline-shielded so counts only go down | scripts/check-site-egress.mjs, scripts/site-egress-baseline.json |
| S1: page CSP weakened or drifting from the canonical profile | Every page must carry the canonical CSP, with connect-src 'none' on standard pages | scripts/check-csp-consistency.mjs |
| S1: scan scope drifts from what is published | Gate and sitemap generator read one shared directory manifest | scripts/published-dirs.json |
| S2: edge-injected script such as an analytics beacon | Fetches live pages, diffs served external references against repo source, fails on any extra | scripts/check-served-egress.mjs, scripts/served-egress-allowlist.json (empty by design) |
| S3: origin file differs from the repository | Deploy writes /.well-known/deploy-checksums.txt; the same gate samples listed URLs and compares sha256 | scripts/check-served-egress.mjs (byte-integrity axis), deploy-to-dreamhost.yml |
| Personal data entered into a tool that exports | Tools that export carry a PII banner | scripts/check-pii-banner.mjs |
| S4: crafted fragment or import | The CSP blocks remote loads and frames; no gate checks how each tool renders crafted input | UNTESTABLE as a general claim |
UNTESTABLE claims
- "Inputs never leave your tab" for every tool. The egress scan and the CSP gate make it hard to violate, and a baseline lists known inert references. No test proves the absence of every exfiltration path, and the CSP allows
'unsafe-inline'scripts, so the CSP is a backstop and not a proof. - "No client-side storage" for every tool. The build directive forbids it (
CONTRACT.mdsection 1.1). We did not find a gate that scans for storage APIs by name, so this is enforced by review. The ledger page does uselocalStoragefor interface state; see the ledger model. - The static host's own logs. The host and the Cloudflare edge log requests under their own policies, which we cannot test from the repository. See data handling.
Residual risk
- The Google Fonts stylesheet and font origins are still allowed by the standard CSP on some pages, so a visitor's IP and user agent can reach Google when a page requests them. A separate change is moving fonts to self-hosting; until it lands, treat this as open.
- A compromise of the deploy credentials would let an attacker publish valid pages with a matching checksum list. The gates detect divergence from the repository, not a malicious commit.
- The edge can transform HTML. Only transforms listed in the allowlist are accepted, and the list is empty, so a legitimate new transform will first show up as a red build.