Skip to content

Rule proposal: form-prefill-sanitize — extend checkout-checkbox-sanitize to text/email/select prefills #121

Open

Description

@twschiller

Category

New defense rule (extension of the checkout-checkbox-sanitize family)

What problem does this solve?

checkout-checkbox-sanitize clears pre-checked checkboxes on checkout pages so the agent doesn't inherit silent opt-ins. The same dark pattern — Mathur et al.'s Preselection — exists for non-checkbox inputs:

  • Pre-populated <select> defaults that pick the costliest shipping speed
  • Pre-filled hidden inputs carrying affiliate / referral / promo IDs that bias pricing or attribution
  • Pre-filled email/phone fields nudging the user toward marketing signup
  • Pre-selected radio defaults on tipping prompts ("18% / 20% / 22% / Custom" with 22% pre-checked)

The agent is then expected to re-select what it actually wants, same contract as the existing checkbox rule.

Proposed solution

On the same checkout-shaped URL gate, walk form controls and:

  • Clear pre-populated <input type="text|email|tel|number"> values when the page state suggests pre-fill (value present without user input — detectable on initial DOM).
  • Reset <select> to its first option (or a blank option if one exists) when the default differs from the natural-first choice.
  • Reset <input type="radio"> groups to unchecked when a default is server-supplied.
  • Clear value on <input type="hidden"> whose name matches a curated affiliate/referral/promo pattern (*aff*, *ref*, *promo*, *utm_*, coupon_id, discount_code) — but only on payment/order pages.

Out of scope for v1: role="textbox" / contenteditable widgets, complex date pickers, anything inside a payment-processor iframe.

Alternatives considered

  • Bundle into checkout-checkbox-sanitize instead of a new rule. Reasonable; the toggle becomes a bigger hammer. Splitting keeps user control finer-grained because text-field clearing has higher FP risk than checkbox clearing.
  • Synthetic blur/change event after clearing. Some sites recalc totals on input events; consider v2 if sites silently re-prefill on input without it.

Controlling false positives

  • Strict URL gate. Payment/order paths only (/cart, /checkout, /basket, /bag, /payment, /order) — never login or arbitrary forms. Reuse the exact gate of cart-addon-annotate and checkout-checkbox-sanitize so the surface is identical to a rule that's already in production.
  • Hard denylist for safety-critical hidden inputs. Never clear <input type="hidden"> whose name matches CSRF/cart/session shapes: _csrf, csrf_token, authenticity_token, cart_id, order_id, session*, nonce, state, _token, anything containing signature. Failure mode here is the form silently rejecting submit, which is worse than the original dark pattern.
  • Allowlist for hidden-input clearing. Only clear hidden inputs whose name matches the affiliate/promo pattern set above. Anything outside the allowlist is preserved.
  • <select>: only reset when the default value is NOT the first option. If the first option is selected (natural default — common pattern is <option value="">Select…</option> or <option>Standard shipping</option> first), the rule does nothing. Avoids clobbering legitimate first-option defaults.
  • Timing. Run on DOMContentLoaded, before browser autofill. Browser autofill that runs after the rule is preserved — meaning the user's password manager and saved addresses still work for inputs the rule has already cleared. Document the ordering explicitly so the contract is clear.
  • Geofencing-aware select defaults. Country/state preselection based on geo is usually legitimate. Mitigation: only reset <select> when the default deviates from the first option AND the field name is in a sneaking-prone set (shipping speed, tip percent, delivery slot, donation amount, insurance plan). Don't touch country/state/region selects.
  • Per-host kill-switch. Loyalty-program checkouts where saved details reappear by design (Amazon 1-Click, Apple Pay flows) can be denylisted by host. These flows are the user's intent.
  • No-op on inputs the user has actually focused. If document.activeElement or :focus-visible matched a field at any point, skip clearing it on rescan.
  • Graceful-failure mode. The worst user-facing outcome is "I need to retype" — recoverable. Document this so a user can clearly attribute the friction to the rule and toggle it off.

