Add abuse protection to the ROI calculator form #24
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/roi-calculator-captcha"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The ROI calculator endpoint was open to anyone and has been collecting spam submissions. This adds a layered guard in a new
security.js, run before anything is written to the DB or sent to the AI provider.Layers
TURNSTILE_SITE_KEY/TURNSTILE_SECRET_KEYare set; fails closed if the check can't complete.hp_company_urlfield; any value is rejected.Layers 2–4 need no configuration, so spam is throttled as soon as this deploys; adding Turnstile keys upgrades it to a full challenge (invisible for most legitimate visitors).
Blocked submissions now stop the flow client-side and show the reason, instead of silently rendering a result. AI/service errors (502/503) still fall through to the locally-computed estimate.
Also in here
trust proxyso client IPs are correct behind nginxReferenceErrorin the "AI not configured" branch, which calledsaveCalcSubmission()before the variables it closes over were declaredVerification
Tested against a live server: missing token, instant submit, filled honeypot, tampered signature and token replay were each rejected; a legitimate submission passed; the 6th tripped the 429. Turnstile tested end-to-end against Cloudflare's test keys — always-fail secret → 403, always-pass → 200.
The browser-side flow was not exercised in a real page (Chrome in the dev environment couldn't reach the local port). It passes
node --checkand was reviewed, but deserves a click-through before deploying.Deploying
Set in
.env(see.env.example):Not covered
/api/leadshas no protection and is the same class of target — a one-lineguardSubmissioncall plus the same frontend bits.🤖 Generated with Claude Code