feat(botid): add Vercel BotID to the four public forms (observe mode) - #441
Draft
ignmandagaran wants to merge 2 commits into
Draft
feat(botid): add Vercel BotID to the four public forms (observe mode)#441ignmandagaran wants to merge 2 commits into
ignmandagaran wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Base automatically changed from
ignmandagaran/newsletter-api-key-disabled
to
main
August 14, 2026 13:46
ignmandagaran
marked this pull request as ready for review
August 14, 2026 13:47
ignmandagaran
force-pushed
the
ignmandagaran/botid-detect
branch
2 times, most recently
from
August 14, 2026 13:50
f2561d5 to
34ad596
Compare
|
ignmandagaran
force-pushed
the
ignmandagaran/botid-detect
branch
from
August 14, 2026 13:53
34ad596 to
41d5830
Compare
ignmandagaran
force-pushed
the
ignmandagaran/botid-detect
branch
from
August 14, 2026 13:58
41d5830 to
9d692c8
Compare
Adds the invisible challenge and its proxy rewrites. No action calls checkBotId() yet, so nothing is classified or blocked. The protect list covers every route under (site): the contact overlay is mounted in that layout and a server action POSTs to the page that invoked it, so /contact alone would leave real submissions unchallenged everywhere else. checkLevel is left unset so Deep Analysis stays a dashboard toggle.
checkBotId() runs on all three form actions, after the honeypot and rate limit so the free checks short-circuit first. Nothing is dropped yet: suspected bots still reach Mailchimp and Notion, and their contact emails are delivered with a [SUSPECTED BOT] subject so sales@ can judge precision before enforcement. The verdict is reported as telemetry rather than a Sentry event: it is attacker-triggerable and no sampleRate is configured, so captureMessage would be unbounded under exactly the flood it reports on.
ignmandagaran
force-pushed
the
ignmandagaran/botid-detect
branch
from
August 14, 2026 14:02
9d692c8 to
ad97a73
Compare
ignmandagaran
marked this pull request as draft
August 14, 2026 14:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Vercel BotID — an invisible CAPTCHA — to the four public forms. The contact form has no validation today and emails
sales@basement.studioon every submit.Nothing is blocked here. The actions call
checkBotId(), report the verdict, then proceed as before. Suspected bots still reach Resend and Notion; their contact emails arrive prefixed[SUSPECTED BOT]sosales@can judge accuracy first. Enforcement is a follow-up PR, once there's data.Observe-first because BotID fails closed: a route missing from the client
protectlist gets no challenge headers, so a real visitor reads as a bot — on a lead form, a silently lost lead.Changes
botid@^1.5.11;withSentryConfig(withBotId(nextConfig), …)initBotId()lists all 13(site)routes, not just/contact— the contact overlay is mounted in(site)/layout.tsxand a server action POSTs to whatever page invoked itcheckBotId()in the three actions, after the honeypot/rate-limit so free checks short-circuit firstsrc/lib/botid.tsreports viaconsole.error+track("botid_detected"), not Sentry — attacker-triggerable and nosampleRateis set, socaptureMessagewould be unbounded under the very flood it reports oncheckLevelset, so it stays a dashboard toggleChecklist
pnpm lintpasses