security-txt.eu

GuideAs of 9 min read

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.

FieldRFC 9116BSI TR-03183-3Content
ContactRequired, may repeat, in order of preferenceRequired: PSIRT mailbox first, CSIRT mailbox second, reporting page third (4.2.3)mailto:, https:// or tel:
ExpiresRequired, exactly once, recommended less than a year aheadRequired, upper-case T and Z; should be at most one year ahead (4.2.9)Date as per RFC 3339
CanonicalOptional, recommended when signedRequired, reachable without redirect (4.2.2)Address of the file itself
EncryptionOptionalRequired for every e-mail address in Contact, direct .asc download (4.2.4, 4.3.2)Address of the OpenPGP key
Preferred-LanguagesOptional, onceRequired, at least en (4.2.6)Language tags, comma-separated
PolicyOptionalRequired (4.2.7)Address of the CVD policy
AcknowledgmentsOptionalRecommended (4.2.5)Hall of fame page
CSAFNot in the RFC, IANA registry since 2023Recommended (4.2.8)Address of provider-metadata.json
Bug-BountyNot in the RFC, IANA registry since March 2026Not coveredTrue or False
HiringOptionalNot coveredSecurity 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> 2y and for the subkeys gpg --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.txt instead 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.com while the file lives at www.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