skip to content

What is an RFC 9116 security.txt file, and where must it be served?

level: juniorimportance: should knowfreq 52%

answer

  1. a signpost, not permission
  2. well-known path, over HTTPS
  3. plain text, two required fields
  4. a contact URI plus a shelf life
  5. lapsed date reads as abandoned

basics

~20 s

security.txt is a plain-text file, standardised by RFC 9116, that tells a researcher how to report a vulnerability to you. Serve it over HTTPS at /.well-known/security.txt with at least one Contact URI and an Expires date.

solid answer

~50 s

RFC 9116 standardises the one place a researcher looks before they give up and go public. It is a plain-text file, `text/plain; charset=utf-8`, served over HTTPS at `/.well-known/security.txt`. Two fields are mandatory: `Contact`, one or more URIs (a `mailto:`, an `https:` reporting form, a `tel:`) listed in order of preference, and `Expires`, a single timestamp after which the content should be considered stale. Useful optional fields include `Policy` (a link to the full disclosure policy), `Encryption` (a key for encrypted reports), `Preferred-Languages`, `Acknowledgments` and `Canonical`, which lists the URIs where the file legitimately lives so a copy planted elsewhere is detectable. Put it on every host a researcher might actually try — the marketing site, the API host, the status page — because people check the host they found the bug on. It is a signpost, not permission to test.

go deeper

for a junior

Be ready to say what the file is for, name the well-known HTTPS location, and recall that Contact and Expires are the two required fields.

for a middle

Explain the optional fields you would actually use and why: Policy to link the real policy, Encryption for reports containing exploit steps, Canonical to make a planted copy detectable.

for a senior

Show you have run this: which hosts carry the file, who drains the inbox, and the calendar owner for the Expires renewal. Treat an expired file as an incident-shaped process failure, not a typo.

for a principal

An interviewer expects you to argue why being reachable is a cheap risk transfer: the alternative to a maintained contact is learning about your bugs from a conference stage with no fix ready.

## The problem it solves Someone has found a flaw in your product and wants to tell you. They try `security@`, which bounces. They open a support ticket and get a reply about billing. They message whoever is loudest on social media. After a few weeks of silence a reasonable person concludes nobody is home, and their remaining options are to drop it, sell it, or talk about it in public. That failure mode is not hypothetical, and it is worst where the asset is physical safety rather than data. Picture a vendor of connected insulin pumps with no published security contact. A researcher who physically owns one of the devices finds a flaw in its pairing handshake, spends three months trying to reach someone, gets nothing, and eventually presents it from a conference stage — because a talk is the only channel that has ever produced a response. The vendor then learns about its own bug at the same moment as everyone else, with no fix ready and no advisory drafted. A findable contact would not have fixed the pump, but it would have bought the months the vendor spent being unreachable. ## The file RFC 9116 defines `security.txt` so that the answer to "where do I report this" is mechanical. Key properties: - **Location.** For a web host, the file belongs at `/.well-known/security.txt`, served over **HTTPS**. A top-level `/security.txt` exists only as legacy compatibility; the well-known path is the one automated tooling and experienced researchers check. - **Format.** Plain text, UTF-8, one `Field: value` per line, `#` for comments. - **`Contact`** — **required**, and it must be a URI, not a bare address: `mailto:[email protected]`, `https://example.com/report`, or a phone URI. List more than one in priority order. - **`Expires`** — **required**, exactly one, a timestamp after which the information should not be trusted. This is the field teams forget, and it is the point of the whole design: an unmaintained file is a trap, so the format forces you to declare a shelf life. Set it within a year and diary the renewal. - **`Policy`** — the link to your written disclosure policy. `security.txt` says *who to tell*; the policy says *what is in scope and whether testing is authorised*. - **`Encryption`** — a URI for a key, so a reporter can encrypt a report that contains working exploit steps. - **`Canonical`** — the URIs at which this file is expected to be found. If you publish the file on three hosts, list all three; a reader who finds the file somewhere not listed knows to be suspicious. - **`Acknowledgments`**, **`Preferred-Languages`**, **`Hiring`**, **`CSAF`** — optional extras. The file may be signed with an OpenPGP cleartext signature; signing is recommended, not required for validity. ## Placement is a real decision A payments company typically has a marketing domain, a separate API domain and a status page, often on different infrastructure with different owners. A researcher poking at the API host checks that host. Someone who found a flaw in the sign-up flow checks the marketing domain. If the file exists only on the domain the security team happens to control, the people most likely to find something interesting will never see it. Publish on each host, keep the `Contact` pointing at the same monitored destination, and use `Canonical` to tie the copies together. Point `Contact` at something a human drains on a schedule. A shared mailbox with a named owner and a rota beats a generic support queue where a report about session fixation gets triaged as a login problem and closed. ## What it does not do Three common misreadings: 1. **It is not authorisation.** Publishing a contact address does not tell a researcher that scanning your production API is permitted or that you will not sue them. That comes from the policy the `Policy` field links to, and specifically from its scope and safe-harbour sections. 2. **It is not a program.** The file is discovery plumbing. Behind it you still need an owner, a triage path and a way to get a fix out. 3. **A stale file is worse than none.** An `Expires` date that passed eighteen months ago is a public signal that the program was abandoned. A researcher reading it will reasonably conclude the fastest route to a fix is publicity or a broker. The cost of getting this right is a text file and a calendar reminder. The cost of getting it wrong is learning about your vulnerabilities from an audience.

  • Your product, marketing site and API are on three different domains. Where does the file go?
    On all three. Researchers check the host they were poking at, not the one your security team owns. Keep the `Contact` values identical so every copy routes to the same monitored inbox, and list every URI in `Canonical` so a reader can tell a legitimate copy from one planted on a look-alike host.
  • What does a lapsed Expires date tell a researcher?
    That the information is stale and probably the program with it. RFC 9116 makes `Expires` mandatory precisely so an abandoned file announces itself. A researcher who sees a date from two years ago has good reason to believe nobody will answer, which pushes them toward public disclosure. Set it inside a year and treat renewal as an owned task.
  • Does publishing security.txt authorise anyone to test your systems?
    No. It only says where to send a report. Authorisation to test, the list of in-scope assets and any promise not to pursue legal action all live in the written disclosure policy that the `Policy` field points to. A researcher reading only the file has a contact address and no assurance at all.

It is the fire-exit sign of a website: cheap, boring, and the only thing that matters to the one person who urgently needs it.

saying these in an interview costs you the question

  • Thinks publishing security.txt authorises testing
  • Publishes it only on the marketing domain
  • Leaves Expires absent or years in the past
  • Points Contact at a general support queue nobody triages
  • Believes the file is invalid unless OpenPGP-signed

context