Security.txt uitgelegd: kwetsbaarheden melden volgens RFC 9116

Iedereen die wel eens een kwetsbaarheid heeft gevonden, kent het probleem: je hebt iets gevonden met echte impact, maar waar meld je het op een manier die niet eindigt bij een sales-formulier of een info@-mailbox die door stagiairs wordt gelezen? LinkedIn-berichten verdwijnen in de leegte, en social media is al helemaal geen serieus kanaal.

Daarvoor bestaat security.txt. Het is een klein, gestandaardiseerd tekstbestand op een vaste plek op je website dat precies één ding doet: security researchers vertellen hoe ze een kwetsbaarheid verantwoord kunnen melden. Niet meer, niet minder. Het is de digitale equivalent van een meldpunt-bordje bij de voordeur.

Het bestand is vastgelegd in RFC 9116, gepubliceerd in april 2022 en geschreven door Edwin Foudil en Yakov Shafranovich. Het wordt gebruikt door onder andere Google, GitHub en overheden — waaronder de Nederlandse rijksoverheid, die het gebruik via het Digital Trust Center actief onderschrijft (securitytxt.org).

In dit artikel leggen we uit hoe security.txt écht werkt volgens de specificatie, welke velden er toe doen, hoe je het beveiligt met een handtekening, en welke fouten vrijwel iedereen maakt. We plaatsen het ook in de context van responsible disclosure in Nederland: security.txt is niet het beleid zelf, maar de machine-leesbare haak die je disclosurebeleid koppelt aan echte meldingen.

1. Wat is security.txt precies?

security.txt is een machine-leesbaar tekstbestand op de vaste locatie:

https://jouwdomein.nl/.well-known/security.txt

Het is bewust simpel gehouden: geen JSON, geen XML, geen API. Gewoon platte tekst met een beperkt aantal velden. Daardoor is het makkelijk te implementeren (zelfs op shared hosting), makkelijk te parsen door tools en scanners, en moeilijk te verpesten — zolang je de specificatie volgt.

Het doel is niet om een volledig vulnerability disclosure-programma te vervangen. Het is de eerste stap: de plek waar een researcher kijkt voordat hij of zij verder zoekt. Hoe je daarna met de melding omgaat, staat in je responsible disclosure-beleid. Meer daarover lees je in onze gids over responsible disclosure in Nederland.

2. Waarom het belangrijker is dan de meeste mensen denken

Researchers zoeken er actief naar. Goede researchers en geautomatiseerde scanners kijken standaard eerst op /.well-known/security.txt. Als die er niet is of de contactgegevens kloppen niet, is de kans groot dat de melding nooit aankomt — of dat de researcher de kwetsbaarheid publiek maakt omdat er geen duidelijk kanaal was (securitytxt.org).

Het is een signaal van volwassenheid. Een correcte, actuele security.txt laat zien dat er nagedacht is over coordinated vulnerability disclosure (CVD). Voor een organisatie die serieus genomen wil worden, is het bijna net zo basaal als een geldig TLS-certificaat.

Het beschermt beide kanten. Voor de website-eigenaar: meldingen komen binnen via het kanaal dat jij kiest. Voor de researcher: je weet precies wat de verwachtingen zijn en hoeft niet te gokken.

3. De regels van het spel (RFC 9116)

De specificatie is streng waar het moet en pragmatisch waar het kan. Dit zijn de regels die in de praktijk het vaakst worden gemist:

RegelWat de RFC voorschrijft
LocatieOrganisaties MOETEN het bestand plaatsen op /.well-known/security.txt (RFC 9116, §3). De oude root-locatie /security.txt mag alleen als legacy-fallback, liefst als redirect naar /.well-known/. Zitten er beide, dan telt altijd de .well-known-variant.
HTTPSHet bestand MOET via https worden opgehaald (RFC 9116, §3).
BereikHet bestand geldt alléén voor het domein of IP-adres waar het vandaan komt — niet voor subdomeinen of bovenliggende domeinen (RFC 9116, §3.1). Een security.txt op voorbeeld.nl dekt api.voorbeeld.nl dus niet.
FormaatPlatte tekst (MIME-type text/plain), gecodeerd in UTF-8. Elke regel eindigt met CRLF of LF; regels die beginnen met # zijn commentaar (RFC 9116, §4).
VolgordeDe volgorde van velden is niet belangrijk — behalve bij meerdere Contact-regels: dan bepaalt de volgorde de prioriteit (RFC 9116, §4).

4. De velden: verplicht, aanbevolen, optioneel

Verplicht — zonder deze twee is het bestand niet conform de RFC:

VeldBetekenisVoorbeeld
Contact (verplicht, mag vaker voorkomen)Hoe de melding moet worden gedaan. De waarde MOET een URI zijn, dus mailto: of https:// — een kale e-mailadresregel is ongeldig (RFC 9116, §2.5.3).Contact: mailto:security@voorbeeld.nl
Expires (verplicht, slechts één keer)Datum en tijd waarop het bestand als verouderd geldt. Formaat: RFC 3339-timestamp. De RFC beveelt aan dat de datum minder dan een jaar in de toekomst ligt, om veroudering te voorkomen (RFC 9116, §2.5.5).Expires: 2027-09-30T23:59:59Z

Sterk aanbevolen:

VeldBetekenis
CanonicalDe autoritatieve URL van dit bestand. Samen met een digitale handtekening authenticeert dit de locatie van het bestand — dé bescherming tegen een nep-bestand dat een aanvaller neerzet (RFC 9116, §2.5.2).
PolicyLink naar je volledige responsible disclosure-beleid — naar een pagina die écht de spelregels uitlegt, niet naar algemene voorwaarden (RFC 9116, §2.5.7).
Preferred-LanguagesTalen waarin je meldingen wilt ontvangen, gescheiden door komma’s. Mag slechts één keer voorkomen (RFC 9116, §2.5.8).

Optioneel:

VeldBetekenis
EncryptionURI naar de plek waar je openbare sleutel te downloaden is. De sleutel zelf mag NOOIT in het veld staan; een web-URI MOET met https:// beginnen (RFC 9116, §2.5.4).
AcknowledgmentsLink naar een “hall of fame” of bedankpagina voor researchers (RFC 9116, §2.5.1).
HiringLink naar security-vacatures (RFC 9116, §2.5.6).

Geregistreerde velden buiten de RFC. De makers beheren bij IANA een open register voor uitbreidingen. Twee zijn interessant:

VeldBetekenis
Bug-BountyGeef met Bug-Bounty: True of Bug-Bounty: False expliciet aan of je een beloning biedt (uit de CERT CVD-guide).
CSAFLink naar een provider-metadata.json van het Common Security Advisory Framework — voor organisaties die advisories machine-leesbaar publiceren.

5. Voorbeelden: van minimaal tot ondertekend

Minimale versie (conform, laagdrempelig)

# Security contact for example.nl
Contact: mailto:security@example.nl
Expires: 2027-09-30T23:59:59Z

Volledige versie (zo het hoort)

# Security contact for example.nl
# https://example.nl/

Contact: mailto:security@example.nl
Contact: https://example.nl/security/melden
Expires: 2027-09-30T23:59:59Z
Preferred-Languages: nl, en
Canonical: https://example.nl/.well-known/security.txt
Policy: https://example.nl/responsible-disclosure
Encryption: https://example.nl/.well-known/pgp-key.txt
Acknowledgments: https://example.nl/security/hall-of-fame

Waarom dit voorbeeld goed is:

  • Meerdere Contact-regels (e-mail + webformulier) — researchers kunnen kiezen, en de eerste regel heeft per definitie prioriteit.
  • Expires ligt ruim vooruit maar binnen het jaar, precies zoals de RFC aanbeveelt.
  • Canonical voorkomt dat een aanvaller een nep-bestand kan neerzetten.
  • Encryption verwijst naar een downloadbare sleutel — alleen opnemen als je PGP-mail ook daadwerkelijk kunt ontsleutelen.

Ondertekende variant

De RFC beveelt aan het bestand te ondertekenen met een OpenPGP cleartext signature, en raadt daarbij expliciet het gebruik van Canonical aan, zodat de handtekening ook de locatie authenticeert (RFC 9116, §2.3). Zo ziet dat eruit (vereenvoudigd):

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Contact: mailto:security@example.nl
Expires: 2027-09-30T23:59:59Z
Canonical: https://example.nl/.well-known/security.txt
...
-----BEGIN PGP SIGNATURE-----
[handtekeningblok]
-----END PGP SIGNATURE-----

6. Veelgemaakte fouten (en hoe je ze voorkomt)

Verlopen Expires. Het bestand is ooit aangemaakt en daarna vergeten. Een verlopen security.txt is erger dan geen: de data geldt als verouderd en mag niet meer worden gebruikt (RFC 9116, §2.5.5). Fix: koppel het vernieuwen aan een vast ritueel, bijvoorbeeld elk jaar op 1 januari.

Verkeerde locatie. Het bestand hoort op /.well-known/security.txt. De root-locatie is alleen een legacy-fallback, liefst als redirect — en bij beide wint altijd de .well-known-variant (RFC 9116, §3).

Contact zonder URI. Contact: security@voorbeeld.nl is ongeldig. Het moet mailto:security@voorbeeld.nl of een https://-link zijn (RFC 9116, §2.5.3). Vermijd bovendien een sales-formulier als meldpunt; link naar een dedicated securitypagina.

Dode Policy-link. Een Policy:-regel die naar een 404 of een generiek privacybeleid verwijst, is precies op het moment dat een researcher duidelijkheid nodig heeft waardeloos.

Encryption zonder capability. Neem je Encryption: op, dan moet de sleutel daadwerkelijk downloadbaar zijn in een geldig formaat én moet de mailbox decryptie aankunnen. “PGP beloofd maar niet bruikbaar” frustreert researchers alleen maar (RFC 9116, §2.5.4).

Verwachten dat het bestand subdomeinen dekt. Dit is de meest onderschatte valkuil: security.txt geldt uitsluitend voor het domein waar het vandaan komt (RFC 9116, §3.1). Heb je aparte producten op subdomeinen? Dan hebben die elk hun eigen security.txt nodig.

