Threat model · STRIDE
Even a personal site has assets worth protecting. This is the model I use for it, including the gaps I haven't closed yet.
Domain or DNS hijack redirects visitors to an impostor site.
Automated or forged contact-form submissions (spam, phishing payloads).
A malicious or compromised npm dependency is introduced (supply chain).
Unreviewed code reaches production.
No reliable record of who changed the site and when.
Cross-site scripting exposes visitors or session data.
Secrets or personal data leak through the repository or bundles.
Traffic floods or abuse of the contact endpoint.
A compromised GitHub or Vercel account deploys malicious content.
| Category | Threat | Mitigations | Residual |
|---|---|---|---|
| Spoofing | Domain or DNS hijack redirects visitors to an impostor site. |
| Low |
| Spoofing | Automated or forged contact-form submissions (spam, phishing payloads). |
| Low |
| Tampering | A malicious or compromised npm dependency is introduced (supply chain). |
| Low |
| Tampering | Unreviewed code reaches production. |
| Low |
| Repudiation | No reliable record of who changed the site and when. |
| Low |
| Information disclosure | Cross-site scripting exposes visitors or session data. |
| Low |
| Information disclosure | Secrets or personal data leak through the repository or bundles. |
| Low |
| Denial of service | Traffic floods or abuse of the contact endpoint. |
| Medium |
| Elevation of privilege | A compromised GitHub or Vercel account deploys malicious content. |
| Medium |
Known gaps. A threat model with no gaps isn't believable.
Related: architecture decision records · verify this site · report a vulnerability