When the security team at Cloudflare takes on new projects, we approach them with the goal of achieving the “builder first mindset” whereby we design, develop, and deploy solutions just as any standard engineering team would. Additionally, we aim to dogfood our products wherever possible. Cloudflare as a security platform offers a lot of functionality that is vitally important to us, including, but not limited to, our WAF, Workers platform, and Cloudflare Access. We get a lot of value out of using Cloudflare to secure Cloudflare. Not only does this allow us to test the security of our products; it provides us an avenue of direct feedback to help improve the roadmaps for engineering projects.
One specific product that we get a lot of use out of is our serverless platform, Cloudflare Workers. With it, we can have incredible flexibility in the types of applications that we are able to build and deploy to our edge. An added bonus here is that our team does not have to manage a single server that our code runs on.
Today, we’re launching support for the security.txt initiative through Workers to help give security researchers a common location to learn about how to communicate with our team. In this post, I’m going to focus on some of the benefits of managing security projects through Workers, detail how we built out the mechanism that we’re using to manage security.txt on cloudflare.com, and highlight some other use cases that our team has built on Workers in the past few months.
Building on Workers
The Workers platform is designed to let anyone deploy code to our edge network which currently spans across 200 cities in 90 countries. As a result of this, applications deployed on the platform perform exceptionally well, while maintaining high reliability. You can implement nearly any logic imaginable on top of zones in your Cloudflare account with almost no effort.
One of the biggest immediate benefits of this is the idea that there are no servers for our team to maintain. Far too often I have seen situations where a long running application is deployed onto an instanced machine within a cloud environment and immediately forgotten about. In some cases, outdated software or poorly provisioned permissions can open up dangerous vectors for malicious actors if a compromise is occurring. Our team can deploy new projects with the confidence that they will remain secure. The Workers runtime environment has many wins such as the fact that it receives automatic security updates and that we don't need to maintain the software stack, just the application logic.
Another benefit is that since Workers executes JavaScript, we can dream up complex applications and rapidly deploy them as full applications in production without a huge investment in engineering time. This encourages rapid experimentation and iteration while achieving high impact with consistent performance. A couple of examples:
Secure code review - On every pull request made to a code repository, a Worker runs a set of security curated rules and posts comments if there are matches.
CSP nonces and HTML rewriting - A Worker generates random nonces and uses the HTMLRewriter API to mutate responses with dynamic content security policies on our dashboard.
Authentication on legacy applications - Using the Web Crypto API, a Worker sits in front of legacy origins and issues, validates, and signs JWTs to control access.
Stay tuned for future blog posts where we plan to dive deeper on these initiatives and more!
security.txt
Our team regularly engages with external security researchers through our HackerOne program and since about 2014, the details of our program can be found on a dedicated page on our marketing site. This has worked quite well in starting up our program and allows anyone to contact our team if they have a vulnerability to report. However, every so often we’d see that there were issues with this approach. Specifically, there were cases of vulnerabilities being submitted to our support staff who would then tell the reporter about the disclosure page which then directs them to HackerOne resulting in an overall error prone experience for everyone involved. Other times, the team that manages our social media would direct researchers to us.
Security researchers, having done the hard work to find a vulnerability, face challenges to responsibly disclose it. They need to be able to quickly locate contact information, consume it and disclose without delay. The security.txt initiative addresses this problem by defining a common location and format for organizations to provide this information to researchers. A specification for this was submitted to the IETF with the description:
“When security vulnerabilities are discovered by researchers, proper reporting channels are often lacking. As a result, vulnerabilities may be left unreported. This document defines a format ("security.txt") to help organizations describe their vulnerability disclosure practices to make it easier for researchers to report vulnerabilities.”
Employing the guidance in security.txt doesn't solve the problem entirely but it is becoming common best practice amongst many other security conscious companies. Over time I expect that researchers will rely on security.txt for information gathering. In fact, some integrations are already being built by the community into security tools to automatically fetch information from a company’s security.txt!
Our security.txt can be found here: https://cloudflare.com/.well-known/security.txt
security.txt as a service -- built on Cloudflare Workers
Cloudflare's security.txt
When scoping out the work for deploying security.txt we quickly realized that there were a few areas we wanted to address when deploying the service:
Automation - Deploys should involve as few humans as possible.
Ease of maintenance - Necessary changes (specification updates, key rotations, etc) should be a single commit and deploy away.
Version control - security.txt is inherently a sensitive file, retaining attribution of every change made is valuable from an auditing perspective.
Certainly, we could manage this project through a manual process involving extensive documentation and coordination for manual deployments but we felt it was important to build this out as a full service that was easily maintainable. Manual maintenance and deployments do not necessarily scale well over time, especially for something that isn’t touched that often. We wanted to make that process as easy as possible since security.txt is meant to be a regularly maintained, living document.
We quickly turned to Workers for the task. Using the Wrangler CLI we can achieve the ease of deployment and automation requirements as well as track the project in git. In under half an hour I was able to build out a full prototype that addressed all of the requirements of the Internet-Draft and deploy it to a staging instance of our website. Since then, members from our team made some revisions to the text itself, updated the expiration on our PGP key, and bumped up to the latest draft version.
One cool decision we made is that the security.txt file is created from a template at build time which allows us to perform dynamic operations on our baseline security.txt. For example, Section 3.5.5 of the draft calls for a date and time after which the data contained in the "security.txt" file is considered stale and should not be used. To address this field, we wrote a short node.js script that automatically sets an expiration of 365 days after the point of deployment, encouraging regular updates:
const dayjs = require('dayjs')
const fs = require('fs')
const main = async () => {
fs.appendFile(
'./src/txt/security.txt.temp',
`\nExpires: ${dayjs()
.add(365, 'day')
// Thu, 31 Dec 2020 18:37:07 -0800
.format('ddd, D MMM YYYY HH:mm:ss ZZ')}\n`,
function(err) {
if (err) throw err
console.log('Wrote expiration field!')
},
)
}
We’ve also leveraged this benefit in our Make targets where at build time we ensure that the deployed security.txt is clearsigned with the [email protected] PGP key:
sign:
gpg --local-user [email protected] -o src/txt/security.txt --clearsign src/txt/security.txt.temp
rm src/txt/security.txt.temp
And finally, leveraging the multi-route support in wrangler 1.8 alongside the request
object that gets passed into our Worker, we can serve our PGP public key and security.txt at the same time on two routes using one Worker, differentiated based on what the eyeball is asking for:
import pubKey from './txt/security-cloudflare-public-06A67236.txt'
import securityTxt from './txt/security.txt'
const handleRequest = async request => {
const { url } = request
if (url.includes('/.well-known/security.txt')) {
return new Response(securityTxt, {
headers: { 'content-type': 'text/plain; charset=utf-8' }, // security.txt
})
} else if (url.includes('/gpg/security-cloudflare-public-06A67236.txt')) {
return new Response(pubKey, {
headers: { 'content-type': 'text/plain; charset=utf-8' }, // GPG Public key
})
}
return fetch(request) // Pass to origin
}
In the interest of transparency and to allow anyone to easily achieve the same wins we did, we’ve open sourced the Worker itself for anyone who wants to deploy this service onto their Cloudflare zone. It just takes a few minutes of time.
You can find the project on GitHub: https://github.com/cloudflare/securitytxt-worker
What’s next?
The security team at Cloudflare has grown a significant amount in the past year. This is most evident in terms of our headcount (and still growing!) but also in how we take on new projects. We’re hoping to share more stories like this in the future and open source some of the other security services that we are building on Workers to help others achieve the same security wins that we are achieving with the platform.