15 KiB
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
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 DNS opnieuw; het werkelijk verbonden peer-IP wordt als publiek gecontroleerd wanneer de transportlaag dit exposeert, anders geldt conservatieve DNS-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/database/UI | account- of infrastructuurcompromis | app-wachtwoorden met MultiFernet en afzonderlijke environmentkey versleuteld; nooit terugtonen; generieke fouttekst; gitignore, secretrotatierunbook | tests/unit/test_mailbox_credentials.py, tests/integration/test_mailbox_connections.py, CI-secret scan VR-115 |
| 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 |
| T-34 | Publieke ATS-feed of robotsredirect wijzigt van host/identiteit | SSRF, verkeerd werkgeverslabel, ongewenst sollicitatie-endpoint of voortgezet fetchen na voorwaardenwijziging | iedere robotsredirect wordt opnieuw als publieke URL gevalideerd; feeds gebruiken alleen gereviewde GET-endpoints; werkgeveridentiteit komt uit source-config; reviews verlopen fail-closed en apply-endpoints zijn geen fetchbron | tests/security/test_robots.py, tests/integration/test_pipeline.py, tests/unit/test_ats_adapters.py, VR-120 |
| T-35 | Regionale vacaturehub bevat een gemanipuleerde off-domain kaart of gedeelde ATS-host overschrijft een andere werkgever | phishinglink, foutieve herkomst, verlies van bronbeleid of verkeerde inventaris | regionale adapter accepteert alleen same-host /job/-links; bronuniciteit gebruikt type + exacte publieke base-URL; per-origin lease en minimuminterval blijven over alle ATS-tenants gedeeld |
tests/unit/test_regional_adapters.py, tests/unit/test_source_models.py, tests/integration/test_seed_sources.py, VR-121 |
| T-36 | Kwaadaardige/oversized platformmail of linkinjectie in een jobalert | parseruitputting, batchuitval, phishing, foutieve vacatures of verborgen scraping | IMAP-batch is begrensd; foutisolatie en idempotente identity per mailbox; platformparser accepteert alleen gelabelde HTTPS-links op het gekozen jobboarddomein en verwerpt externe/adminlinks; alle brede jobboards blijven op de directe-fetchdenylist | tests/integration/test_email_import_notifications.py, tests/unit/test_email_adapter.py, tests/security/test_policy.py, VR-122/123/124/125 |
| T-37 | Lokale werkgeverslijst wijzigt markup, injecteert een externe kaart of vermengt functies buiten de regionale scope | phishing, foutieve locatie, te brede radar of onbetrouwbare ranking | lokale adapter is beperkt tot vijf gereviewde host/padcombinaties, accepteert alleen same-host details en past waar beschikbaar een expliciete Hasselt-filter toe; retire-seeding schakelt buitenregionale bronnen uit zonder provenance te wissen | tests/unit/test_regional_adapters.py, tests/integration/test_seed_sources.py, VR-125 |
| T-38 | Cross-user mailboxbeheer, dubbele polls of IMAP naar private host | credentialmisbruik, duplicaten, toegang tot interne diensten | alle views scopen op gebruiker en vereisen CSRF; unieke user+platformkoppeling; transactionele lease; hostvorm en publieke DNS/IP-validatie vóór TLS-IMAP | tests/integration/test_mailbox_connections.py, tests/unit/test_mailbox_credentials.py, apps/sources/services/imap_import.py, VR-123 |
| T-39 | Mol-/Kempenbron vermengt een andere werkgever, campus of vestiging | foutieve afstand, phishing of buitenregionale resultaten | exacte HTTPS-host/pad/GUID-routes; same-host details; expliciete plaatsfilters voor regionale en gedeelde lijsten; postcodecentra blijven als benadering herkenbaar; waaklijstbronnen worden niet gescand | tests/unit/test_regional_adapters.py, tests/integration/test_tasks_and_more_views.py, VR-126/201 |
| T-40 | Verouderde lokale CA-store of ongeldige serverketen lokt een TLS-bypass uit | onderschepte vacature- of mailboxdata en credentialdiefstal | expliciet gepinde certifi-CA-bundel voor HTTP, robots en IMAP; hostnaamcontrole en CERT_REQUIRED; nooit verify=False; dependency- en negatieve TLS-tests bij update |
tests/unit/test_tls.py, tests/security/test_robots.py, apps/sources/services/tls.py, VR-201 |
| T-41 | Gemodificeerde next-parameter na vacaturefeedback |
open redirect naar phishingdomein na een geldige gebruikersactie | terugkeer-URL moet dezelfde host en het actuele HTTPS-beleid respecteren; anders veilige detailfallback | tests/integration/test_tasks_and_more_views.py, VR-206 |
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 gebruikt de gekozen platformidentiteit, accepteert alleen gelabelde HTTPS-links op dat jobboarddomein en negeert externe tracking-, account-, privacy- en uitschrijflinks. De platformlink wordt hoogstens als alias opgeslagen. 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:
- nieuwe/gewijzigde threat in deze tabel;
- negatieve test die de aanval representeert;
- begrensde input/output en foutcategorie;
- logreview op secrets/PII;
- runbook- en configuratie-update;
- volledige
codex_verify-gate.
Resterende risico's
-
De fetcher controleert het werkelijk verbonden peer-IP wanneer httpcore dat exposeert. Een custom transport dat geen peerinformatie aanbiedt valt terug op DNS-set-overlap; volledige IP-pinning blijft een aanvullend egress-hardeningniveau.
-
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:
SourcePolicyReviewmet decision/expiry + policy gate inassess_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