Skip to content

security.txt and security@: how a small SaaS gets security reports

A security.txt file at /.well-known/security.txt tells researchers where to report a vulnerability. Add Contact and Expires, then route security@ to people.

Koltrix Team5 min read
A silver padlock against a plain background
Photo by Zaqy Al Fattah on Unsplash
On this page(9 sections)
  1. What is security.txt?
  2. What goes in the file?
  3. Why does Expires matter so much?
  4. Do you need to sign it?
  5. What should security@ be?
  6. How do you triage a report?
  7. What should your policy page promise?
  8. How do you publish and check it?
  9. Bottom line

Sooner or later a stranger will find a hole in your product and try to tell you about it. If they cannot find who to tell, they either give up, post it publicly, or send it to your support inbox where it sits behind a pile of password-reset questions. Two small things fix most of that: a security.txt file on your website and a security@ mailbox that someone actually reads.

What is security.txt?

security.txt is a plain text file, defined in RFC 9116, that tells security researchers how to contact you about a vulnerability. It lives at https://yourdomain.com/.well-known/security.txt, is served over HTTPS as text/plain in UTF-8, and has two required fields: Contact and Expires. Everything else is optional.

The idea is the same as robots.txt: a predictable location, so a researcher or an automated scanner does not have to guess. It does not make you responsible for anything new. It only says where to send a report.

What goes in the file?

Start with the smallest file that is valid, then add fields only when you can keep them true.

# Report vulnerabilities to the address below. Thank you.
Contact: mailto:[email protected]
Expires: 2027-09-30T23:59:00.000Z
Preferred-Languages: en
Canonical: https://example.com/.well-known/security.txt
Policy: https://example.com/security
Field Required What it does
Contact Yes Where to report. Use a URI: mailto:, tel: or an https: page. List several in order of preference.
Expires Yes, once When the file goes stale, as an RFC 3339 date. RFC 9116 recommends less than a year ahead.
Policy No Link to your disclosure policy: scope, what you promise, what you ask.
Canonical No The URL where this file should be found. Useful when the file is signed.
Preferred-Languages No Comma-separated language tags. English is assumed if missing.
Encryption No A link to a public key, never the key itself.
Acknowledgments No A page that credits researchers.
Hiring No A link to security jobs.

Why does Expires matter so much?

Expires tells a researcher when the information may no longer be accurate. A file that expired two years ago says "nobody maintains this", which is the opposite of what you want to signal. Put a calendar reminder about a month before the date, change it to a new date less than a year out, and check at the same time that the address still reaches a person.

Do you need to sign it?

RFC 9116 recommends an OpenPGP cleartext signature, and says that if you sign, you should also list Canonical. For a small team this is a nice-to-have, not a starting requirement. A signature only helps if you also publish the key somewhere a researcher can verify, and a stale key is worse than none. Ship the unsigned file first. Add signing when you have someone who will own the key.

What should security@ be?

security@ is a conventional role mailbox for security reports. RFC 2142 lists it as the standard address for security bulletins and enquiries, so researchers will often try it even without a security.txt. Treat it as a shared mailbox, not as one person's inbox.

A few practical rules:

  1. Make it a real address on your own domain. Do not point Contact at a personal Gmail account. People leave, and reports go with them.
  2. Give at least two people access. One person on holiday should not mean a week of silence. Our post on auditing access to a shared mailbox covers who should be able to read it.
  3. Do not let spam filters eat it. Role addresses attract junk, and some reports arrive as odd attachments or links. Check the junk folder weekly for the first month.
  4. Keep it out of automation that replies for you. A generic "we have received your ticket" is fine. A canned "this is not a bug" is not.

If you are still deciding which role addresses to run, role addresses like info@ and admin@ explains how they behave at other providers.

How do you triage a report?

Most reports are not critical. Many are automated scanner output, such as a missing header on a static page. A few are real and urgent. A simple routine keeps you calm and fair to the person who wrote in.

Within one business day: acknowledge. Say thank you, say who is looking, and say when they will hear next. You do not need to agree it is a bug.

Within a few days: reproduce. Try to repeat what they describe in a test environment, not on customer data. If you cannot, ask a specific question.

Then classify. A short table is enough:

Question If yes
Can someone read or change another customer's data? Treat as urgent. Fix first, then investigate scope.
Does it need an unlikely setup or an already-compromised account? Fix in normal planning, tell the reporter.
Is it a scanner finding with no real impact? Reply politely, explain why, close it.
Is the reporter asking for money before telling you anything? Reply once with your policy, do not negotiate.

Keep the reporter informed. Tell them when it is fixed. If you have an acknowledgments page, ask before you name them.

Phishing and spoofing reports are a separate pile: if someone says they got a fake email that looks like it came from your domain, that is often an email spoofing problem for your DMARC setup, not a bug in your app.

What should your policy page promise?

You do not need a legal document. A one-page policy that you can keep is better than a long one you cannot. Say:

  • what is in scope (your app, your API, your marketing site) and what is not;
  • that you will reply within a stated number of working days, and a number you can actually meet;
  • that testing against other customers' accounts or data is not allowed;
  • how you want reports sent, and in what level of detail;
  • that you will not take action against good-faith research that follows the rules. Check this one with whoever advises you on legal matters before you publish it, because it is a commitment.

Do not promise a bounty unless you have a budget. "We cannot pay rewards, but we will credit you" is honest and common.

How do you publish and check it?

  1. Create the file and serve it from /.well-known/security.txt on your main domain. Many static hosts need a rule so a path starting with a dot is not hidden.
  2. Open https://yourdomain.com/.well-known/security.txt in a browser. It should show plain text, not a download or an HTML page.
  3. Check the response header is Content-Type: text/plain; charset=utf-8.
  4. Send a test message to the Contact address from an outside account and confirm that two people receive it.
  5. Add a reminder for the Expires date.

Bottom line

A security.txt file is about ten lines of text and one shared mailbox. Put Contact and Expires at /.well-known/security.txt, route security@ to at least two people, answer within a day, and keep the file current. That is enough for a small SaaS to be reachable by the people who find problems, long before a formal security program exists.

Start with Koltrix

Your domain, one inbox, and an API that sends.

A team inbox where AI sorts and drafts (nothing is sent without your click), plus the transactional API and SMTP relay your product sends with. 7 days free, no card.

SharePost on XLinkedIn
More in Guides →