Files
VacatureRadar/docs/quality/THREAT_MODEL.md
T

143 lines
11 KiB
Markdown

# Threat model
## Scope en assets
Te beschermen:
- gebruikersaccount, sessies en zoekvoorkeuren;
- mailbox-, SMTP-, database- en registrycredentials;
- sollicitatiedossiers, notities en eventuele documenten;
- integriteit van vacatureclusters, scores en feedback;
- beschikbaarheid van de Unraid-host en het thuisnetwerk;
- bronbeleid en bewijs dat alleen toegestane bronnen worden benaderd.
Niet vertrouwd:
- iedere vacaturetekst, HTML, JSON-LD, feed en e-mail;
- alle links en redirectdoelen;
- externe DNS/HTTP/TLS-responses;
- AI-modeloutput, ook lokaal;
- browserinput en handmatige URL's;
- logs of exports die buiten de applicatie worden geopend.
## Trust boundaries
```text
Internet/mailbox
-> URL/source policy + IMAP boundary
-> raw document quarantine/retention
-> parser + sanitizer
-> normalized domain model
-> deterministic rules/scoring
-> authenticated UI / digest
User browser
-> TLS/reverse proxy
-> Django session + CSRF + object scoping
-> database
Django/Celery
-> Redis (queue, geen waarheid)
-> PostgreSQL (bron van waarheid)
-> optionele Ollama boundary
```
## Belangrijkste dreigingen en mitigaties
| ID | Dreiging | Impact | Mitigaties | Verificatie |
|---|---|---|---|---|
| T-01 | SSRF via bron- of vacature-URL | toegang tot LAN, metadata of beheerinterfaces | schema/host/IP/poortcontrole, DNS-resolutie, redirecthercontrole, denylist, geen credentials in URL | `tests/security/test_url_security.py`, `test_policy.py`, fetchertests |
| T-02 | DNS rebinding/tijd-van-controle | request bereikt ander IP dan beoordeeld | iedere fetch en redirect valideert opnieuw DNS-resolutie en vereist consistente IP-set-overlap | `VR-115`, `tests/unit/test_fetcher.py`, aanvullende fetcher negative tests |
| T-03 | XSS/HTML-injectie | sessiediefstal of ongewenste navigatie | Bleach allowlist, platte tekst, template autoescaping, CSP/securityheaders | `tests/security/test_sanitize.py`, viewtests |
| T-04 | Prompt injection in vacature | AI verandert beleid of voert tools uit | vacaturetekst in data-envelope, schema-output, evidence-validatie, cachefouten met foutcategorie, geen toolrechten, deterministische harde regels, AI optioneel | AI-tests, ADR-0003, `VR-109` evaluaties |
| T-05 | Malafide/oversized document | geheugen/CPU/diskuitputting | contenttype-, byte-, timeout- en redirectlimieten; korte retentie | fetchertests, source-runmetrics |
| T-06 | Crawlstorm of ban | externe overlast, IP-blokkade | expliciet allowbeleid, per-origin minimuminterval, concurrencylimiet, leasegebaseerde taakclaim met TTL + crash recovery, conditional requests, backoff, quarantaine | tasktests; `VR-103`, `VR-112` |
| T-07 | Direct platformscrapen | voorwaarden-/blokkaderisico | centrale denylist, e-mailingress, geen loginbot/CAPTCHA | policytests, ADR-0002/0005 |
| T-08 | E-mailparserlink naar phishing/private host | ongewenste fetch of gebruiker misleid | linkextractie slaat unsubscribe over, follow-up opnieuw door policy/SSRF, bronlabel zichtbaar | e-mail- en policytests |
| T-09 | MIME/HTML-bom of malformed mail | resource-uitputting/parsercrash | IMAPbatchlimiet, bodylimiet bij vervolgtaak, robuuste parser, idempotente recordidentiteit | `VR-115`, e-mailfixtures |
| T-10 | Cross-user objecttoegang | lek van sollicitaties/feedback | LoginRequired, user-scoped querysets/get_or_create, autorisatietests | integratie-viewtests |
| T-11 | CSRF op feedback/profiel | ongewenste status- of profielmutatie | Django CSRF-middleware, POST-only acties, SameSitecookies | viewtests en frameworkcheck |
| T-12 | Credentiallek in Git/logs | account- of infrastructuurcompromis | env-only secrets, gitignore, beperkte logs, voorbeeldwaarden, secretrotatierunbook | CI-secret scan gepland `VR-115`; review |
| T-13 | Onveilige reverse proxy | sessie over HTTP, host-header-/originproblemen | TLS, exact ALLOWED_HOSTS/CSRF origins, secure cookies, proxychecklist | deployment smoke-test |
| T-14 | Redis als waarheid behandeld | dataverlies/dubbele verwerking | PostgreSQL-state, idempotente taken/outbox, acks-late | integratietests |
| T-15 | Dubbele Celery-uitvoering | dubbele vacatures/mails | unieke keys, transacties, message identity, outbox-uniciteit | pipeline/digesttests |
| T-16 | Dedupe voegt verschillende jobs samen | gemiste kans/verkeerde data | exact vóór fuzzy, conservatieve drempel, bronaliassen/provenance, herstelbare clusterbeslissing gepland | dedupetests; `VR-116` evaluaties |
| T-17 | AI hallucineert ontbrekend feit | foutieve ranking | onbekend blijft onbekend, evidence/confidence, geen hard exclusion door AI | scoring/AI-tests |
| T-18 | Feedback poisoning/self-reinforcement | steeds smallere resultaten | begrensde gewichten, opt-in standaard uit, per-feature minimum samples, metadata-logging en resetpad | profieltests; `VR-110` |
| T-19 | Automatisch solliciteren/massamail | reputatie/privacy/juridisch risico | geen submitendpoint/task, expliciete ADR en non-goal | codezoekreview, AC-043 |
| T-20 | Kwaadaardig bestand in sollicitatiedossier | host/browsercompromis | uploads nog niet actief; vóór implementatie allowlist, sniffing, size limit, niet-uitvoerbare opslag vereist | `VR-113`, nieuwe threat review |
| T-21 | Back-up bevat secrets/PII | langdurig datalek | encryptie, gescheiden opslag, korte retentie, herstelprocedure | runbook en hersteltest |
| T-22 | Supply-chainpackage/image | code execution | exacte versies/lockfile, beperkte dependencies, pinned baseimages/digests en scans gepland | CI, `VR-115` |
| T-23 | Onbevoegde admin op thuisnetwerk | volledige datatoegang | uniek wachtwoord, TLS/VPN, geen defaultcredentials, sessiebeveiliging | Unraidchecklist |
| T-24 | Source terms wijzigen | ongewenste voortgezette crawling | reviewdatum, source health en policy expiry gepland | `VR-102`, `VR-112` |
| T-31 | Sollicitatiedossier-export bevat niet-gewenste payload | data-lek of onbedoeld dossieroverdragen | export bevat alleen het gekozen dossier, ZIP-inhoud is beperkt tot snapshot/tijdlijn/print-HTML, bestandsnaam is geslugified zonder padseparators | `tests/integration/test_applications.py` |
| T-32 | XML external entity/entity-expansion via sitemap | lokale data-uitlezing of parseruitputting | sitemap-XML wordt met `defusedxml` verwerkt; fetcherlimieten blijven vóór parsing gelden | `tests/unit/test_discovery_rss.py`, Ruff securitycheck |
| T-33 | Externe UI-CDN of niet-vertrouwde Stitch-interactie | supply-chain-XSS, tracking of acties buiten Django-beleid | productie gebruikt alleen lokale CSS/JS en inline SVG-symbolen; Stitch-code is documentatiereferentie, alle mutaties blijven Django POST+CSRF; themavoorkeur bevat geen persoonsgegevens en opslagfouten worden afgevangen | `tests/e2e/test_vr114_browser_and_accessibility.py`, browserconsole- en assetcontrole VR-118 |
## Misbruikscenario's
### Vacature zegt “negeer eerdere instructies”
De tekst wordt gesanitized en als veldwaarde doorgegeven. Een eventuele AI-call krijgt een vast schema en geen tools. De output kan geen bron activeren, URL openen, harde regel verwijderen, mail sturen of sollicitatie indienen.
### Publieke pagina redirect naar `192.168.1.1`
De redirectlocatie wordt opnieuw gevalideerd. Het request naar het private adres wordt niet uitgevoerd; de bronrun krijgt een policy/securityfout en de bron kan in quarantaine gaan.
### E-mailalert bevat een platformlink en uitschrijflink
De adapter herkent vacaturekandidaten, negeert bekende unsubscribepatronen en slaat de platformlink hoogstens als alias op. Automatisch volgen vereist opnieuw een toegestane source policy; denylistplatformen worden geweigerd.
### Aanvaller laat scheduler dezelfde job herhalen
Canonieke sleutels, databaseconstraints, transacties, idempotente message identity en outboxuniciteit beperken duplicaten. Taken zijn ontworpen voor at-least-once in plaats van exact-once aannames.
## Security gates bij nieuwe functionaliteit
Een wijziging aan netwerk, mail, AI, rendering, auth, exports of uploads vereist:
1. nieuwe/gewijzigde threat in deze tabel;
2. negatieve test die de aanval representeert;
3. begrensde input/output en foutcategorie;
4. logreview op secrets/PII;
5. runbook- en configuratie-update;
6. volledige `codex_verify`-gate.
## Resterende risico's
- Een applicatielaag kan DNS rebinding niet volledig uitsluiten zonder transportniveau-IP-pinning; dit staat in `VR-115`.
- Brute-force of herhaalde foutieve mutatiepogingen blijven mogelijk, maar zijn beperkt door in-memory rate limiting en blokkades op login/manual-import.
- Bronvoorwaarden vereisen menselijke/externe review per domein; automatisering kan dat niet juridisch beslissen.
- Fuzzy dedupe en featureheuristieken kunnen inhoudelijk verkeerd zijn; provenance, feedback en benchmarkevaluaties beperken maar elimineren dit niet.
- Een persoonlijke Unraid-host blijft afhankelijk van correcte netwerksegmentatie, patching en back-ups door de beheerder.
- T-25: Verloren of verlopen policyreview
- Impact: bron kan op onbedoelde wijze doorgaan met crawlen
- Mitigatie: `SourcePolicyReview` met decision/expiry + policy gate in `assess_url`
- Verificatie: security/integration tests rond verlopen review in fail-closed gedrag
- T-26: Handmatige URL/tekstimport
- Impact: ongewild ophalen van geblokkeerde of niet-ingesteste informatie, XSS via ingevulde tekst of overschrijding van limieten
- Mitigatie: CSRF-only import endpoint, allowlist-domeinvrije policy checks, sanitize op tekstveld, byte-limiet en max-size/timeout gedrag
- Verificatie: integration/security tests rond rejectie van geblokkeerde URL's en overschrijding van paste-limiet
- T-27: Reminder-flood of dubbele reminder-mails
- Impact: gebruiker ontvangt herhaalde of ongewenste herinneringen
- Mitigatie: stabiele `dedupe_key`, idempotente outbox met statusmachine, `reminder_type`-types en task-driven verzending
- Verificatie: `tests/integration/test_reminders.py`
- T-28: Onterecht verzenden zonder ontvanger/uitgeschakelde reminderinstelling
- Impact: onnodige fout- of testmails, verwarring over afmeldgedrag
- Mitigatie: master- en topmatchschakelaar per profiel, `SKIPPED`-status bij lege ontvanger en foutlogica met retries op taakniveau
- Verificatie: `tests/integration/test_reminders.py`
- T-29: Bronhealth zet bronnen te vroeg in quarantaine bij incidentele netwerkruis
- Impact: tijdelijke uitval of incidentele bronfouten blokkeren een gezonde bron
- Mitigatie: duidelijke foutcategoriedrempels, gescheiden policy/security- en tijdelijke-foutlogica, en canaryherstel via trialpad
- Verificatie: `tests/integration/test_source_health.py`
- T-30: Geautomatiseerde canaryherstel blijft onbegrensd draaien
- Impact: herhaalde herstarts van dezelfde bron veroorzaken extra belasting
- Mitigatie: cooldown plus metadataflag voor eenmalige canary, en trialstatus met beperkte runtrigger
- Verificatie: `tests/integration/test_source_health.py`