Medium watch CVSS 5.3 chrome Info Disclosure 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
5.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactObservable discrepancy in Forms
DescriptionObservable discrepancy in Forms
ComponentForms
Bug ClassInfo Disclosure
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker517404644
Fix commit60e801e23034 (chromium/src) +236/-20
CWECWE-203
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-28 (per vendor advisory)
Fix landed2026-07-06 (public git)
Disclosed2026-08-25
Patch gap50 days — fix public in source before the advisory

Background

Autofill preview text
The suggested, not-yet-accepted value the browser renders inside a form control; it is generated internally and should not be observable by the page’s script or author styles.
`::-internal-input-suggested` / `:-internal-autofill-previewed`
Internal Blink pseudo-elements/pseudo-classes applied to a control (and to date/time sub-fields like ::-webkit-datetime-edit-year-field) while it is showing an autofill preview.
`@font-face` `unicode-range` disclosure
Because the browser only downloads a font whose unicode-range covers a glyph actually present in the rendered text, an author can register many single-character @font-face rules and infer preview characters from which font URLs get fetched.
UA stylesheet font pinning
Blink’s user-agent stylesheet (html.css) forces a hard-coded generic font on preview text so author @font-face/font-family cannot influence which fonts are matched against the secret preview string.

Root Cause Analysis

The user-agent rules in html.css that pin the autofill-preview font to a generic family (-webkit-small-control / sans-serif, plus font-feature-settings: normal) previously applied only to input::-internal-input-suggested and textarea::-internal-input-suggested. <select> autofill previews (select:-internal-autofill-previewed) and the <input type=date|time|month|week|datetime-local> sub-field pseudo-elements (::-webkit-datetime-edit-*) were not covered, so for those controls the author’s font-family / @font-face still applied to the preview text. An author could therefore attach carefully crafted @font-face rules with narrow unicode-ranges and observe (via network fetches) which characters the preview text contained, leaking the suggested value.

The fix introduces a AutofillPreviewIgnoreAuthorFont runtime feature and, when enabled, extends the font-pinning rules to select:-internal-autofill-previewed (generic sans-serif) and to every input:-internal-autofill-previewed::-webkit-datetime-edit-* sub-field (monospace), while keeping the previous behavior under @supports not blink-feature(AutofillPreviewIgnoreAuthorFont). Hard-coding a generic family defeats the @font-face match and closes the character-disclosure side channel.

Key insight
The preview-font hard-coding that neutralized the @font-face unicode-range side channel had never been applied to <select> and date/time input previews, leaving their preview text styleable by author fonts; the fix adds those selectors (gated on the new AutofillPreviewIgnoreAuthorFont feature) so a generic font is forced for them too.

Attack Path

  1. Register probing fonts The attacker page defines multiple @font-face rules whose src points at distinct URLs and whose unicode-range each covers a single character or small set, and applies an author font-family to a <select> or a date/time <input>.
  2. Induce an autofill preview The browser surfaces a suggested value for that control (e.g. via internals.setSuggestedValue in the test, or real autofill), rendering the secret preview text in the un-pinned author font.
  3. Match author fonts against the secret text Because the preview text for select:-internal-autofill-previewed / ::-webkit-datetime-edit-* sub-fields used the author font, the engine matches the @font-face unicode-range rules against the preview characters.
  4. Exfiltrate via font fetches Only the @font-face URLs whose unicode-range covers a character actually in the preview are downloaded, so observing the network requests reveals which characters the suggested value contains, disclosing the autofill data. (inferred: full reconstruction of the value depends on how many characters are probed.)

Impact Assessment

A malicious page can infer characters of an autofill preview value (an observable discrepancy / information leak in Forms) for <select> and date/time inputs, without the user accepting the suggestion, using only author CSS and observation of font network requests in the renderer. The advisory classifies it as an observable-discrepancy information leak with no statement of in-the-wild exploitation; the leak is limited to what the preview renders and any broader sensitive-data recovery is (inferred). Preconditions are that the site controls the page’s CSS and that a preview is shown for one of the newly-covered control types.

