CrawlCheck

Guides · 2026-10-02 · By · 0 views

security.txt (RFC 9116): fields, expiry and location

security.txt tells someone who found a vulnerability where to report it. RFC 9116 requires two fields and one location. What goes in the file, the expiry rule most files break within a year, and how to check yours from outside.

security.txt, standardised in RFC 9116 in April 2022, is a plain-text file at /.well-known/security.txt that tells security researchers how to report a vulnerability. It must be served over HTTPS as text/plain and must contain at least one Contact field and exactly one Expires field; the RFC recommends Expires be less than a year in the future. Optional fields are Encryption, Acknowledgments, Preferred-Languages, Canonical, Policy and Hiring. The file may be OpenPGP-signed. An expired file should be treated as stale, so the most common failure is a correct file that nobody renewed.

When someone finds a security problem on a website, the hardest part of reporting it is often finding who to tell. Generic contact forms go to sales, social accounts go unread, and the report stalls. security.txt fixes that with a small file in a fixed location that names the right contact. It costs minutes to publish and is one of the few security measures a site can show to anyone who checks. This guide covers what RFC 9116 requires, the optional fields worth adding, the expiry rule, and how to verify the file as an outsider would.

An RFC 9116 security.txt, field by field/.well-known/security.txtContact: mailto:security@example.comREQUIRED, one or moreExpires: 2027-09-30T00:00:00ZREQUIRED, once, < 1 year outPreferred-Languages: enoptionalCanonical: https://example.com/.well-known/security.txtoptional, recommended if signedPolicy: https://example.com/securityoptionalServed over HTTPS as text/plain; charset=utf-8. A file past its Expires date should be treated as stale.

Where the file goes #

The canonical location is /.well-known/security.txt, served over HTTPS with Content-Type: text/plain; charset=utf-8. The RFC also allows a copy at the top-level path /security.txt for older tools, typically as a redirect to the well-known location. Each host needs its own file or a redirect to the one that applies, because a researcher who finds a problem on shop.example.com will look there first. Serving the file as HTML, or behind a bot challenge that answers with status 200, makes it unreadable to the tools that check for it.

The fields #

FieldRequiredWhat it says
Contactyes, one or morea mailto:, https: or tel: URI to report to, in order of preference
Expiresyes, exactly oncedate and time after which the file should be considered stale, in ISO 8601 form
Encryptionnowhere to find a key for encrypting the report
Acknowledgmentsnoa page thanking past reporters
Preferred-Languagesnolanguages the team reads, as language tags
Canonicalnothe URI or URIs where this file is meant to live; important when the file is signed
Policynothe disclosure policy: scope, safe harbour, what to expect after reporting
Hiringnosecurity job openings

Lines starting with # are comments. Field names are case-insensitive. The whole file can be wrapped in an OpenPGP cleartext signature, in which case a Canonical field is what stops a valid signed file from being copied to another site and passed off as that site's.

The expiry rule #

Expires is required precisely so that abandoned files stop being trusted. The RFC recommends a value less than a year ahead. The consequence is that every security.txt needs renewing on a schedule, and a file published once and forgotten becomes formally stale within a year. That is the most common defect in practice: correct contact, correct location, expired date. Put the renewal in the same calendar as certificate and domain renewals, or generate the file from code with a rolling expiry. Ours reads:

Contact: mailto:hello@crawlcheck.io
Expires: 2027-09-24T00:00:00.000Z
Preferred-Languages: en
Canonical: https://crawlcheck.io/.well-known/security.txt
Policy: https://crawlcheck.io/security

Making the contact work #

A security.txt is only as good as the inbox it points to. Use an address that a person reads, not a ticketing queue that auto-closes, and test it by sending a message from outside the organisation. We found the hard way that an alerting address on our own domain had no mailbox behind it for five days, which we wrote up in five days of alerts to an address with no mailbox. If the address is on your own domain, make sure the domain's mail authentication will not reject replies; the DMARC side of that is in moving DMARC to quarantine.

Checking it from outside #

Request https://yourdomain/.well-known/security.txt from a network you do not control, with a plain client such as curl, and confirm four things: status 200, content type text/plain, a Contact line, and an Expires date in the future but less than a year away. Then check the top-level /security.txt path redirects to it or returns the same content, and repeat for each host you operate. The other security signals a scanner can read from outside, including HSTS and CSP, are listed on our security page and in the trust centre.

The Policy field points at a page explaining what happens after someone reports. It does not need to be long. State what is in scope, such as the main site and its subdomains, and what is out of scope, such as third-party services the site uses. Say how quickly you will acknowledge a report and roughly how quickly you aim to fix confirmed problems. Say that you will not pursue legal action against good-faith research that stays within the scope and avoids accessing other people's data, and ask reporters not to disclose publicly until a fix is in place or a stated period has passed. If you do not pay bounties, say so plainly; reporters prefer a clear no to silence.

Keep the policy and the contact address consistent with what the business can actually do. A one-person business promising a 24-hour response it cannot meet loses trust faster than one promising a week and meeting it.

Common mistakes #

Beyond expiry, four mistakes recur: a Contact line with a bare email address instead of a mailto: URI; the file served as HTML by a CMS that routes unknown paths to a page template; a file present on the main domain but missing on the subdomain where the vulnerability was found; and an Encryption field pointing to a key that expired or was revoked. Each makes the file harder to use exactly when someone is trying to use it.

What it does not do #

security.txt does not protect anything by itself, and its presence is not evidence that a site is secure. It shortens the path from discovery to a report reaching someone who can act. For a small business that has never received a vulnerability report, that is still worth five minutes, because the alternative is a researcher giving up or posting publicly.

Every figure above came out of this scanner.

Point it at your own domain and see the same measurements, free.

Scan a domain — free

The main product

Found this on your own site? We fix it for $749.

Scan free to see where you stand. The fix is one site, every finding implemented and re-measured, with a sealed before and after.

Questions this post answers

What is security.txt?

A plain-text file, standardised in RFC 9116, that tells security researchers how to report a vulnerability in a website.

Where should security.txt be located?

At /.well-known/security.txt, served over HTTPS as text/plain. A copy or redirect at /security.txt is allowed for older tools.

Which fields are required in security.txt?

At least one Contact field and exactly one Expires field. Everything else is optional.

How far ahead should Expires be set?

RFC 9116 recommends less than a year in the future. After the date passes, the file should be treated as stale.

Should security.txt be signed?

It may be signed with an OpenPGP cleartext signature. If it is, include a Canonical field so the signed file cannot be reused on another site.

Does having security.txt make a site secure?

No. It only tells people where to report problems. It shortens the path from discovery to a fix.

Related findings

How anything measured in this article was measured15client identitiesone second, one address5machine filesapex and www114named agentsresolved from robots.txt24sections scoredreach, read, quoteHow anything measured here was measured15 client identities5 machine files114 named agents24 sections scoredone second, one addressapex and wwwresolved from robots.txtreach, read, quote
No account, nothing installed, and the same sequence on every domain — which is what makes one scan comparable to another. Run it on your own site.

Comments

Comments are read before they appear. Nothing is published automatically, and no account is needed.

Writing about this? Facts, live figures and marks — every number on that page is dated and traceable to a scan.

All guides · The dataset · How the dataset works