payment and address items could be stored (CLI wizard, Desktop dialog) but nothing could
fill them: a dead surface holding real card numbers. browser_vault_fill now handles all
three kinds through the same origin-bound, supervisor-only, redacted path:
- classify_checkout_control / select_checkout_fills map WHATWG autocomplete tokens
(cc-number, cc-exp[-month|-year], cc-csc, address-line1/2, address-level1/2, postal-code,
country-name) with label/name heuristics as backup; a combined "MM/YY" control gets
exp_month+exp_year and suppresses the split fills; inspection now covers <select>
(country, state, expiry month) and the fill script picks an option by value or text.
- Every payment fill goes through request_elicitation_consent (gateway button round-trip
or CLI panel) before a byte is written; declined → payment_declined, headless sessions
are refused. A prompt injection that reaches a checkout can ask, not spend. Card values
join the redaction registry like passwords; the result lists targeted field tokens only.
- Origin is now required for every kind (CLI wizard asks; Desktop dialog always shows the
field) because a card without a bound origin is unfillable.
- The tool descriptions, docs and CLI copy drop "Phase 1 / login only".
Live (evals/vault_fill_live_e2e.py, real browser_exec + packaged Chromium): decline writes
nothing; accept fills card/expiry/CVC on the /checkout tab, leaves the email box and the
country <select> untouched, and neither the card number nor the CVC appears in any result.
browser_vault_tool also: focuses the tab on the bound origin holding the right form before the
origin pre-check (focus_page from the previous commit); tool descriptions say "the browser's
input tool" (rewritten per session by model_tools); _check_vault_available is registered
uncached because its answer is per profile (vault dir + config) and the probe is a file stat.