Geen Canonical bij ondertekening. Onderteken je het bestand, dan hoort Canonical erbij — anders kan de handtekening de locatie niet authentiseren (RFC 9116, §2.3).

7. Implementatie

Op shared hosting (Apache en dergelijke)

  1. Maak in de root van je website de map .well-known aan (via FTP of bestandsbeheer).
  2. Upload het bestand security.txt met de juiste inhoud.
  3. Zorg dat het als text/plain wordt geserveerd (meestal standaard) en controleer dat redirects je niet naar een verkeerd pad sturen.

Op WordPress

Handmatig plaatsen zoals hierboven is betrouwbaarder dan een plugin. Veel plugins zetten het bestand op de verkeerde plek of houden de Expires-datum niet bij.

Testen

  1. Open https://jouwdomein.nl/.well-known/security.txt in de browser: zie je platte tekst met de juiste velden?
  2. Controleer de response-headers: Content-Type: text/plain en een geldige HTTPS-verbinding.
  3. Draai het bestand door een validator die RFC 9116 volgt.
  4. Test dat Contact en Policy daadwerkelijk werken — vanaf mobiel ook.

De makers onderhouden op securitytxt.org de officiële FAQ en richtlijnen.

8. De Nederlandse context

In Nederland is coordinated vulnerability disclosure de norm: het NCSC hanteert er een formeel beleid voor (NCSC), en de rijksoverheid onderschrijft het gebruik van security.txt via het Digital Trust Center (securitytxt.org). Security.txt is niet “het beleid” — het is de machine-leesbare haak die je disclosurebeleid koppelt aan echte meldingen. De keten:

  1. Researcher vindt een kwetsbaarheid.
  2. Researcher opent /.well-known/security.txt.
  3. Researcher ziet het contactkanaal én de policy.
  4. Melding komt binnen via het kanaal dat jij hebt gekozen.
  5. Jij volgt je eigen policy.

Zonder security.txt blijft stap 2 vaak hangen. Heb je al een responsible disclosure-beleid? Dan is security.txt de logische volgende stap om dat beleid vindbaar te maken. Zie ook onze gids over responsible disclosure en de FAQ (vraag: “Ik heb een kwetsbaarheid gevonden. Wat nu?”).

9. Checklist: is jouw security.txt in orde?

  • Bestand staat op https://jouwdomein.nl/.well-known/security.txt
  • Wordt geserveerd als text/plain over HTTPS
  • Bevat minimaal Contact (als URI) en Expires (RFC 3339)
  • Expires ligt minder dan een jaar vooruit, en je hebt een jaarlijks vernieuwritueel
  • Belangrijkste contactkanaal staat als eerste Contact-regel
  • Policy verwijst naar een werkende responsible disclosure-pagina
  • Canonical is aanwezig en klopt — zeker bij een ondertekend bestand
  • Preferred-Languages is ingevuld (slechts één keer, komma-gescheiden)
  • Als je Encryption opneemt: de sleutel is downloadbaar en je kunt PGP-mail echt lezen
  • Subdomeinen hebben waar nodig hun eigen security.txt

10. FAQ

Moet ik ook een Bug-Bounty-veld opnemen?

Nee, het is optioneel. Maar als je een beloning aanbiedt (of juist niet), maakt Bug-Bounty: True of False dat direct duidelijk via een geregistreerd veld (IANA).

Dekt mijn security.txt ook subdomeinen?

Nee. Het bestand geldt alleen voor het domein of IP-adres waar het vandaan komt (RFC 9116, §3.1).

Wordt mijn e-mailadres gespamd?

Het veld is optioneel. Ben je bang voor spam, gebruik dan een https://-URI naar je beveiligingspagina als contactwaarde (securitytxt.org).

Hoe vaak moet ik het bestand vernieuwen?

De RFC beveelt aan Expires minder dan een jaar vooruit te zetten (RFC 9116, §2.5.5). Een jaarlijks ritueel (bijvoorbeeld 1 januari) werkt goed.

Moet ik het bestand ondertekenen?

Het is een aanbeveling, geen verplichting (RFC 9116, §2.3). Doe je het wel, gebruik dan een OpenPGP cleartext signature én het Canonical-veld.

11. Conclusie

Security.txt is geen rocket science. Het is een klein, gestandaardiseerd bestand met een groot effect: het maakt de weg vrij tussen iemand die een kwetsbaarheid vindt en de mensen die hem kunnen oplossen. Een correct bestand volgens RFC 9116 vermindert ruis, voorkomt misrouting, verlaagt de kans op escalatie richting publicatie — en laat zien dat coordinated vulnerability disclosure bij jou serieus wordt genomen.

Voor een organisatie die “ethisch, legaal en Nederlands” in het vaandel heeft, is dat geen optionele extra. Het is basishygiëne. Wil je meer weten over hoe wij zelf omgaan met kwetsbaarheidsmeldingen? Lees dan onze Over Ons-pagina en de responsible disclosure-gids, of neem contact op.