Closed Bug 2078097 Opened 1 month ago Closed 1 month ago

FormAutofill:GetRecords returns all stored PII to any content process — no origin filtering, no actor scope restriction (Fission IPC validation gap)

Categories

(Toolkit :: Form Autofill, defect)

defect

Tracking

()

RESOLVED DUPLICATE of bug 2022419

People

(Reporter: nguyentuanhung1149, Unassigned)

Details

(Keywords: reporter-external)

Summary

The FormAutofill JSWindowActor is registered without a matches constraint (browser/extensions/formautofill/api.js:143-156), making it available on every web page in every content process. The parent-side handler FormAutofill:GetRecords (toolkit/components/formautofill/FormAutofillParent.sys.mjs:315-317) calls collection.getAll() which returns ALL stored autofill records without any origin filtering. Additional handlers FormAutofill:RemoveAddresses and FormAutofill:RemoveCreditCards accept content-controlled GUIDs for record deletion.

A compromised content process can silently exfiltrate all stored autofill data (addresses with full PII, credit card metadata) and delete any stored records, without user interaction.

Affected Code (mozilla-central tip, verified 2026-10-05)

1. Actor registration — NO matches constraint

browser/extensions/formautofill/api.js:143-156

ChromeUtils.registerWindowActor("FormAutofill", {
    parent: {
        esModuleURI: "resource://autofill/FormAutofillParent.sys.mjs",
    },
    child: {
        esModuleURI: "resource://autofill/FormAutofillChild.sys.mjs",
        events: {
            focusin: {},
            "form-changed": { createActor: false },
            "form-submission-detected": { createActor: false },
        },
    },
    allFrames: true,
});

Compare to other actors that handle sensitive data:

  • BlockedSite: matches: ["about:blocked?*"]
  • NetError: matches: ["about:certerror?", "about:neterror?"]

The FormAutofill actor has NO matches restriction.

2. GetRecords returns ALL records without origin filtering

toolkit/components/formautofill/FormAutofillParent.sys.mjs:315-317

case "FormAutofill:GetRecords": {
    const records = await this.getRecords(data);
    return { records };  // ALL records returned to content process
}

toolkit/components/formautofill/FormAutofillParent.sys.mjs:752-799

async getRecords({ searchString, collectionName, fieldName }) {
    collectionName ||= FormAutofillUtils.getCollectionNameFromFieldName(fieldName);
    const collection = lazy.gFormAutofillStorage[collectionName];
    const records = await collection.getAll();  // ALL records, NO origin filter
    // ... filters by searchString only
    return records;
}

3. Data exposed

Address records (full plaintext PII):

  • name, organization, street-address, address-level1/2/3, postal-code, country, tel, email

Credit card records:

  • cc-name, cc-number (masked: ************1234 — last 4 leaked), cc-exp-month, cc-exp-year, cc-type
  • cc-number-encrypted (OS KeyStore encrypted blob — included in getAll response)

4. Content-controlled record deletion

toolkit/components/formautofill/FormAutofillParent.sys.mjs:376-387

case "FormAutofill:RemoveAddresses": {
    data.guids.forEach(guid =>
        lazy.gFormAutofillStorage.addresses.remove(guid)
    );
}
case "FormAutofill:RemoveCreditCards": {
    data.guids.forEach(guid =>
        lazy.gFormAutofillStorage.creditCards.remove(guid)
    );
}

Content-controlled GUIDs, no ownership validation.

5. Content-controlled record injection

FormAutofill:SaveAddress at line 355: adds addresses with content-controlled data (no auth).

Attack Chain

  1. Compromised renderer A (evil.com) in a Fission content process
  2. Actor instantiated (no matches restriction — any page can create it)
  3. Sends FormAutofill:GetRecords with {collectionName: "addresses"}
  4. Parent returns ALL stored addresses (names, addresses, phones, emails)
  5. Sends FormAutofill:GetRecords with {collectionName: "creditCards"}
  6. Parent returns ALL credit cards (names, last 4 digits, expiry, types, encrypted numbers)
  7. No user interaction. No visual indicator. Completely silent.

