Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Cloudflare Workers that adds an "Cf-Password-Pwnd" header to a POST request indicating whether the 'password' field appears in Troy Hunt's database of pwned passwords.
addEventListener('fetch', event => {
async function fetchAndCheckPassword(req) {
if (req.method == "POST") {
try {
const post = await req.formData();
const pwd = post.get('password')
const enc = new TextEncoder("utf-8").encode(pwd)
let hash = await crypto.subtle.digest("SHA-1", enc)
let hashStr = hex(hash).toUpperCase()
const prefix = hashStr.substring(0, 5)
const suffix = hashStr.substring(5)
const pwndpwds = await fetch('' + prefix)
const t = await pwndpwds.text()
const pwnd = t.includes(suffix)
let newHdrs = new Headers(req.headers)
newHdrs.set('Cf-Password-Pwnd', pwnd?'YES':'NO')
const init = {
method: 'POST',
headers: newHdrs,
body: post
return await fetch(req.url, init)
} catch (err) {
return new Response('Internal Error')
return await fetch(req)
function hex(a) {
var h = "";
var b = new Uint8Array(a);
for(var i = 0; i < b.length; i++){
var hi = b[i].toString(16);
h += hi.length === 1?"0"+hi:hi;
return h;

This comment has been minimized.

Copy link

@sejoker sejoker commented Feb 26, 2018

Outside of try/catch blocks, return await is redundant.


This comment has been minimized.

Copy link

@kentonv kentonv commented Feb 26, 2018

So, I had previously commented here that you should change:

return await fetch(req.url, init)


return await fetch(req, init)

By passing a whole Request object as the first parameter, rather than just a URL, you make sure to copy all of the properties of the original request -- except for the ones that are overridden by init, of ocurse. This is important, for example, because you want to make sure to use the same redirect mode (the req.redirect property). This script as written currently will unfortunately cause POST redirects to be handled at the worker level rather than returned to the client (because the default redirect mode is "follow", but for incoming proxied requests it's "manual").

However, this correction doesn't work! This code will throw an exception complaining that req.body is already used. But init is providing a new body, so this shouldn't matter.

This appears to be a bug in the Fetch API spec (not just our implementation). We've filed: whatwg/fetch#674

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment