fix(forms): harden honeypot hiding on contact + inline lead forms
Deploy to Production / Build & Verify (push) Has been cancelled
Deploy to Production / Pre-Deploy Tests (push) Has been cancelled
Deploy to Production / Deploy to Railway (push) Has been cancelled
Deploy to Production / Deploy to Render (push) Has been cancelled
Deploy to Production / Deploy to VPS (PM2) (push) Has been cancelled
Deploy to Production / Deploy to Fly.io (push) Has been cancelled
Deploy to Production / Post-Deploy Verification (push) Has been cancelled
Deploy to Production / Notify on Failure (push) Has been cancelled
E2E Test Suite / Smoke Tests (P0) (push) Has been cancelled
E2E Test Suite / Critical User Journeys (push) Has been cancelled
E2E Test Suite / API Integration Tests (push) Has been cancelled
E2E Test Suite / Form Interaction Tests (push) Has been cancelled
E2E Test Suite / Destructive & Chaos Tests (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (chromium) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (firefox) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (webkit) (push) Has been cancelled
E2E Test Suite / Mobile Device Tests (push) Has been cancelled
E2E Test Suite / Security Header Tests (push) Has been cancelled
E2E Test Suite / Test Report Summary (push) Has been cancelled
Ping Search Engines / Notify Search Engines (push) Failing after 12m31s
Deploy to Production / Build & Verify (push) Has been cancelled
Deploy to Production / Pre-Deploy Tests (push) Has been cancelled
Deploy to Production / Deploy to Railway (push) Has been cancelled
Deploy to Production / Deploy to Render (push) Has been cancelled
Deploy to Production / Deploy to VPS (PM2) (push) Has been cancelled
Deploy to Production / Deploy to Fly.io (push) Has been cancelled
Deploy to Production / Post-Deploy Verification (push) Has been cancelled
Deploy to Production / Notify on Failure (push) Has been cancelled
E2E Test Suite / Smoke Tests (P0) (push) Has been cancelled
E2E Test Suite / Critical User Journeys (push) Has been cancelled
E2E Test Suite / API Integration Tests (push) Has been cancelled
E2E Test Suite / Form Interaction Tests (push) Has been cancelled
E2E Test Suite / Destructive & Chaos Tests (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (chromium) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (firefox) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (webkit) (push) Has been cancelled
E2E Test Suite / Mobile Device Tests (push) Has been cancelled
E2E Test Suite / Security Header Tests (push) Has been cancelled
E2E Test Suite / Test Report Summary (push) Has been cancelled
Ping Search Engines / Notify Search Engines (push) Failing after 12m31s
Both honeypots now use off-screen positioning (position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden) instead of relying on a parent's aria-hidden alone, and the input itself carries tabindex="-1", autocomplete="off", and aria-hidden="true". Labels are sr-only and sit as siblings of the input (no nested label/input). Avoid display:none and visibility:hidden so bots that skip those still trip the trap. Verified: rendered honeypot HTML matches spec on both /contact and the homepage inline lead form, and /api/contact still 200s a populated `website` silently (bot path) while accepting empty `website` payloads as real leads.
This commit is contained in:
@@ -54,15 +54,26 @@
|
||||
data-testid="inline-lead-form"
|
||||
novalidate
|
||||
>
|
||||
<!-- Honeypot (visually & SR-hidden — bots fill it, real users do not). -->
|
||||
<div class="absolute -left-[9999px] top-auto w-px h-px overflow-hidden" aria-hidden="true">
|
||||
<label for="inline-lead-website">Website</label>
|
||||
<!--
|
||||
Honeypot — off-screen positioned, NOT display:none / visibility:hidden
|
||||
(some bots skip those entirely). aria-hidden + sr-only label keep it
|
||||
silent for screen readers; tabindex="-1" + autocomplete="off" keep it
|
||||
out of the tab order and browser autofill. Bots that blindly fill
|
||||
every field will populate `website`, and /api/contact silently drops
|
||||
the submission.
|
||||
-->
|
||||
<div
|
||||
class="absolute -left-[9999px] top-auto w-px h-px overflow-hidden"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<label for="inline-lead-website" class="sr-only">Website</label>
|
||||
<input
|
||||
type="text"
|
||||
id="inline-lead-website"
|
||||
name="website"
|
||||
tabindex="-1"
|
||||
autocomplete="off"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+22
-12
@@ -156,18 +156,28 @@ const trustStats = [
|
||||
</div>
|
||||
|
||||
<form id="contact-form" class="space-y-5" novalidate>
|
||||
<!-- Honeypot field (anti-spam) - hidden from users -->
|
||||
<div class="absolute -left-[9999px]" aria-hidden="true">
|
||||
<label for="website">
|
||||
Website
|
||||
<input
|
||||
type="text"
|
||||
id="website"
|
||||
name="website"
|
||||
tabindex="-1"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</label>
|
||||
<!--
|
||||
Honeypot field (anti-spam).
|
||||
Hidden from sighted users via off-screen positioning (NOT display:none /
|
||||
visibility:hidden — some bots skip those entirely and never trip the trap).
|
||||
The wrapper carries aria-hidden so screen-readers don't announce the label
|
||||
or the input, and tabindex="-1" + autocomplete="off" keep it out of the
|
||||
tab order and browser autofill. Bots that blindly fill every field will
|
||||
set a value here, and /api/contact silently discards the submission.
|
||||
-->
|
||||
<div
|
||||
class="absolute -left-[9999px] top-auto w-px h-px overflow-hidden"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<label for="website" class="sr-only">Website</label>
|
||||
<input
|
||||
type="text"
|
||||
id="website"
|
||||
name="website"
|
||||
tabindex="-1"
|
||||
autocomplete="off"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Name + Email row -->
|
||||
|
||||
Reference in New Issue
Block a user