Skip to content

Bug 1247245 - Don't autofill login forms whose fields aren't rendered. r?sgalich - #428

Closed
coolswood wants to merge 1 commit into
mozilla-firefox:mainfrom
coolswood:agent/p1-visibility-gate
Closed

coolswood wants to merge 1 commit into
mozilla-firefox:mainfrom
coolswood:agent/p1-visibility-gate

Conversation

@coolswood

@coolswood coolswood commented Nov 3, 2026 •

Copy link
Copy Markdown

Bug 1247245

What

Page-load autofill writes saved credentials into password fields that are not rendered — e.g. a type="password" username input inside a [hidden] container of an inactive "log in by username instead of QR" flow, marked autocomplete="off". Gate the non-user-triggered fill path in _fillForm on the rendered state of the fill target (passwordField ?? usernameField): when Element.checkVisibility() reports no box, bail out with a new AUTOFILL_RESULT.FIELD_NOT_RENDERED before any value is written.

Untouched by design:

  • user-triggered fills (doorhanger autocomplete, context menu) — userTriggered=true paths are not gated;
  • capture/submit heuristics (the gate lives in _fillForm only);
  • fields the site reveals later: the gate runs after markAsAutoCompletableField, so the autocomplete dropdown still appears on focus;
  • background tabs: checkVisibility() never consults document.visibilityState (validated against Element.cpp semantics and empirically).

Why

Silent real-world breakage: S-Pankki's FTN federated login (Suomi.fi / vero.fi) serializes every form input into POST /ftn/auth/encap/start. The autofilled hidden value binds the Encap authentication session to the wrong identity, the phone app cannot complete the handshake, and the page polls /ftn/auth/encap/finish forever with processStatus:"IN_PROGRESS" — no error, no timeout (see also bug 1783962). Deleting the saved login is the only fix for affected users. The same structure (single masked username field in a hidden container, no other fillable inputs) is common on bank/government login pages.

Note the capture→refill loop that produces poisoned logins: banks mask the username input as type="password"; submitting that flow makes Firefox offer to save the username's content as a password, which is later autofilled back into the hidden masked field of the other flow.

Testing

  • Minimal testcase (self-contained replica of the bank form structure): with a seeded login, unpatched trunk 161.0a1 (linux-aarch64) fills the hidden field on page load (username=190774 in the page's serialize-all-fields payload); with the patch the field stays empty in all pref variants, including signon.usernameOnlyForm.enabled=false (the username-only heuristic is not involved — getUsernameFieldFromUsernameOnlyForm returns null for any form containing a password field).
  • ./mach mochitest toolkit/components/passwordmgr/test/ on the patched build: full suite; the watchlist for this change is green — test_autofill_from_bfcache.html, browser_focus_before_first_DOMContentLoaded.js, browser_glean_pwmgr_form_autofill_result.js (validates the Glean guard), browser_autofill_hidden_document.js. test_input_events.html asserted autofill into a display: none fixture (exactly the removed behavior), so this patch renders that fixture — its purpose (autofill fires input/change events) is unchanged; it passes with the update. The two remaining unexpected results (test_LoginManagerContent_passwordEditedOrGenerated.html, browser_doorhanger_urlbar_focus.js) reproduce identically on an unpatched trunk build.
  • FIELD_NOT_RENDERED is deliberately not counted in pwmgr.form_autofill_result yet: adding a label to an expires: never labeled counter requires data review. The guard in the finally block makes the follow-up (label + count) trivial once approved.

Lando: link
Bugzilla: bug 1247245

⚠️ This pull request has 3 warnings.
🚫 This pull request has 2 blockers.

…. r?sgalich

Autofill would fill password fields that exist in the DOM but are not
rendered, for example type="password" inputs inside hidden containers
for alternative, inactive login flows. Credentials silently written into
fields the user cannot see or edit break sites that serialize every
input of the form, such as S-Pankki's FTN QR login (bug 1783962).

Gate the non-user-triggered fill path in _fillForm on the rendered state
of the fill target: the password field, or the username field for
username-only forms. When Element.checkVisibility() reports the field
has no box (e.g. inside a display:none or [hidden] ancestor), bail out
with a new AUTOFILL_RESULT.FIELD_NOT_RENDERED before writing any value.
The gate runs after autocomplete attachment, so a field that becomes
visible later still offers the autocomplete popup; user-triggered fills
(doorhanger, context menu) are unaffected.

FIELD_NOT_RENDERED is deliberately not counted in the
pwmgr.form_autofill_result Glean labeled counter yet: adding a label to
an "expires: never" metric requires data review. A follow-up can add the
field_not_rendered label and drop the guard.

Also render the fixture in test_input_events.html: that test asserts the
input events fired by page-load autofill, which now only happens for
rendered fields.
@firefoxci-taskcluster

Copy link
Copy Markdown
No Taskcluster jobs started for this pull request

The allowPullRequests configuration for this repository (in .taskcluster.yml on the default branch) does not allow starting tasks for this pull request.

@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

(Automated Close) Please do not file pull requests here, see https://firefox-source-docs.mozilla.org/contributing/how_to_submit_a_patch.html

@github-actions github-actions Bot closed this Nov 3, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Nov 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant