security.txt
7 min read
security.txt is a small plain-text file a website publishes to tell security researchers how to report vulnerabilities. It is the security counterpart of robots.txt: a well-known, machine-readable location that answers "who do I contact about a security problem on this site?". Without it, researchers who find a vulnerability often have no reliable disclosure channel and end up mailing generic support addresses or giving up.
The format is standardized as RFC 9116 (April 2022, Informational). It is recommended by, among others, the US CISA, the UK government, the Dutch, French and Italian governments and the Australian Cyber Security Centre, and is published by sites such as Google, Facebook and GitHub.
Location
The file lives under the well-known URI path of a domain:
https://example.com/.well-known/security.txt
• It must be served over HTTPS (HTTP/1.0 or later). A file fetched over plain HTTP should not be trusted.
• Content-Type must be text/plain with charset=utf-8.
• For legacy compatibility it may also be placed at the root (/security.txt), ideally as a redirect to the /.well-known/ one. If both exist, the /.well-known/ file takes precedence.
Scope
A security.txt applies only to the host it was fetched from — the exact domain or IP address. It does not cover subdomains or parent domains: https://example.com/.well-known/security.txt says nothing about api.example.com, which needs its own file (or a redirect to a shared one). A file may, however, state that it also covers the organization's products and services.
Format
The file is a list of Field: value lines, one field per line:
• Lines end with LF or CRLF.
• Field names are case-insensitive.
• Lines starting with # are comments; blank lines are allowed.
• Web URIs in any field must start with https://.
• Unless noted otherwise, each field has a single value; multiple values are expressed by repeating the field, not by chaining values on one line.
• Consumers must ignore fields they don't understand, which keeps the format extensible.
Fields
| Field | Required | Repeatable | Value |
|---|---|---|---|
Contact | yes | yes | mailto:, tel: or https:// URI to report issues to |
Expires | yes | no | RFC 3339 timestamp after which the file is stale |
Encryption | no | yes | Where to find the key for encrypted reports |
Acknowledgments | no | yes | Page thanking researchers ("hall of fame") |
Policy | no | yes | Vulnerability disclosure policy |
Preferred-Languages | no | no | Comma-separated language tags |
Canonical | no | yes | The URI(s) this file is supposed to be served from |
Hiring | no | yes | Security-related job openings |
CSAF | no | yes | Link to a CSAF provider-metadata.json |
Contact
Where to send vulnerability reports. This is the only field that really matters, and it is required. It can appear multiple times; entries are listed in order of preference, the first being the preferred channel.
Contact: mailto:security@example.com
Contact: tel:+1-201-555-0123
Contact: https://example.com/security-contact.html
A web form or contact page is a valid alternative to an email address — useful when publishing a plain address would just attract spam.
Expires
When the content should be considered stale and not relied upon anymore. Required, exactly once. The RFC recommends setting it less than a year in the future, so the file is re-reviewed regularly and a forgotten file doesn't send reports to a long-gone mailbox.
Expires: 2027-09-01T00:00:00.000Z
Encryption
Points to the key researchers should use to encrypt their report — typically an OpenPGP key (see GPG). It must be a reference to a key, never the key material itself.
Encryption: https://example.com/pgp-key.txt
Encryption: dns:5d2d37ab76d47d36._openpgpkey.example.com?type=OPENPGPKEY
Encryption: openpgp4fpr:5f2de5521c63a801ab59ccb603d49de44b29100f
Acknowledgments
A page recognizing researchers who reported vulnerabilities.
Acknowledgments: https://example.com/hall-of-fame.html
Policy
The vulnerability disclosure policy: what is in scope, how reports are handled, response times, safe-harbor terms, bug bounty details.
Policy: https://example.com/disclosure-policy.html
Important
The presence of a security.txt does not grant permission to test the site. Whether and how testing is allowed is determined solely by the linked policy.
Preferred-Languages
Languages the security team prefers for reports, as RFC 5646 tags. Appears at most once; the values are comma-separated and their order carries no meaning. If absent, English is assumed.
Preferred-Languages: en, de, fr
Canonical
The URI(s) where this exact file is meant to be served from. Mainly relevant for signed files: without it, a valid signed file could be copied to a different site and still verify. If the file contains Canonical fields and the URI it was actually fetched from isn't one of them, its contents should not be trusted.
Canonical: https://example.com/.well-known/security.txt
Canonical: https://www.example.com/.well-known/security.txt
Hiring
Security-related job openings at the organization.
Hiring: https://example.com/jobs.html
CSAF
Not part of the original RFC; registered later in the IANA registry by OASIS for the Common Security Advisory Framework. Points to the organization's CSAF provider-metadata.json, so tooling can find machine-readable security advisories.
CSAF: https://example.com/.well-known/csaf/provider-metadata.json
Extension fields
New fields are registered in the IANA security.txt Fields registry (Expert Review). Any registered extension field is optional, and parsers ignore fields they don't support.
Example
# Our security address
Contact: mailto:security@example.com
Contact: https://example.com/report-vulnerability
# Our OpenPGP key
Encryption: https://example.com/pgp-key.txt
# Our security policy
Policy: https://example.com/security-policy.html
# Our security acknowledgments page
Acknowledgments: https://example.com/hall-of-fame.html
Preferred-Languages: en, de
Canonical: https://example.com/.well-known/security.txt
Hiring: https://example.com/jobs.html
Expires: 2027-09-01T00:00:00.000Z
Digital Signature
The file should be signed with an OpenPGP cleartext signature (RFC 4880 §7) so researchers can verify it hasn't been tampered with. A signed file should always include a Canonical field, since the signature authenticates the content but not the location it's served from.
sh
# sign
gpg --clearsign --output security.txt security.txt.unsigned
# verify (researcher side)
curl -s https://example.com/.well-known/security.txt | gpg --verify
The result looks like:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Canonical: https://example.com/.well-known/security.txt
Contact: mailto:security@example.com
Encryption: https://example.com/pgp-key.txt
Expires: 2027-09-01T00:00:00.000Z
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCgAdFiEE...
-----END PGP SIGNATURE-----
A valid signature only proves the file was signed by that key — the researcher still has to decide whether the key actually belongs to the organization.
Serving it
Any static file will do. Examples:
nginx
location = /.well-known/security.txt {
alias /var/www/security.txt;
default_type text/plain;
charset utf-8;
}
# legacy location → redirect
location = /security.txt {
return 301 /.well-known/security.txt;
}
caddyfile
example.com {
handle /.well-known/security.txt {
header Content-Type "text/plain; charset=utf-8"
root * /var/www
rewrite * /security.txt
file_server
}
redir /security.txt /.well-known/security.txt 301
}
Check it:
sh
curl -sI https://example.com/.well-known/security.txt # status + Content-Type
curl -s https://example.com/.well-known/security.txt
Security Considerations
Points from RFC 9116 §5 worth keeping in mind — both when publishing and when consuming a file:
• Compromised files — an attacker controlling the site could swap the contact address to intercept reports. Signing + Canonical mitigate this; researchers can also compare against historical copies.
• Redirects — researchers should note where a redirect leads before trusting the target, especially cross-domain.
• Stale data — outdated contacts send sensitive reports to the wrong people. That's what Expires is for; keep it short and actually update the file.
• Malformed / hostile files — parsers should reject files larger than 32 KB, fields longer than 2048 characters or files with more than 1000 lines.
• No testing permission — neither the presence nor the absence of the file authorizes or forbids testing.
• Multi-tenant hosting — on shared platforms (user pages under one domain), the operator should reserve /.well-known/security.txt so tenants can't publish a fake one for the whole domain.
• Transport — fetch the file and all referenced URIs over HTTPS and validate certificates.
• Spam — publishing an address will attract automated low-quality "beg bounty" reports; plan triage accordingly. Using a web form as Contact can help.
• Vulnerability vs. incident response — the file is meant for reporting vulnerabilities, not as a channel for active incident response.
Tooling
• Validation — internet.nl checks for a valid security.txt as part of its website test; many recon/scanner tools (e.g. nuclei templates) look for it too.
• Recon — for researchers, the file is the first place to look before reporting; some sites link a bug bounty program via Policy.