Website problems

No security.txt file

`security.txt` is a plain-text file at `/.well-known/security.txt` that tells anyone who finds a security problem how to report it. It is specified in RFC 9116, and its absence means a researcher with a genuine finding has to guess — a support form, a generic address, a social media account — and many will give up or disclose publicly instead. It costs nothing to publish and it is the difference between learning about a problem privately and reading about it.

What the file contains

`Contact:` is the only required field, and it may repeat. A `mailto:` address, a URL to a reporting form, or a telephone number, in order of preference.

`Expires:` is also required. It is a timestamp after which the file should no longer be considered current, which forces the contents to be reviewed rather than left to rot.

`Encryption:` points at a public key so a report can be sent encrypted.

`Policy:` links to your disclosure policy — what is in scope, what you ask of reporters, what they can expect.

`Acknowledgments:` links to a page thanking people who have reported, which costs nothing and materially increases the number of reports you get.

`Preferred-Languages:` lists the languages your team reads, which prevents a report being written in one nobody can act on.

The Expires field, and why it is required

It was made mandatory because the predictable failure of this file is abandonment: a contact address for someone who left, a policy link that 404s, a file nobody has read in four years.

An expired file is worse than none, because a reporter follows it, receives no reply, and concludes the organisation does not care — having done exactly what was asked.

The specification recommends a value less than a year in the future, which turns the file into a recurring review rather than a one-off publication.

So the maintenance obligation is the point, not an overhead. A file with a fresh `Expires` is a statement that someone checked recently.

Where it goes and how it is served

`/.well-known/security.txt` is the canonical location. A copy at the root is permitted for legacy reasons and the well-known path is the one that should exist.

It must be served over HTTPS, as `text/plain`, with a `charset` of `utf-8`.

A common mistake is serving it as `text/html` because the web server guesses the type from a missing extension, which makes it non-conforming.

The file may be signed with an OpenPGP signature, which lets a reporter verify it was published by you rather than by someone who compromised the site.

For a site with several domains, each one needs its own file, since a reporter looking at one domain will not think to check another.

What it must not contain

Anything that is not a contact route. The file is public, indexed, and fetched by every scanner on the internet.

Internal hostnames, ticketing URLs behind a VPN, staging addresses, or the names of internal systems.

Personal contact details of individuals rather than a role address. People change roles; the address should not.

Anything resembling a credential, including links containing tokens.

And it must not promise more than the organisation will deliver. A policy stating a 24-hour response that nobody honours produces exactly the disappointment the file was meant to avoid.

How to check it yourself

`curl -I https://example.com/.well-known/security.txt` — a 200 with `Content-Type: text/plain; charset=utf-8` is correct.

`curl -s https://example.com/.well-known/security.txt` and read it. Confirm `Contact` and `Expires` are present and that `Expires` is in the future.

Follow every URL in the file. A `Policy` link that 404s is the most common defect in a file that otherwise exists.

Send a test report to the contact address and see whether it reaches someone. A valid file pointing at an unmonitored inbox passes every automated check and fails the only test that matters.

How VeriFixScan detects it

`exposure.security_txt.present` requests the file at the well-known location and reports whether it exists and is served correctly.

`exposure.security_txt.fields` reports the fields it contains, `exposure.security_txt.expired` reports whether the `Expires` timestamp has passed, and `exposure.security_txt.policy` reports whether a policy is linked.

`exposure.security_txt.location` reports where the file was found, since a file only at the root rather than under `/.well-known/` is a partial implementation.

The checks read a public file. Whether the contact address is monitored is not observable from outside, and the report says so.

Frequently asked questions

Where exactly should security.txt live?
At /.well-known/security.txt, served over HTTPS as text/plain with a utf-8 charset. A copy at the web root is allowed for legacy reasons but is not the canonical location.
Why is the Expires field mandatory?
Because the predictable failure of this file is abandonment. An expiry date forces periodic review, and RFC 9116 recommends a value less than a year ahead.
Do I need a bug bounty to publish one?
No. The file states how to report a problem. A policy explaining that you accept reports and do not pay for them is a complete and honest policy.

Sources

Related

VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.

Scan a website