Comparison with LoginManagerParent (correct pattern)

LoginManagerParent.sys.mjs:293-297:

  • Rejects content-provided origins
  • Uses this.origin derived from this.manager.documentPrincipal
  • Returns only logins matching current page origin

FormAutofillParent:

  • Has formOrigin getter (line 405) using documentPrincipal (correct)
  • But getRecords NEVER USES formOrigin — returns ALL records regardless

Impact

  • Full PII leak: names, physical addresses, phone numbers, emails
  • Credit card metadata: cardholder names, last 4 digits, expiry, card types
  • Data destruction: all stored records can be deleted
  • Data injection: fake addresses can be added
  • Cross-origin: browser-global storage, not per-origin
  • Silent: no user interaction or visual indicator
  • Fission violation: site-isolated renderer accesses entire autofill database

Suggested Fix

  1. Add origin filtering to getRecords (use existing formOrigin getter)
  2. Add matches constraint or require user gesture for actor creation
  3. Add principal validation to Remove and Save handlers
  4. Never send cc-number-encrypted to content processes

Credit: Nguyen Tuan Hung (nguyentuanhung1149@gmail.com) VNU HCM - UIT

Please do not rate your own security bugs. Bugs must be rated by Mozilla.

Severity: S2 → --
Flags: needinfo?(nguyentuanhung1149)
Keywords: sec-high
Flags: needinfo?(nguyentuanhung1149)

Automatic triage (under development): deduplication
No validation or verification has been performed.

This issue has been determined to be a duplicate of bug 2022419.

Both reports describe the same defect: FormAutofillParent.receiveMessage handles the test-only messages FormAutofill:GetRecords, FormAutofill:SaveAddress, FormAutofill:RemoveAddresses and FormAutofill:RemoveCreditCards for any content process. Because the FormAutofill actor is registered with allFrames: true and no matches restriction, a compromised content process can read every saved address and credit-card record through getRecords()/getAll(), add new records, and delete records by GUID. The attack chain, the affected handlers and the impact (silent PII exfiltration, record deletion and data injection) are the same.

Status: UNCONFIRMED → RESOLVED
Closed: 1 month ago
Duplicate of bug: CVE-2026-6765
Resolution: --- → DUPLICATE
Group: core-security → firefox-core-security

General critique you should incorporate into future submissions:

What EXACT version are you reporting the bug against?

For a Mozilla-shipped binary we want the buildID (displayed in about:support). For source analysis we need the hash of the revision you are inspecting. A link is better because we have multiple repos you might be looking at. Your report says

Affected Code (mozilla-central tip, verified 2026-10-05)

  1. Actor registration — NO matches constraint
    browser/extensions/formautofill/api.js:143-156

This is a complete fabrication. Or maybe Oct 5 is really the day you personally looked at it, but that tells us NOTHING about the version you were looking at. The snippet of code you quote is not at the lines you claim, and is missing a line of code that was added June 18. I don't know what version you were looking at, but I know it's at least 4 versions out of date.

There is no POC to verify your claims

Code that looks bad in a local analysis might be perfectly fine due to constraints elsewhere, or even unreachable. I'm not sure what you "verified" without one. In this case the code you identified will only be processed in the parent in a testing configuration.

You have requested a bounty In a couple of bugs. Please be aware that our client bug bounty program requires a POC that demonstrates that the vulnerability is reachable in Firerfox as shipped by Mozilla. Please read our client bounty program guidelines and FAQ on our web site.

Check for duplicates

This bug is a duplicate of one that was fixed in March (Firefox 150). A POC would have already saved you filing it, but the duplicate had been public for about 5 weeks when you filed this bug so you should have been able to find that as well.

Group: firefox-core-security
You need to log in before you can comment on or make changes to this bug.