Changed Functions

FunctionChangeNotes
while
third_party/blink/web_tests/fast/forms/autofill-preview-font.html
modified
if
third_party/blink/web_tests/fast/forms/autofill-preview-font.html
modified

Files Changed

  • third_party/blink/renderer/platform/runtime_enabled_features.json5
  • third_party/blink/renderer/core/html/resources/html.css
  • third_party/blink/web_tests/fast/forms/autofill-preview-font.html

Audit Directions

  • Incomplete pseudo-element coverage of secret text
    When a UA rule sanitizes a security-sensitive rendering (preview, -internal-* state), enumerate every control type and shadow/pseudo sub-element (::-webkit-datetime-edit-*, select, textarea) that can display that text and confirm each is covered, not just the common input/textarea cases.
  • `@font-face` `unicode-range` side channels
    Look for any browser-generated or otherwise secret text that is rendered with author-controllable font-family/@font-face, since selective font downloads leak character presence; such text should be pinned to a generic family.
  • Author-influenceable styling of internal UI
    Review other author-reachable properties (not only fonts) on autofill/preview/internal pseudo-elements that could turn rendering into an observable signal (network fetches, layout/scroll metrics, rendering-time differences).
From 60e801e23034c2828079cfcc6511e9fb5322f4b8 Mon Sep 17 00:00:00 2001
From: Joey Arhar <[email protected]>
Date: Mon, 06 Jul 2026 10:18:50 -0700
Subject: [PATCH] Hard code autofill preview font for select and date/time inputs

Allowing the author to set a custom font on autofill preview text can
lead to a privacy issue.

Fixed: 517697155, 517404644, 40057398
Change-Id: I089ffe93048038f42ac4e2c18bb88668cb050b41
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7885624
Commit-Queue: Joey Arhar <[email protected]>
Reviewed-by: Joey Arhar <[email protected]>
Reviewed-by: David Baron <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1657280}
---
diff --git a/third_party/blink/renderer/core/html/resources/html.css b/third_party/blink/renderer/core/html/resources/html.css
index 41e7d28c..0cf08036 100644
--- a/third_party/blink/renderer/core/html/resources/html.css
+++ b/third_party/blink/renderer/core/html/resources/html.css
@@ -634,29 +634,84 @@
     overflow: hidden;
 }
 
