How to set up security.txt, step by step
A security.txt tells anyone who has found a security flaw in your website or products where to report it. Writing the file is quick. This guide shows what belongs in it, how to sign it, how to serve it correctly and how to keep it current.
What is security.txt?
security.txt is a small text file located at https://your-domain/.well-known/security.txt. It is defined in RFC 9116, published by the IETF in April 2022. Every line is a field in the form Field-Name: value; comments start with #. Security researchers, scanners and reporting bodies such as CERTs process it automatically.
RFC 9116 is explicit about two things: the file must be served over HTTPS as text/plain with charset=utf-8 (RFC 9116 section 3), and it applies only to the exact domain it was retrieved from, not to subdomains or parent domains (section 3.1). If your site answers on both company.com and www.company.com, you need the file at both addresses.
The fields at a glance
RFC 9116 requires only two fields. Technical Guideline TR-03183-3 of the German Federal Office for Information Security (BSI) makes more of them mandatory. Newer fields such as CSAF and Bug-Bounty are listed in the IANA registry.
| Field | RFC 9116 | BSI TR-03183-3 | Content |
|---|---|---|---|
| Contact | Required, may repeat, in order of preference | Required: PSIRT mailbox first, CSIRT mailbox second, reporting page third (4.2.3) | mailto:, https:// or tel: |
| Expires | Required, exactly once, recommended less than a year ahead | Required, upper-case T and Z; should be at most one year ahead (4.2.9) | Date as per RFC 3339 |
| Canonical | Optional, recommended when signed | Required, reachable without redirect (4.2.2) | Address of the file itself |
| Encryption | Optional | Required for every e-mail address in Contact, direct .asc download (4.2.4, 4.3.2) | Address of the OpenPGP key |
| Preferred-Languages | Optional, once | Required, at least en (4.2.6) | Language tags, comma-separated |
| Policy | Optional | Required (4.2.7) | Address of the CVD policy |
| Acknowledgments | Optional | Recommended (4.2.5) | Hall of fame page |
| CSAF | Not in the RFC, IANA registry since 2023 | Recommended (4.2.8) | Address of provider-metadata.json |
| Bug-Bounty | Not in the RFC, IANA registry since March 2026 | Not covered | True or False |
| Hiring | Optional | Not covered | Security job openings |
On top of that comes the signature: RFC 9116 recommends an OpenPGP signature (section 2.3), the TR requires it (4.2.10). Complete files for both levels are on the examples page.
RFC 9116 or BSI TR-03183-3?
RFC 9116 is the IETF specification used worldwide and is enough for most websites. TR-03183-3 "Vulnerability Reports and Notifications" (version 1.0.0 of 20 August 2025) builds on it and describes how manufacturers should receive vulnerability reports: two separate role mailboxes, keys, a reporting page with a web form, a disclosure policy and a signature.
The TR is voluntary. For manufacturers of products with digital elements it is still the obvious benchmark: the EU Cyber Resilience Act (CRA, Regulation (EU) 2024/2847) requires a contact address from 11 December 2027 for vulnerability reports (Annex I, Part II, point 6) but prescribes no format, and with the TR the BSI describes a concrete one. A simple company website without its own products is well served by RFC 9116. The BSI also recommends security.txt to all organisations in its guidance BSI-CS 149 (in German).
Step 1: Create the file
The fastest way is the generator: enter your domain, choose the standard, add any missing addresses. It writes the fields in the order and with the comments the TR asks for, sets a valid expiry date and lets you copy the file only once it is free of errors. You can also write it by hand; a file under RFC 9116 can be this short:
Contact: mailto:security@example.com
Expires: 2027-10-01T00:00:00.000Z
Preferred-Languages: en
Canonical: https://www.example.com/.well-known/security.txt
Keep values in ASCII outside comments (TR 4.2.1 c). Internationalised domains go into the file as Punycode, for example xn--mller-kva.de instead of müller.de.
Step 2: Keys and signature
The signature shows that the file comes from you and not from someone trying to divert reports, provided the reader can trust your key, for example via the fingerprint on your reporting page. You need GnuPG. The TR recommends a dedicated signing key (4.2.10 b); it must not be valid for more than five years (4.2.10 e). The algorithm must comply with BSI TR-03116-4 or the European ECCG catalogue (4.2.10 d). Elliptic curves such as NIST P-256 (nistp256) or brainpoolP256r1 satisfy both; RSA of 3000 bits or more is accepted only by the ECCG catalogue. Ed25519, the default of recent GnuPG versions, is in neither. Create the key with NIST P-256 and a two-year lifetime:
gpg --quick-generate-key "Example Ltd security.txt <security@example.com>" nistp256 sign 2y
gpg --fingerprint security@example.com
gpg --armor --export security@example.com > security-txt-signing.asc
Sign with a cleartext signature. The file stays readable and the signature wraps around it:
gpg --clearsign --digest-algo SHA512 --local-user security@example.com --output security.txt.signed security.txt
mv security.txt.signed security.txt
Publish the public key security-txt-signing.asc on your website and list its address and fingerprint on your reporting page (TR 4.5.3 c and d). Under the TR, each role mailbox also needs its own encryption key (4.3.1 j), whose .asc file goes into the Encryption field:
gpg --quick-generate-key "Example Ltd PSIRT <psirt@example.com>" nistp256 sign 2y
gpg --quick-add-key <fingerprint> nistp256 encr 2y
gpg --armor --export psirt@example.com > psirt.asc
The second command adds the encryption subkey; the first command prints the fingerprint. Repeat for csirt@. Their fingerprints also go on your reporting page (4.3.2 b).
Sign again after every change: a single changed character breaks the signature. The cleartext signature tolerates line endings (LF or CRLF) and trailing spaces, but not a change of character encoding or an added BOM, so upload the file unchanged (binary mode).
Step 3: Serve it from your web server
The file belongs in the .well-known folder at the root of your website. The folder name starts with a dot; some FTP clients hide such folders and some server configurations block them. After uploading, check that the request returns status 200 and the right content type.
Apache
In the .htaccess at the web root or in the server configuration:
<Files "security.txt">
ForceType "text/plain; charset=utf-8"
</Files>
<FilesMatch "\.asc$">
ForceType application/pgp-keys
</FilesMatch>
nginx
Many templates deny every path that starts with a dot. Allow .well-known explicitly and set the charset:
location ^~ /.well-known/ {
allow all;
}
location = /.well-known/security.txt {
charset utf-8;
}
WordPress and other CMS
Put the file into /.well-known/ next to the WordPress folders via FTP or a file manager. The web server serves a real file before WordPress sees the request. Then check that you do not get a CMS error page with status 200 instead; that is a common mistake.
Cloudflare and other bot protection
The TR requires that scanners can retrieve the file automatically (4.2.11). Bot protection that answers automated requests with a challenge page prevents exactly that. On Cloudflare the basic Bot Fight Mode cannot be switched off for individual paths; exceptions for /.well-known/ require Super Bot Fight Mode on the Pro plan or above. The checker shows whether your protection gets in the way.
Old location /security.txt
If your file currently lives only at /security.txt, move it. The old address may redirect to the new one (RFC 9116 section 3). If the file exists in both places, the one under /.well-known/ wins.
Step 4: Check it
The checker fetches the file and verifies structure, expiry date, Canonical, links, mail domains, keys and the signature, under RFC 9116 or under the TR. By hand:
curl -sI https://www.example.com/.well-known/security.txt
curl -s https://www.example.com/.well-known/security.txt | gpg --verify
The first command must show HTTP/2 200 (or 1.1) and content-type: text/plain; charset=utf-8. The second reports "Good signature" if the public key is in your keyring. Also send a test e-mail to every address in the file and make sure it arrives and gets read.
Step 5: Keep it current
security.txt has an expiry date so that outdated information does not live forever. After it, the file counts as stale and scanners report an error. Put three dates in your calendar:
- Before the expiry date: review the content, set a new date at most one year ahead, sign again, upload.
- Quarterly: the TR requires checking and correcting the information at least every quarter (4.2.9 c).
- Before your keys expire: extend them with
gpg --quick-set-expire <fingerprint> 2yand for the subkeysgpg --quick-set-expire <fingerprint> 2y '*', then export the .asc files again. The fingerprint stays the same.
Common mistakes
An analysis of the top one million domains by uriports (24 January 2025) shows how rarely the file is right: only 1.25 percent had a security.txt, and 44 percent of those complied with the RFC. 45 percent lacked Expires, 13 percent had expired.
- Wrong location: only at
/security.txtinstead of/.well-known/security.txt. - Web page instead of file: the CMS intercepts the path and returns an error page with status 200.
- Expired Expires or a date more than a year ahead; under the TR also a lower-case t or z in the date.
- Canonical points elsewhere, for example to
company.comwhile the file lives atwww.company.com(26 percent of cases according to uriports). - Acknowledgements instead of Acknowledgments: the field uses the American spelling; uriports still found the British one in 10 percent of files.
- E-mail without mailto: in the Contact field.
- Encryption points to a web page instead of directly to the .asc file (not allowed under the TR, 4.3.2 d).
- Broken signature, because the file was edited after signing or rewritten during upload.
- Nobody reads the mailbox. The most consequential mistake, and no scanner can find it.
Frequently asked questions
Is security.txt mandatory?
No law prescribes the file. From 11 December 2027 the Cyber Resilience Act (CRA) requires manufacturers to provide a contact address for vulnerability reports, but no format. BSI TR-03183-3 requires security.txt but is voluntary. For everyone else it is a recommendation, including by national cybersecurity agencies.
Will security.txt get me more spam?
Usually yes, mostly beg bounty emails that report a run-of-the-mill finding and ask for a reward. Bug-Bounty: False, a clear policy, a dedicated address and filters that sort rather than delete keep it manageable. See spam after security.txt.
Which fields are required?
Under RFC 9116 only Contact and Expires. Under the TR also Canonical, Encryption, Preferred-Languages with at least English, Policy and the signature.
How far ahead may the expiry date be?
RFC 9116 recommends less than a year; under the TR it should be at most one year. The generator suggests one year minus one day.
Is security@ enough as an address?
For RFC 9116, yes. The TR requires two role mailboxes, psirt@ for products and csirt@ for your own IT. The two roles work closely together but, except in microenterprises, must be held by different people (4.3.1 b).
Do I need the file on every subdomain?
The file applies only to the domain it is served from (RFC 9116 section 3.1). A separate file makes sense for every domain and subdomain with its own website, at least for the main domain with and without www.
Do I have to sign the file?
RFC 9116 recommends it, the TR requires it. Without a signature nobody can be sure the contact addresses really come from you.
Where do researchers report if there is no security.txt?
Often to a general address nobody associates with security, or not at all. Some then publish the flaw directly. That is exactly what the file is meant to prevent.
Sources
- RFC 9116: A File Format to Aid in Security Vulnerability Disclosure, IETF, April 2022.
- BSI TR-03183-3 Vulnerability Reports and Notifications, version 1.0.0, Federal Office for Information Security, 20 August 2025.
- IANA registry: security.txt Fields, as of 7 March 2026.
- BSI-CS 149: Sicherheitskontakte mit Hilfe einer security.txt nach RFC 9116 angeben (in German), Alliance for Cyber Security.
- Regulation (EU) 2024/2847 (Cyber Resilience Act), Annex I, Part II, point 6.
- Cloudflare Docs: Bot Fight Mode, retrieved 10 October 2026.
- security.txt in 2025, uriports, 24 January 2025.