Skip to content

Part 2 of 7 · Form spam filter series ~5 min read

How the cheap signals work

The cheap signals do most of the work, and they are cheap in two senses: they cost nothing to compute and they cost the visitor nothing. Two of the six are frequently implemented in a way that quietly rejects real people, which is worth being careful about.

Key takeaways

  • Six signals: honeypot, fill time, field order, link count, field consistency, and repetition.
  • The honeypot must be hidden accessibly, or screen reader users fill it in.
  • Fill time needs a floor and no ceiling. A slow submission is not suspicious.
  • Link count is the strongest single content signal and needs no model.
  • Repetition across submissions catches the bots that beat everything else.

The six

SignalWhat it catchesWorth
Honeypot filledNaive bots that fill every fieldVery strong; near-certain spam
Fill time under 2sAutomated submissionStrong, with a floor only
Field orderScripted fills that do not tab naturallyModerate
Links in the messageAlmost all commercial spamStrong
Field inconsistencyA name in the phone field, etc.Moderate
RepetitionThe same body from many addressesVery strong, and slow to trigger

Between them these classify the large majority of submissions confidently in one direction or the other, at a computational cost of essentially zero and a visitor cost of exactly zero.

The two that go wrong

How the six cheap spam signals are combinedA vertical chain of five steps entered by a box labelled A submission, with its signals. Step one asks whether the honeypot was filled, and how it was hidden, noting it must be hidden with CSS and never with an aria-hidden trick; filled exits to Almost certainly a bot, sent to quarantine. Step two asks whether it was filled in under two seconds, using a floor rather than a window; yes exits to a strong spam signal that combines rather than decides. Step three asks whether there are links in the body, counting them; two or more exits to another strong spam signal. Step four combines the score, weighted rather than counted. Step five is confident or not, and what is left is the model band. A note says only the honeypot decides alone and everything else contributes to a score.AWS ACCOUNTA submissionwith its signalsHoneypot filled?and hidden how?Hidden with CSSnever with anaria-hidden trickAlmost certainly a botquarantinefilledFilled in under 2s?a floor, not a windowStrong spam signalcombine, do not decideyesLinks in the body?count themStrong spam signaltwo or moreyesCombine the scoreweighted, not countedConfident, or notthe model band is what is leftOnly the honeypot decides alone. Everything else contributes to a score.
Fig 1. How the cheap signals combine. Only one of them is trusted on its own, and the rest contribute weight rather than making decisions.
  • App integration
  • Networking
  • Security & identity
  • Analytics
  • Front-end & mobile

The honeypot and screen readers

A honeypot is a form field that is invisible to people and visible to naive bots. The common implementation hides it with display: none, which is fine, or with type=“hidden”, which most bots skip, or by positioning it off-screen without hiding it from assistive technology — which is where it goes wrong.

A screen reader user encountering an off-screen labelled field will fill it in, because it is announced as a form field like any other. They then get silently classified as a bot, and there is no way for them to know. The fix is one attribute: hide it from the accessibility tree as well as visually, and label it something that discourages autofill.

Fill time needs a floor and no ceiling

Under two seconds is essentially impossible for a person typing a message and is a strong bot signal. The tempting mirror — treating a very long fill time as suspicious — is wrong, because a real person opens the form, gets distracted, comes back forty minutes later and submits.

So the check is a floor only. Any ceiling at all will misclassify somebody’s genuine enquiry, and a business that has ever had a customer fill in a form while on the phone to somebody has already seen the case.

Repetition

How repeated message bodies are detected across submissionsA horizontal row of five boxes. One submission: nothing unusual. Same body: with a different name and address. Third time: within a week. Fingerprint: a normalised body hash. All three quarantined: including retrospectively. A note says a bot good enough to beat every other signal still sends the same message twice.REPETITION CATCHES THE GOOD BOTSOne submissionnothing unusualSame bodydifferent name, addressThird timewithin a weekFingerprintnormalised body hashAll three quarantinedincluding retrospectivelyA bot good enough to beat every other signal still sends the same message twice.
Fig 2. The signal that catches sophisticated bots. Anything that passes the structural checks is usually running at volume, and volume is itself detectable.
  • Security & identity
  • Management
  • Analytics
  • Front-end & mobile

The retrospective part matters. When the third copy of a message arrives and reveals the pattern, the first two have already gone to somebody’s inbox. Moving them to quarantine and telling the recipient which ones moved is better than leaving them, and it is the one case where the system reclassifies something after delivery.

Normalising the body before hashing — lowercasing, stripping punctuation and whitespace, removing the parts that vary like a name or a URL — is what makes this work against bots that template their messages.

Next: the narrow model band.

All posts