-input::-internal-input-suggested,
-textarea::-internal-input-suggested {
-    font: -webkit-small-control !important;
-    /* font: -webkit-small-control resolves to Arial on every platform. Ideally
-       we'd keep Arial, but a concrete family is matched against author
-       @font-face, so a single-character unicode-range could disclose the
-       preview text; a generic family avoids that lookup. crbug.com/517710554. */
-    @supports blink-feature(AutofillPreviewGenericFontFamily) {
-      font-family: sans-serif !important;
+@supports blink-feature(AutofillPreviewIgnoreAuthorFont) {
+    input::-internal-input-suggested,
+    textarea::-internal-input-suggested {
+        font: -webkit-small-control !important;
     }
-    /* -webkit-small-control does not pin the font-feature-settings and we want
-       previews to look consistent. */
-    font-feature-settings: normal !important;
-    /* Prevent that overflow affects the scrollable area. Without this,
-       LayoutBox::*Scroll{Height,Width}() may determine the scroll width/height
-       from the scrollable area instead of from the overrides in
-       LayoutTextControl{Single,Multi}Line::Scroll{Height,Width}(). */
-    overflow: hidden !important;
-    overflow-anchor: none;
+    select:-internal-autofill-previewed,
+    input::-internal-input-suggested,
+    textarea::-internal-input-suggested {
+        /* font: -webkit-small-control resolves to Arial on every platform. Ideally
+           we'd keep Arial, but a concrete family is matched against author
+           @font-face, so a single-character unicode-range could disclose the
+           preview text; a generic family avoids that lookup. crbug.com/517710554. */
+        font-family: sans-serif !important;
+    }
+    textarea::-internal-input-suggested,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-ampm-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-day-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-hour-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-millisecond-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-minute-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-month-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-second-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-week-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-year-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-text,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-fields-wrapper {
+        font-family: monospace !important;
+    }
+    input::-internal-input-suggested,
+    textarea::-internal-input-suggested,
+    select:-internal-autofill-previewed,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-ampm-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-day-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-hour-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-millisecond-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-minute-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-month-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-second-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-week-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-year-field,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-text,
+    input:-internal-autofill-previewed::-webkit-datetime-edit-fields-wrapper {
+        /* -webkit-small-control does not pin the font-feature-settings and we want
+           previews to look consistent. */
+        font-feature-settings: normal !important;
+        /* Prevent overflow from affecting the scrollable area. Without this,
+           LayoutBox::*Scroll{Height,Width}() may determine the scroll width/height
+           from the scrollable area instead of from the overrides in
+           LayoutTextControl{Single,Multi}Line::Scroll{Height,Width}(). */
+        overflow: hidden !important;
+        overflow-anchor: none;
+    }
 }
 
-textarea::-internal-input-suggested {
-  font-family: monospace !important;
+@supports not blink-feature(AutofillPreviewIgnoreAuthorFont) {
+    input::-internal-input-suggested,
+    textarea::-internal-input-suggested {
+        font: -webkit-small-control !important;
+        /* font: -webkit-small-control resolves to Arial on every platform. Ideally
+           we'd keep Arial, but a concrete family is matched against author
+           @font-face, so a single-character unicode-range could disclose the
+           preview text; a generic family avoids that lookup. crbug.com/517710554. */
+        @supports blink-feature(AutofillPreviewGenericFontFamily) {
+          font-family: sans-serif !important;
+        }
+        /* -webkit-small-control does not pin the font-feature-settings and we want
+           previews to look consistent. */
+        font-feature-settings: normal !important;
+        /* Prevent overflow from affecting the scrollable area. Without this,
+           LayoutBox::*Scroll{Height,Width}() may determine the scroll width/height
+           from the scrollable area instead of from the overrides in
+           LayoutTextControl{Single,Multi}Line::Scroll{Height,Width}(). */
+        overflow: hidden !important;
+        overflow-anchor: none;
+    }
+    textarea::-internal-input-suggested {
+        font-family: monospace !important;
+    }
 }
 
 input[type="password" i] {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 8b9ed5d5..7e3e27c 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -790,6 +790,12 @@
       status: "stable",
     },
     {
+      // Makes form control elements have a hard coded font when they are in
+      // their autofill previewed state.
+      name: "AutofillPreviewIgnoreAuthorFont",
+      status: "stable",
+    },
+    {
       name: "AutomationControlled",
       base_feature: "none",
       public: true,
diff --git a/third_party/blink/web_tests/fast/forms/autofill-preview-font.html b/third_party/blink/web_tests/fast/forms/autofill-preview-font.html
new file mode 100644
index 0000000..a42985c
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/autofill-preview-font.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:[email protected]">
+<link rel=help href="https://issues.chromium.org/issues/517697155">
+<link rel=help href="https://issues.chromium.org/issues/517404644">
+<link rel=help href="https://issues.chromium.org/issues/40057398">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/common.js"></script>
+<style>
+  @font-face {
+    font-family: Ahem;
+    src: url(../../resources/Ahem.ttf);
+  }
+  .use-ahem {
+    font-family: Ahem;
+  }
+</style>
+
+<select id=my-select class=use-ahem>
+  <option value=v1>Value 1</option>
+  <option value=v2>Value 2</option>
+</select>
+
+<input id=my-date type=date class=use-ahem>
+<textarea id=my-textarea class=use-ahem></textarea>
+<input id=my-text type=text class=use-ahem>
+<input id=my-search type=search class=use-ahem>
+<input id=my-tel type=tel class=use-ahem>
+<input id=my-url type=url class=use-ahem>
+<input id=my-email type=email class=use-ahem>
+<input id=my-password type=password class=use-ahem>
+<input id=my-number type=number class=use-ahem>
+<input id=my-month type=month class=use-ahem>
+<input id=my-week type=week class=use-ahem>
+<input id=my-time type=time class=use-ahem>
+<input id=my-datetime-local type=datetime-local class=use-ahem>
+
+<script>
+function getElementByTextContent(root, text) {
+    var node = root;
+    while (node) {
+        if (node.nodeType === Node.ELEMENT_NODE && node.textContent === text)
+            return node;
+        node = traverseNextNode(node, root);
+    }
+    return null;
+}
+
+promise_test(async () => {
+  await document.fonts.ready;
+  const select = document.getElementById('my-select');
+  const initialSelectStyle = window.getComputedStyle(select);
+  assert_equals(initialSelectStyle.fontFamily, 'Ahem', 'Select should use author font initially');
+
+  internals.setSuggestedValue(select, 'v2');
+  const selectStyle = window.getComputedStyle(select);
+  assert_not_equals(selectStyle.fontFamily, 'Ahem',
+    'Select should not use author font in preview state.');
+}, 'Autofill preview should not use author fonts for select');
+
+const simpleTypes = [
+  { type: 'textarea', value: 'suggested value' },
+  { type: 'text', value: 'suggested value' },
+  { type: 'search', value: 'suggested value' },
+  { type: 'tel', value: '123-456-7890' },
+  { type: 'url', value: 'https://example.com' },
+  { type: 'email', value: '[email protected]' },
+  { type: 'password', value: 'secret' },
+  { type: 'number', value: '42' }
+];
+
+simpleTypes.forEach(({type, value}) => {
+  promise_test(async () => {
+    await document.fonts.ready;
+    const id = type === 'textarea' ? 'my-textarea' : `my-${type}`;
+    const element = document.getElementById(id);
+    const initialStyle = window.getComputedStyle(element);
+    assert_equals(initialStyle.fontFamily, 'Ahem', `${type} should use author font initially`);
+
+    internals.setSuggestedValue(element, value);
+    const shadowRoot = internals.shadowRoot(element);
+    const pseudoIds = [];
+    var node = shadowRoot;
+    while (node) {
+        if (node.nodeType === Node.ELEMENT_NODE) {
+            pseudoIds.push(internals.shadowPseudoId(node));
+        }
+        node = traverseNextNode(node, shadowRoot);
+    }
+    const suggestedElement = getElementByPseudoId(shadowRoot, '-internal-input-suggested')
+      || getElementByTextContent(shadowRoot, value);
+    const style = window.getComputedStyle(suggestedElement || element);
+    assert_not_equals(style.fontFamily, 'Ahem',
+      `${type} should not use author font in preview state. Pseudo IDs: ${pseudoIds.join(', ')}`);
+  }, `Autofill preview should not use author fonts for ${type}`);
+});
+
+const complexTypes = [
+  { type: 'month', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-month-field'
+    ], value: '2026-05' },
+  { type: 'week', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-week-field'
+    ], value: '2026-W22' },
+  { type: 'time', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-hour-field',
+      '-webkit-datetime-edit-minute-field',
+      '-webkit-datetime-edit-ampm-field'
+    ], value: '10:05' },
+  { type: 'datetime-local', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-month-field',
+      '-webkit-datetime-edit-day-field',
+      '-webkit-datetime-edit-hour-field',
+      '-webkit-datetime-edit-minute-field',
+      '-webkit-datetime-edit-ampm-field'
+    ], value: '2026-05-29T10:05' },
+  { type: 'date', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-month-field',
+      '-webkit-datetime-edit-day-field'
+    ], value: '2026-05-29' },
+];
+
+complexTypes.forEach(({type, fields, value}) => {
+  promise_test(async () => {
+    await document.fonts.ready;
+    const element = document.getElementById(`my-${type}`);
+    const shadowRoot = internals.shadowRoot(element);
+
+    const firstField = getElementByPseudoId(shadowRoot, fields[1]);
+    assert_true(!!firstField, `Should find ${fields[1]}`);
+    const initialStyle = window.getComputedStyle(firstField);
+    assert_equals(initialStyle.fontFamily, 'Ahem', `${type} field should use author font initially`);
+
+    internals.setSuggestedValue(element, value);
+
+    fields.forEach(pseudoId => {
+      const el = getElementByPseudoId(shadowRoot, pseudoId);
+      if (el) {
+        const style = window.getComputedStyle(el);
+        assert_not_equals(style.fontFamily, 'Ahem',
+          `${pseudoId} should not use author font in preview state for ${type}.`);
+      }
+    });
+  }, `Autofill preview should not use author fonts for ${type}`);
+});
+</script>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/fast/forms/autofill-preview-font.html b/third_party/blink/web_tests/fast/forms/autofill-preview-font.html
new file mode 100644
index 0000000..a42985c
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/autofill-preview-font.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:[email protected]">
+<link rel=help href="https://issues.chromium.org/issues/517697155">
+<link rel=help href="https://issues.chromium.org/issues/517404644">
+<link rel=help href="https://issues.chromium.org/issues/40057398">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/common.js"></script>
+<style>
+  @font-face {
+    font-family: Ahem;
+    src: url(../../resources/Ahem.ttf);
+  }
+  .use-ahem {
+    font-family: Ahem;
+  }
+</style>
+
+<select id=my-select class=use-ahem>
+  <option value=v1>Value 1</option>
+  <option value=v2>Value 2</option>
+</select>
+
+<input id=my-date type=date class=use-ahem>
+<textarea id=my-textarea class=use-ahem></textarea>
+<input id=my-text type=text class=use-ahem>
+<input id=my-search type=search class=use-ahem>
+<input id=my-tel type=tel class=use-ahem>
+<input id=my-url type=url class=use-ahem>
+<input id=my-email type=email class=use-ahem>
+<input id=my-password type=password class=use-ahem>
+<input id=my-number type=number class=use-ahem>
+<input id=my-month type=month class=use-ahem>
+<input id=my-week type=week class=use-ahem>
+<input id=my-time type=time class=use-ahem>
+<input id=my-datetime-local type=datetime-local class=use-ahem>
+
+<script>
+function getElementByTextContent(root, text) {
+    var node = root;
+    while (node) {
+        if (node.nodeType === Node.ELEMENT_NODE && node.textContent === text)
+            return node;
+        node = traverseNextNode(node, root);
+    }
+    return null;
+}
+
+promise_test(async () => {
+  await document.fonts.ready;
+  const select = document.getElementById('my-select');
+  const initialSelectStyle = window.getComputedStyle(select);
+  assert_equals(initialSelectStyle.fontFamily, 'Ahem', 'Select should use author font initially');
+
+  internals.setSuggestedValue(select, 'v2');
+  const selectStyle = window.getComputedStyle(select);
+  assert_not_equals(selectStyle.fontFamily, 'Ahem',
+    'Select should not use author font in preview state.');
+}, 'Autofill preview should not use author fonts for select');
+
+const simpleTypes = [
+  { type: 'textarea', value: 'suggested value' },
+  { type: 'text', value: 'suggested value' },
+  { type: 'search', value: 'suggested value' },
+  { type: 'tel', value: '123-456-7890' },
+  { type: 'url', value: 'https://example.com' },
+  { type: 'email', value: '[email protected]' },
+  { type: 'password', value: 'secret' },
+  { type: 'number', value: '42' }
+];
+
+simpleTypes.forEach(({type, value}) => {
+  promise_test(async () => {
+    await document.fonts.ready;
+    const id = type === 'textarea' ? 'my-textarea' : `my-${type}`;
+    const element = document.getElementById(id);
+    const initialStyle = window.getComputedStyle(element);
+    assert_equals(initialStyle.fontFamily, 'Ahem', `${type} should use author font initially`);
+
+    internals.setSuggestedValue(element, value);
+    const shadowRoot = internals.shadowRoot(element);
+    const pseudoIds = [];
+    var node = shadowRoot;
+    while (node) {
+        if (node.nodeType === Node.ELEMENT_NODE) {
+            pseudoIds.push(internals.shadowPseudoId(node));
+        }
+        node = traverseNextNode(node, shadowRoot);
+    }
+    const suggestedElement = getElementByPseudoId(shadowRoot, '-internal-input-suggested')
+      || getElementByTextContent(shadowRoot, value);
+    const style = window.getComputedStyle(suggestedElement || element);
+    assert_not_equals(style.fontFamily, 'Ahem',
+      `${type} should not use author font in preview state. Pseudo IDs: ${pseudoIds.join(', ')}`);
+  }, `Autofill preview should not use author fonts for ${type}`);
+});
+
+const complexTypes = [
+  { type: 'month', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-month-field'
+    ], value: '2026-05' },
+  { type: 'week', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-week-field'
+    ], value: '2026-W22' },
+  { type: 'time', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-hour-field',
+      '-webkit-datetime-edit-minute-field',
+      '-webkit-datetime-edit-ampm-field'
+    ], value: '10:05' },
+  { type: 'datetime-local', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-month-field',
+      '-webkit-datetime-edit-day-field',
+      '-webkit-datetime-edit-hour-field',
+      '-webkit-datetime-edit-minute-field',
+      '-webkit-datetime-edit-ampm-field'
+    ], value: '2026-05-29T10:05' },
+  { type: 'date', fields: [
+      '-webkit-datetime-edit-text',
+      '-webkit-datetime-edit-year-field',
+      '-webkit-datetime-edit-month-field',
+      '-webkit-datetime-edit-day-field'
+    ], value: '2026-05-29' },
+];
+
+complexTypes.forEach(({type, fields, value}) => {
+  promise_test(async () => {
+    await document.fonts.ready;
+    const element = document.getElementById(`my-${type}`);
+    const shadowRoot = internals.shadowRoot(element);
+
+    const firstField = getElementByPseudoId(shadowRoot, fields[1]);
+    assert_true(!!firstField, `Should find ${fields[1]}`);
+    const initialStyle = window.getComputedStyle(firstField);
+    assert_equals(initialStyle.fontFamily, 'Ahem', `${type} field should use author font initially`);
+
+    internals.setSuggestedValue(element, value);
+
+    fields.forEach(pseudoId => {
+      const el = getElementByPseudoId(shadowRoot, pseudoId);
+      if (el) {
+        const style = window.getComputedStyle(el);
+        assert_not_equals(style.fontFamily, 'Ahem',
+          `${pseudoId} should not use author font in preview state for ${type}.`);
+      }
+    });
+  }, `Autofill preview should not use author fonts for ${type}`);
+});
+</script>
Loading diff…

