serverless for security engineering
Cloudflare’s security team approaches projects with what it calls a “builder first mindset” — designing, developing, and deploying solutions the same way any standard engineering team would. That includes dogfooding Cloudflare’s own products: the WAF, Workers platform, and Cloudflare Access are all used to secure Cloudflare itself. The approach yields direct feedback that feeds into engineering roadmaps, but the team also gets concrete operational benefits, particularly from Cloudflare Workers. Deploying code at the edge means there is no server to patch, provision, or forget about, and because Workers runs JavaScript, complex applications can go from idea to production quickly.
Recent examples of this style of internal tooling include:
- Secure code review — a Worker evaluates every pull request against security-curated rules and posts comments on matches.
- CSP nonces and HTML rewriting — a Worker generates random nonces and leverages the HTMLRewriter API to apply dynamic content security policies to the dashboard.
- Authentication on legacy applications — using the Web Crypto API, a Worker in front of legacy origins issues, validates, and signs JWTs for access control.
why security.txt
Cloudflare has run a HackerOne program and maintained a dedicated disclosure page since 2014, but the process had friction points. Vulnerability reports sometimes landed with support staff or social media managers, who then pointed researchers to the disclosure page, which directs them to HackerOne — an error-prone path for someone who has already done the hard work of finding a bug.
The security.txt initiative, submitted to the IETF, defines a common location and format for organizations to describe their vulnerability disclosure practices. As the draft puts it:
“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.”
Cloudflare now publishes its file at https://cloudflare.com/.well-known/security.txt.
building security.txt as a Worker
When scoping the deployment, the team set three requirements:
- Automation — deploys should involve as few humans as possible.
- Ease of maintenance — updates like spec changes or key rotations should be a single commit and deploy.
- Version control — security.txt is a sensitive file, and retaining attribution for every change is valuable from an audit perspective.
A manual process with extensive documentation wouldn't scale, especially for a file meant to be maintained regularly. Workers, along with the Wrangler CLI and git, addressed all three concerns. The team had a full prototype addressing every requirement of the Internet-Draft deployed to a staging instance in under half an hour.
The security.txt file is generated from a template at build time, which allows dynamic operations. For example, the draft requires a date after which the file is stale — a short node.js script sets that expiration to 365 days after 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!')
},
)
}
At build time, Make targets also ensure the deployed file 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
Finally, multi-route support in wrangler 1.8, paired with the request object passed into the Worker, serves both the PGP public key and security.txt on two routes through a single Worker, differentiated by request:
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
}
The Worker is open source and available at https://github.com/cloudflare/securitytxt-worker for anyone who wants to deploy the same service on their own zone.
what’s next
The security team has grown significantly over the past year, both in headcount and in how it takes on new projects. More of these internal services built on Workers are expected to be shared and open sourced in the future.



