improvement(contact): add Turnstile CAPTCHA, honeypot, and robustness fixes#4248
improvement(contact): add Turnstile CAPTCHA, honeypot, and robustness fixes#4248waleedlatif1 merged 6 commits intostagingfrom
Conversation
… fixes - Add Cloudflare Turnstile with graceful degradation: when the widget fails to load (ad blockers, iOS privacy, corporate DNS), submissions fall through to a tighter rate-limit bucket rather than hard-blocking - Add honeypot field to filter automated submissions without user impact - Add separate CAPTCHA_UNAVAILABLE_RATE_LIMIT bucket (3/min) for the no-captcha path so spam via ad-blocker bypass remains expensive - Pass expectedHostname to verifyTurnstileToken to close cross-site token reuse gap - Add SITE_HOSTNAME as module-level constant (avoid URL parsing per req) - Wire onExpire/onError/onUnsupported callbacks so token expiry during slow form-filling falls back gracefully instead of showing a captcha error - Add getResponsePromise(30_000) timeout to prevent indefinite hang on network blips - Add size: 'invisible' to Turnstile options (required for execute mode) - Move turnstile.ts to lib/core/security/ alongside csp/encryption/input-validation - Switch all CSS to --landing-* variables throughout contact form - Move error display inline next to label with truncation in LandingField - Add labelClassName prop to LandingField for context-specific overrides - Simplify contact page to single-column max-w-[640px] layout
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Updates the landing contact UI by restyling inputs to Reviewed by Cursor Bugbot for commit 1320e5d. Configure here. |
Greptile SummaryThis PR hardens the contact form with Cloudflare Turnstile CAPTCHA, a honeypot field, a separate tighter rate-limit bucket for the no-CAPTCHA path, hostname validation on token verification, and graceful client-side degradation. The visual redesign migrates all styling to Confidence Score: 5/5Safe to merge — all previously raised P0/P1 concerns are resolved; only a minor style suggestion remains. Transport-error fallback (previously flagged P1) is correctly handled, honeypot positioning was fixed, and the CSS variable concern was confirmed intentional. The one remaining comment is a P2 style nit (as unknown as double cast for CONTACT_TOPIC_OPTIONS). No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant Form as ContactForm (client)
participant TW as Turnstile Widget
participant API as /api/contact
participant CF as Cloudflare siteverify
User->>Form: Submit
Form->>Form: Validate fields (Zod)
alt Turnstile site key configured
alt widgetReady
Form->>TW: reset() + execute()
TW-->>Form: captchaToken (or timeout/error)
else widget unavailable/expired
Form->>Form: captchaUnavailable=true
end
end
Form->>API: POST {fields, captchaToken?, captchaUnavailable?, website}
API->>API: Check honeypot (website field)
alt captchaUnavailable
API->>API: CAPTCHA_UNAVAILABLE rate limit (3/min)
else Turnstile configured and token present
API->>CF: POST siteverify
CF-->>API: {success, hostname, error-codes}
alt transport error
API->>API: CAPTCHA_UNAVAILABLE rate limit (3/min)
else verification failed
API-->>Form: 400 CAPTCHA failed
end
end
API->>API: Validate body (Zod)
API->>API: Send emails
API-->>Form: 201 success
Form->>User: Show success state
Reviews (3): Last reviewed commit: "fix(contact): disable submit during CAPT..." | Re-trigger Greptile |
|
Good catch on the transport error path — fixed in b734541. When P2a ( P2b (missing |
|
@greptile |
|
@cursor review |
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1320e5d. Configure here.

Summary
Type of Change
Testing
Tested manually
Checklist