Original Bug Report

reported by [email protected]

Cross-origin autofill preview leak in temporal inputs via lazy font loading

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential cross-origin information leak exists where autofill previews inside temporal input elements (such as type=month or type=date) are rendered in author-controlled fonts. Because temporal inputs do not use standard text placeholders, they bypass the ::-internal-input-suggested font-pinning defense. An attacker can use custom CSS @font-face rules with unicode-range definitions to detect which digits are rendered, potentially leaking the digit set of the user’s stored credit card expiry date or birthdate during hover previews.

Affected files:

  • third_party/blink/renderer/core/html/forms/multiple_fields_temporal_input_type_view.cc
  • third_party/blink/renderer/core/html/forms/text_control_element.cc
  • third_party/blink/renderer/core/html/forms/html_input_element.cc
  • components/autofill/core/browser/filling/payments/field_filling_payments_util.cc
  • components/autofill/content/renderer/form_autofill_util.cc

Estimated timestamp from git blame: 2019-06-14

Description

When a standard text input field receives an autofill preview (suggested value), the previewed text is rendered within a placeholder element styled with the ::-internal-input-suggested pseudo-element ID. The user-agent stylesheet contains a rule pinning this pseudo-element to a default control font:

input::-internal-input-suggested,
textarea::-internal-input-suggested {
    font: -webkit-small-control !important;
    font-feature-settings: normal !important;
}

