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
FieldRequiredRepeatableValue
Contactyesyesmailto:, tel: or https:// URI to report issues to
ExpiresyesnoRFC 3339 timestamp after which the file is stale
EncryptionnoyesWhere to find the key for encrypted reports
AcknowledgmentsnoyesPage thanking researchers ("hall of fame")
PolicynoyesVulnerability disclosure policy
Preferred-LanguagesnonoComma-separated language tags
CanonicalnoyesThe URI(s) this file is supposed to be served from
HiringnoyesSecurity-related job openings
CSAFnoyesLink 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
• Generator — securitytxt.org has a form that builds a valid file from your inputs.
• 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.