From 8c895f3b3d20ea0c49ff50956a6a3a113f69433c Mon Sep 17 00:00:00 2001 From: Arun Kumar Thiagarajan Date: Sun, 21 Jun 2026 08:41:40 +0530 Subject: [PATCH] Test that Turnstile rejects a verified token for an unlisted hostname The gateway rejects a Siteverify success whose hostname is not in TURNSTILE_HOSTNAMES, which stops a token minted for an attacker-controlled page from being replayed against this form. That branch had no coverage: the test double always returned the allow-listed hostname. Add a token that resolves to an unlisted hostname and assert the submission is rejected with verification_failed and no Site Data write, after Siteverify was consulted. --- worker/test/index.test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/worker/test/index.test.js b/worker/test/index.test.js index 6a6b882..6261e38 100644 --- a/worker/test/index.test.js +++ b/worker/test/index.test.js @@ -128,6 +128,14 @@ function makeDependencies(options = {}) { }); } + if (token === "wrong-hostname-token") { + return Response.json({ + success: true, + action, + hostname: "phishing.example.com", + }); + } + return Response.json({ success: true, action, @@ -322,6 +330,26 @@ test("rejects invalid or mismatched Turnstile tokens without writing", async () } }); +test("rejects Turnstile tokens verified for an unlisted hostname", async () => { + const env = makeEnv(); + const { calls, dependencies } = makeDependencies(); + const response = await handleRequest( + makeRequest( + "/suggestions", + suggestionBody({ turnstile_token: "wrong-hostname-token" }), + ), + env, + undefined, + dependencies, + ); + const body = await response.json(); + + assert.equal(response.status, 400); + assert.equal(body.code, "verification_failed"); + assert.equal(calls.turnstile.length, 1); + assert.equal(calls.siteData.length, 0); +}); + test("rate limits invalid-token floods before calling Siteverify", async () => { const rateLimitCalls = []; const env = makeEnv({