This prevents the page’s author-defined CSS from controlling the font-family and styling of the previewed values. However, temporal input fields (handled via MultipleFieldsTemporalInputTypeView) bypass this style-pinning defense.

When HTMLInputElement::SetSuggestedValue() is called, it triggers TextControlElement::SetSuggestedValue(). In TextControlElement::SetSuggestedValue(), a placeholder is queried:

HTMLElement* placeholder = UpdatePlaceholderText();
if (!placeholder)
  return; // Early return for temporal/date fields!

Because temporal inputs do not use standard text placeholders, UpdatePlaceholderText() returns nullptr, prompting an early return before the kPseudoInternalInputSuggested pseudo-ID can be applied. Instead, the suggested value is parsed and written directly into the DOM text nodes of the individual subfields of MultipleFieldsTemporalInputTypeView::UpdateView(), which are styled with font: inherit !important; in input_multiple_fields.css.

As a result, when a preview value is displayed, it inherits the parent <input> element’s author-defined font. An attacker can exploit this via custom @font-face declarations with unicode-range descriptors to detect which characters are loaded by the browser during the hover-preview state, resulting in a cross-origin leak of stored date/expiry information prior to any form submission.


Potential Attack Scenario

Note: These are potential steps based on code analysis, as our tooling does not currently have the capability to execute code.

  1. A page serves a form with a credit card number input and a temporal month input:
    <input name="ccnum" autocomplete="cc-number">
    <input type="month" autocomplete="cc-exp" max="2022-12">
    
  2. The month input is styled to use a custom font family targeting individual digits (0 through 9) using unicode-range definitions, each pointing to a distinct probe URL on the attacker’s server:
    input[type="month"] {
      font-family: LeakFont;
    } 
    @font-face {
      font-family: LeakFont;
      src: url('/probe-3');
      unicode-range: U+0033;
    }
    /* Repeat for all digits */
    
  3. The user focuses the credit card number field and hovers over an autofill suggestion in the dropdown list.
  4. When the browser previews the expiration date (e.g., 2028-07), it writes the parsed digits into the subfield text nodes of the temporal input. These inherit the parent’s LeakFont family.
  5. To shape and render the digits 2, 0, 8, and 7, the browser evaluates the matching unicode-range definitions and lazily requests /probe-2, /probe-0, /probe-8, and /probe-7 from the attacker’s server. By tracking which probes are requested, the attacker learns the set of digits present in the user’s stored card expiration date.

Suggested Fix

To remediate this issue, temporal input subfields should be styled with a default pinned font whenever the input element is in an autofill-previewed state. This can be achieved by utilizing the existing -internal-autofill-previewed pseudo-class in third_party/blink/renderer/core/html/resources/input_multiple_fields.css:

input:-internal-autofill-previewed::-webkit-datetime-edit-ampm-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-day-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-hour-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-millisecond-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-minute-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-month-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-second-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-week-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-year-field,
input:-internal-autofill-previewed::-webkit-datetime-edit-text {
    font: -webkit-small-control !important;
    font-feature-settings: normal !important;
}

Evaluated with Chrome root at commit: b1520ef4a76878853a31f0943b565e42060edec8


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker