All skills
cloudflare avatar

/turnstile-spin

@41e0d19 official
by cloudflarecloudflare/skills3k stars
298

Set up, repair, or migrate to Cloudflare Turnstile bot verification in an existing frontend and backend, including server-side Siteverify.

Use this Skill: https://skilld.dev/gh/cloudflare/skills/turnstile-spin

This session only. Nothing lands on disk.

testsvalidation.md

≈729 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Skill validation cases

These cases match the assertions in the Turnstile Spin PRD. Run them after editing this skill to confirm an agent loading it can still execute the wizard end-to-end.

Test 1: Dummy Siteverify returns a structured error

Step 10's validate.sh sends a deliberately-invalid token directly to challenges.cloudflare.com/turnstile/v0/siteverify using the captured secret. The expected response is success: false with error-codes: ["invalid-input-response"]. Anything else means the secret is wrong or the widget is misconfigured.

printf '%s' "$WIDGET_SECRET" |
  python3 -I -c 'import sys,urllib.parse; print(urllib.parse.urlencode({"secret":sys.stdin.read(),"response":"XXXX.DUMMY.TOKEN.XXXX"}),end="")' |
  curl --disable --fail --silent --show-error \
    "https://challenges.cloudflare.com/turnstile/v0/siteverify" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    --data-binary @- |
  jq -e '.success == false and (.["error-codes"] | index("invalid-input-response"))'

Expected exit code: 0.

Test 2: Metadata matches the sitekey and secret

printf '%s' "$WIDGET_SECRET" |
  scripts/validate.sh \
    --sitekey "$SITEKEY" \
    --account-id "$ACCOUNT_ID" \
    --expected-domains '["example.com","localhost","127.0.0.1"]'

Expected exit code: 0 for all valid clearance levels: no_clearance, interactive, managed, and jschallenge. A secret from another sitekey must fail.

Test 3: Runtime checks match the protected surface

Inspect every generated frontend and backend pair:

  • The widget has a meaningful action such as signup, login, or contact.
  • The backend requires the same result.action value.
  • The backend requires result.hostname to match its deployment-specific frontend hostname allowlist.
  • A production hostname allowlist does not contain localhost or 127.0.0.1.

Test 4: Same-page retries reset the correct widget

Native forms that navigate do not need reset logic. For each same-page flow, verify that the code retains the widget ID returned by turnstile.render() and calls turnstile.reset(widgetId) after the request completes. Multiple protected surfaces must not share a widget ID or reset without an ID.

Test 5: Skill persists to a bundle location

After Step 11:

test -f .claude/skills/turnstile-spin/SKILL.md \
  || test -f .codex/skills/turnstile-spin/SKILL.md \
  || test -f .opencode/skills/turnstile-spin/SKILL.md

Expected exit code: 0. File-oriented rules targets install the hosted prompt.md directly instead of using persist-skill.sh.

Running all cases

The consuming test harness must pass the widget secret through standard input. It must not export it or place it in a command argument.

(run-all.sh is not bundled with this skill; the cases above are intended to be wired into the consuming agent's own test harness, or run by hand after a deploy.)

Source: SKILL.md on GitHub

No alertstoday3 checks · Risk SAFE
  • Gen Agent Trust Hubtoday

    This skill provides a structured workflow for integrating Cloudflare Turnstile bot protection into web applications. It implements robust security practices, particularly regarding the handling of sensitive API tokens and secrets. While the skill interacts with project files and external Cloudflare APIs, it includes specific guardrails to prevent data exfiltration and unauthorized command execution. See the detailed analysis for a breakdown of the security controls in place.

  • Sockettoday

    No alerts

  • Snyktoday

    Risk: LOW · No issues

Signed by skilld at 41e0d19. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 6 hours ago.

Activeupdated 7 hours ago
  • turnstile
  • cloudflare
  • captcha
  • bot-protection
  • workers
  • form-validation
  • siteverify
  • javascript

README badge

README badge for cloudflare/skills/turnstile-spin

Sets up Cloudflare Turnstile end-to-end: creates the widget via API, deploys a siteverify Worker, wires frontend snippets, and validates the integration. Targets projects using vanilla HTML, Next.js, Astro, SvelteKit, or Hugo and includes migration paths from reCAPTCHA or hCaptcha.

Generated from the current SKILL.md.

Does this skill work with my framework?
Yes. The skill has templates for vanilla HTML, Next.js (app and pages), Astro, SvelteKit, and Hugo. It detects your framework during the codebase scan and adapts the frontend edits accordingly.
Will this overwrite my existing form code?
No. The skill gates your existing submit handler on Turnstile validation success but leaves the handler logic unchanged. It only adds the token fetch and Worker call before your code runs.
What if I already have a Turnstile widget set up?
The skill can wire siteverify to your existing sitekey without recreating the widget. Provide your sitekey and the skill will fetch its secret, deploy the Worker, and integrate validation into your form.
Can this skill migrate from reCAPTCHA or hCaptcha?
Yes. If the skill detects reCAPTCHA or hCaptcha during codebase scan, it will present a migration plan that swaps the script tag, updates the widget class and data attributes, and routes validation through the deployed Worker.
Does the Turnstile secret stay secure?
Yes. The secret is never written to disk. It's passed via stdin directly to `wrangler secret put` and stored as a Worker environment variable.

Generated from the current SKILL.md. These answers refresh after source changes.