Skip to content

We use analytics cookies to see how the site is used. They are only set if you accept. Accepting also turns on session recording (pages viewed, clicks and scrolls) so we can fix problems; what you type stays hidden. It also lets Meta (Facebook) see your visit, so we can measure our ads. Read the privacy policy

A floor plan with a red you are here dot and three green dashed routes to exits labelled security.txt, SECURITY.md and report form.

Vulnerability report evacuation plan

security.txt, SECURITY.md and Private Reporting: Three Doors for the Person Who Finds Your Bug

Set up the three places a researcher looks before reporting a flaw in your tool: /.well-known/security.txt, a SECURITY.md file and GitHub private vulnerability reporting, with a fire drill to test them.

A researcher holding a bug, and the three ways out.

Read first plan legend

Why plan the exits now

The RFC behind security.txt says that having no file at all may be better than having a stale one, and that line explains the whole job. Someone who finds a flaw in your tool will look for a way to tell you privately. If the address bounces or the page is gone, many of them will post it in a public issue, or not report it at all.

A small tool needs three doors, each in the place a different kind of reporter looks: a file on your website, a file in your repository, and a private form on GitHub. Each one below has the exact text to copy, and the fire drill at the end tests that all three still open. Everything here was checked against RFC 9116 and GitHub's docs on 4 November 2026.

Exit 1 /.well-known/security.txt

A text file on your domain

RFC 9116 defines a plain text file that tells researchers how to reach you. Put it at https://example.com/.well-known/security.txt. The path must be under /.well-known/, the file must be served over HTTPS, and its Content-Type must be text/plain with a UTF-8 charset. A copy at the top level /security.txt is allowed for older tools, but when both exist the one under /.well-known/ wins.

# /.well-known/security.txt
Contact: mailto:[email protected]
Contact: https://github.com/example/tool/security/advisories/new
Expires: 2027-10-31T23:00:00.000Z
Policy: https://example.com/security
Preferred-Languages: en
Canonical: https://example.com/.well-known/security.txt

Only two lines are required. Contact must be present, and if you list several, the first is the one you prefer. Expires must appear exactly once, and the RFC recommends a date less than a year ahead. Every other field is optional.

Every field, and its rule

FieldNeededRule from RFC 9116
ContactRequiredA URI: mailto:, tel: or an https:// page. List in order of preference.
ExpiresRequired, onceAn RFC 3339 date and time. Less than a year ahead is recommended.
EncryptionOptionalA link to your key, never the key itself.
PolicyOptionalA link to your disclosure policy: scope, what you promise, what testing you allow.
AcknowledgmentsOptionalA link to a page thanking reporters.
Preferred-LanguagesOptional, onceLanguage tags such as en, de. Without it, English is assumed.
CanonicalOptionalThe URLs where this file lives. Recommended when you sign the file.
HiringOptionalA link to security job openings.

One file covers one host. Section 3.1 says it applies only to the domain it was fetched from, not to subdomains, so docs.example.com and app.example.com each need their own copy or a redirect.

Exit 2 SECURITY.md

A policy file in your repository

Most people who find a bug in a library never visit your website. They open the repository. GitHub calls this file a security policy: a SECURITY.md that says which versions you still support and how to report a vulnerability. You can start one from the repository's "Security and quality" tab, under "Security policy".

GitHub reads the file from three places, in this order: the .github folder, the repository root, then docs. If a repository has none, GitHub falls back to the file in your account's public .github repository, so one file can cover every project you own.

# Security policy

## Supported versions
| Version | Supported |
| ------- | --------- |
| 2.x     | yes       |
| 1.x     | security fixes until 2027-03-31 |
| < 1.0   | no        |

## Reporting a vulnerability
Please do not open a public issue.
Use "Report a vulnerability" on this repository's
Advisories page, or email [email protected].
We reply within 5 working days.

The reply time in that sample is a promise, so only write one you will keep. For a longer real example, GitHub's own docs point to the SECURITY.md of the Electron project.

Exit 3 Advisories page

A private report form on GitHub

Email works, but it leaves the reporter guessing what to include. Owners and admins of public repositories can turn on private vulnerability reporting under Settings, then Advanced Security, next to "Private vulnerability reporting". Researchers then see a "Report a vulnerability" button on the repository's Advisories page, and the report stays private between them and the maintainers.

By default the form asks for a summary, details, a proof of concept and an impact statement. GitHub's docs say the form can be changed with the same YAML syntax as issue forms, with fields you can mark as required. That structure saves the first round of "can you send steps to reproduce?" emails.

Point the other two doors here. The second Contact line in the security.txt above and the reporting section in the SECURITY.md both send people to /security/advisories/new, so the three exits meet in one room you already check.

Exit 4 fire drill

Fire drill: is this file valid?

Five short cases. Decide, then open each one to check against the RFC.

The file has a Contact line and a Policy line, and no Expires line. Valid?

No. Expires is required and must appear exactly once. Without it, a researcher cannot tell whether the contact is still current.

Contact: [email protected]. Valid?

No. Contact must be a URI, so an email address is written mailto:[email protected]. A phone number is written with tel:.

The file is served at http://example.com/.well-known/security.txt and nowhere else. Valid?

No. The file must be fetched over HTTPS. Serve it on https and redirect plain http to it.

Your file sits on example.com. Does it also cover api.example.com?

No. A security.txt applies only to the host it was fetched from, not to subdomains or parent domains.

Does publishing a security.txt mean anyone may scan or attack your site to find bugs?

No. The RFC says the presence or absence of the file grants or denies no permission to test. If you allow testing, say so, with limits, in the page your Policy field links to.

Exit 5 every 6 months

The drill to repeat

Doors that nobody tests stop opening. Put this list in your calendar twice a year, and also on the day a maintainer leaves.

  • Fetch /.well-known/security.txt over HTTPS and check it returns 200 and text/plain.
  • Move Expires forward so it stays under a year ahead. A file past its date is stale by its own rules.
  • Send a test mail to every mailto: Contact and confirm a person who is still on the team reads it.
  • Open the "Report a vulnerability" button on each public repository and check it is still enabled.
  • Read the supported versions table in SECURITY.md against your actual release lines.
  • If the file is signed, sign it again after every edit, and keep the Canonical URLs current.

Exit 6 sources

Sources

All four were read on 4 November 2026.