Prior art / references

  • Mathur et al. (CSCW 2019), Dark Patterns at Scale. — Preselection category; already cited.
  • Brignull, deceptive.design — Preselection.
  • WHATWG HTML autocomplete attribute spec — informs which fields are legitimate autofill targets vs. server-pushed prefills.
  • Adjacent OSS: Consent-O-Matic sets values to opt out on consent forms — same mechanic, different intent.

Tagged Impact L–M / Complexity M.

Activity

  1. added
    enhancementNew feature or request
    rule-proposalProposed new defense rule, pending triage/citation review
    on Jun 3, 2026
  2. changed the title [-]Rule proposal: form-prefill-clear — extend checkout-checkbox-sanitize to text/email/select prefills[/-] [+]Rule proposal: form-prefill-sanitize — extend checkout-checkbox-sanitize to text/email/select prefills[/+] on Jun 3, 2026
  3. twschiller commented on Jun 6, 2026

    @twschiller
    ContributorAuthor

    Proposal: split into an annotate-first rule and a narrow sanitize rule

    This proposal bundles five categories (text/email/tel, select, radio, hidden affiliate) under one sanitize contract. The FP profile across those categories isn't uniform — visible inputs are nearly indistinguishable from legitimate browser autofill / multi-step persistence / remembered preferences, while hidden affiliate inputs are allowlist-narrow and unambiguous. Annotation absorbs the high-FP categories at lower cost; sanitize stays for the one category where annotation can't do the job.

    Rule 1: form-prefill-annotate (default-on, sibling of cart-addon-annotate / hidden-fee-annotate)

    Annotate-only — no values are cleared. Prepends an inline chip near the field so the agent reads "pre-populated" in its snapshot and decides whether to overwrite.

    Scope by category:

    • Text / email / tel / number with non-empty value on initial DOM → chip on the field's label/wrapper: [abs: pre-populated — verify before submit]. URL-gated to checkout. Skip if the input has autocomplete= matching a legitimate target (name, email, tel, street-address, etc.) and the value matches the autofill shape (rough heuristic, accept FPs here).
    • <select> whose initial selectedIndex !== 0 and not in the geo/country/state allowlist → chip: [abs: default "<label>" is not first option]. No reset. Geo selects are explicitly excluded.
    • Radio group with an initially-checked option → chip on the group's fieldset: [abs: "<label>" pre-selected]. No deselect (would break required-selection submits).
    • Form containing hidden inputs matching the affiliate/promo allowlist → chip on the form's submit row: [abs: form carries pre-filled affiliate/promo metadata]. Value not touched here — handled by Rule 2.

    FP control: URL gate (isCheckoutUrl), per-host denylist, skip if document.activeElement has ever matched the field (cooperate with autofill ordering), cap chip count per form to avoid noise on long forms.

    Rule 2: hidden-affiliate-sanitize (default-on, narrow allowlist)

    The only sanitize action that stays in v1. Clears value on <input type=\"hidden\"> whose name matches a curated allowlist (utm_*, aff*, ref*, promo*, coupon_id, discount_code). Annotation is the wrong tool here — the value is submitted regardless of any chip, and the agent never reads hidden values into a decision.

    Hard denylist (CSRF/cart/session shapes) takes precedence, matching the original list above. Per-host kill-switch for known Amazon-1-Click / Apple Pay flows.

    Why split

    Open questions before coding

    1. Do agents currently read value= on hidden inputs into their state, or only visible text? If they ignore hidden inputs entirely, Rule 2's "annotate alternative" is moot and sanitize is the only useful posture (assumed above, worth confirming).
    2. Is there appetite for the v2 synthetic-blur/change follow-up the original issue floats, or is that a separate ticket once we see real-world re-prefill behavior?
    3. Should the annotate chip text include the actual prefilled value, or just flag presence? Including the value helps the agent decide; excluding avoids leaking remembered PII into a logging snapshot.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestrule-proposalProposed new defense rule, pending triage/citation review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions