Skip to content
TRIAGERS™
Deep Dives · 6 min read · TRIAGERS™ Team

security.txt Guide: RFC 9116 Fields, Hosting, and Common Mistakes

A practical security.txt (RFC 9116) guide: annotated example file, field-by-field explanation, where to host it, and the mistakes that break it.

security.txt is the smallest useful thing a company can do for its security intake: a plain text file that tells a researcher who found a bug where to send it. No more guessing between security@, a support form, and a LinkedIn DM to someone who left two years ago. It's defined by RFC 9116, it takes ten minutes to write, and a surprising number of the ones in the wild are broken in ways that quietly defeat the point.

This is the file, the fields, where it goes, and the mistakes that make it useless.

What it is

security.txt is a text file served at a well-known path on your domain. A researcher (or their tooling) fetches it to learn your disclosure contact and policy before reporting. It's the front door for vulnerability intake: it routes people to your VDP or bug bounty program.

It is not a security control and doesn't protect anything. It's signage. Good signage prevents the failure mode where a well-intentioned researcher can't find anyone to tell and either gives up or posts publicly.

A full annotated example

# Canonical security.txt for example.com
# https://example.com/.well-known/security.txt

Contact: mailto:[email protected]
Contact: https://example.com/security/report
Expires: 2026-12-31T23:59:59.000Z
Encryption: https://example.com/.well-known/pgp-key.txt
Acknowledgments: https://example.com/security/hall-of-fame
Preferred-Languages: en, de
Canonical: https://example.com/.well-known/security.txt
Policy: https://example.com/security/policy
Hiring: https://example.com/careers/security

Every line above is a real RFC 9116 field. Case matters for field names as written in the spec examples, and each directive is Field-Name: value on its own line.

Field by field

Contact: required. Where to send reports. Can be a mailto:, a tel:, or an https:// URL to a form. You can list several; order them by preference, most-preferred first. At least one Contact must be present or the file is meaningless.

Expires: required. An ISO 8601 timestamp after which the file's information should no longer be trusted. This is the field everyone forgets to maintain, and an expired security.txt is arguably worse than none: it signals the contact details may be stale. Set it 6–12 months out and put a calendar reminder to refresh it.

Encryption: optional. A link to your PGP key (or a fingerprint / OpenPGP URL) so reporters can encrypt sensitive details. Link to the key; don't paste the key inline. If you can't actually receive and decrypt PGP mail, don't advertise it.

Acknowledgments: optional, and yes, that US spelling is the spec. A link to your hall of fame / thanks page. Cheap goodwill.

Preferred-Languages: optional. Comma-separated language tags for the languages your team can handle reports in. It's a preference, not a promise, and doesn't imply the file itself is translated.

Canonical: optional but recommended. The canonical URI(s) where this file lives. It lets a reader confirm they're looking at the authoritative copy and not a mirror or a stale cache. If present, it should include the actual well-known URL.

Policy: optional. Link to your vulnerability disclosure policy or bug bounty program rules: scope, safe harbour, expectations. This is the bridge from "who do I tell" to "what are the rules."

Hiring: optional. Link to security job openings. A researcher poking at your site is a plausible hire; some of the best security hires started as external reporters.

Signature: optional, not shown above. You can sign the file with PGP and reference the signature via a companion .sig file, so readers can verify it hasn't been tampered with. Worth it for high-value targets; overkill for most.

Where to host it

The canonical location is:

https://example.com/.well-known/security.txt

Rules that trip people up:

  • It must be under /.well-known/. A legacy top-level /security.txt is tolerated by some tooling as a fallback, but the well-known path is the standard and where scanners look. Serve it at .well-known and, if you like, redirect the root path to it.
  • HTTPS is required. Serve it over https:// with a valid certificate. A security.txt fetched over plain HTTP doesn't meet the spec and can't be trusted.
  • Correct content type. Serve it as text/plain with UTF-8. If your server hands .txt files a text/html type or a download disposition, fix that.
  • Per-domain. It applies to the domain it's served on. Large orgs with many domains either serve it on each or use Canonical to point back to a central authoritative file.
GET /.well-known/security.txt HTTP/1.1
Host: example.com

HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8

Common mistakes

These are the ones we see over and over, in rough order of how often they defeat the file's entire purpose:

  1. Expired Expires field. The most common failure. The file was written once, in 2023, and its Expires passed a year ago. Compliant tooling now treats the whole file as untrustworthy. Set a reminder and refresh it.
  2. Wrong path. Sitting at /security.txt only, or /.well-known/security-txt, or behind a redirect chain that drops the well-known prefix. Put it at /.well-known/security.txt and confirm it returns 200.
  3. Contact that goes nowhere. A security@ alias no one reads, or a form that 404s. Test it. Send yourself a report through every Contact you list.
  4. Advertising Encryption you can't use. Linking a PGP key you've lost the private half of means encrypted reports you can't read. Only list it if you can decrypt.
  5. Served as HTML or over HTTP. A pretty HTML page at that path isn't a security.txt; a plain-HTTP one isn't trusted. Plain text, HTTPS, correct content type.
  6. No Policy link. Optional per the spec, but without it a reporter knows where to send but not whether they're safe doing so. If you have a VDP or program, link it.

How it fits with a VDP and bug bounty intake

Think of it as the outermost layer of intake:

  • security.txt answers "who do I contact, and where are the rules?"
  • The Policy it links to (your VDP) answers "what's in scope, what's safe harbour, what should I expect?"
  • Your bug bounty program (if you run one) is where reports land, get triaged, and get rewarded.

A researcher's path is security.txt → policy → submission → your triage queue. If the first link is broken or expired, the whole chain fails before anyone reads a report, and you're back to receiving vulnerabilities via Twitter. If you're standing up intake for the first time, security.txt is step one. The rest of the readiness work is in our program readiness checklist.


security.txt gets researchers to your door; what happens after (validating, reproducing, and responding well) is where a program earns its reputation. TRIAGERS™ runs on-demand triage teams that pick up where your intake path ends. If you've got the front door sorted and need hands on the queue behind it, get in touch.

Keep reading
The Triage Brief

New articles, straight to your inbox.

Practical triage writing, published a few times a month. Unsubscribe anytime.

Or grab the RSS feed.

Drowning in unread reports?

Lease an expert triage team that validates, reproduces and rates every submission, so your engineers only see signal.

Get a triage team