security.txt expire
Most conformance rules are static. You fix the file once, and it stays fixed until somebody
edits it. Expires is not like that: it is a date, so a file that passes every check
today fails on its own — with no commit, no deploy, and nothing in any log to point at.
That is not an oversight in the specification. It is the specification's main idea.
Before RFC 9116, the worst outcome for a published disclosure contact was not a missing file.
It was an abandoned one. A security.txt published in 2019, naming an
address that stopped being monitored in 2021, gives a researcher every reason to believe they
have reached the right place — and no way at all to tell that they have not. They send the
report, they wait, they hear nothing, and eventually they conclude you do not care. From your
side, nothing happened, because nothing arrived.
A mandatory expiry date makes that staleness explicit. After the date, the file is no longer vouching for itself, and a consumer knows to stop trusting it rather than having to infer abandonment from silence.
RFC 9116 states that data in an expired file must be considered stale and should not be
used. So to a conforming researcher or automated consumer, an expired
security.txt publishes nothing at all. A person holding a real finding falls back
to whatever else they can find — a support form that routes to billing, a public issue tracker,
a social post, or nobody.
Meanwhile: the server returns 200. The text still reads correctly to a human. Every uptime check, every link checker, and every deploy pipeline you have stays green. This failure has no symptom on your side, which is exactly why it is worth checking deliberately.
The RFC recommends less than a year ahead. Two competing pressures decide where inside that range you land:
The way out of that trade-off is not a cleverer date, it is automation. If a scheduled job checks the file, the expiry length stops being a bet on your own memory:
node check.mjs example.com # exit 1 once Expires has passed
That is the one check in this catalogue genuinely worth putting on a schedule rather than in a per-commit pipeline, because the thing that changes is the calendar, not the code.
Expiry is the most common, but it shares a shape with the rest of the quiet ones: they are all legal-looking text that a conforming parser simply ignores.
Acknowledgements with the middle "e"
The RFC field is Acknowledgments. The British spelling is not a recognised field,
and RFC 9116 says consumers must ignore fields they do not recognise — so the hall-of-fame page
you are pointing at is simply never found. No error, no warning, nothing.
Contact
Contact is defined as a URI field. security@example.com is not a URI;
mailto:security@example.com is. A consumer that resolves URIs will skip the first
one, and a human reading the file will not notice the difference.
RFC 9116 is explicit that keys must not appear in security.txt —
Encryption takes a URI that points at one. An inline PGP block also breaks the
line-oriented format for every field after it, so it tends to take the rest of your file down
with it.
Canonical
A cleartext signature proves the text is yours. It does not prove where the text was meant to
live, so a signed file copied to another host verifies just as well. Canonical is
what closes that gap, which is why the RFC says to use it when the file is signed.
Because the failure mode the format had before it was an abandoned file that still looked authoritative. A security.txt published in 2019 naming an address that stopped being monitored in 2021 gives a researcher every reason to believe they have reached the right place, and no way to tell they have not. A mandatory expiry date makes staleness explicit rather than invisible: after that date, a conforming consumer knows the file is no longer vouched for, instead of guessing from a timestamp nobody publishes.
RFC 9116 says data in an expired file must be considered stale and should not be used. In practice that means a conforming researcher or automated consumer treats you as publishing no disclosure contact — so a person holding a real finding falls back to whatever they can find: a support form, a public issue tracker, a social post, or nothing. The server keeps returning 200, the text still reads correctly to a human, and no monitoring you have will notice.
RFC 9116 recommends less than a year into the future. A shorter value is a stronger claim — it says someone looked at this recently — and a very long one gives away most of the benefit, since the point is to force a periodic re-check rather than to be a formality. The practical answer is to pick a period you will actually honour and automate the renewal, because a date chosen to avoid maintenance is a date that will pass unnoticed.
The quiet ones share a shape: they are legal-looking text a conforming parser ignores. "Acknowledgements" with the middle e is not the RFC field name, so the page it points at is never found. A bare email address in Contact is not a URI, so a consumer that resolves URIs skips it. An unknown field name must be ignored by conforming parsers, per the RFC, so anything you invented does nothing. None of these produce an error anywhere — the file parses, serves, and under-delivers.
Check your own file: security.txt Checker. See also: how this differs from securitytxt.org's generator and validator.