Low watch CVSS 5.3 chrome Info Disclosure 🔧 Commit mapped

Overview

Low
Severity
5.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactSide-channel information leakage in Skia
DescriptionSide-channel information leakage in Skia
ComponentSkia
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.
Tracker506377118
Fix commita36b97ccf34e (skia) +29/-8
CWECWE-1300
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-04-25 (per vendor advisory)
Fix landed2026-06-23 (public git)
Disclosed2026-07-29
Patch gap36 days — fix public in source before the advisory

Background

Hash-flooding DoS
an attack that feeds many keys colliding into the same hash bucket, degrading a hash table to worst-case behavior, which expat mitigates by salting its internal string hash.
`XML_SetHashSalt`
the expat API that seeds the parser’s internal string-hash function so the bucket layout is not predictable to an attacker.
Hash salt as a side channel
because the salt value shapes observable hash ordering/timing, deriving it from a secret in-process value can let that value be inferred by an outside observer.
`SkRandom`
Skia’s portable pseudo-random generator that produces values without pulling from OS entropy sources such as Windows’ rand_s.

Root Cause Analysis

Before the patch, src/xml/SkXMLParser.cpp derived the expat hash salt from kHashSeed, a static pointer initialized to its own address (constexpr const void* kHashSeed = &kHashSeed;), then passed the low 32 bits of that address to XML_SetHashSalt. Using a live pointer value as the salt means the salt is a direct function of the process’s memory layout, so the observable hashing behavior it controls becomes a side channel that can leak address information (an ASLR-related secret). This violates the invariant that a value chosen to be hard-to-guess must not itself be derived from, and thus disclose, sensitive process state.

The fix replaces kHashSeed with get_hash_salt, which computes a per-process salt once from SkTime::GetNSecs() fed through SkRandom, ensuring a value that is non-deterministic and unguessable while carrying no memory-layout information. Because SkRandom is portable and avoids external entropy, it also preserves the original goal of not calling rand_s inside Windows sandboxed processes, keeping the anti-DoS protection intact.

Key insight
The single mistake was seeding the expat hash salt from a runtime pointer address (kHashSeed), turning an anti-DoS value into a channel that leaks memory-layout information; the fix derives the salt from a time-seeded SkRandom value instead, so it stays unguessable without exposing any pointer.

Attack Path

  1. Trigger XML parsing Get the target to parse attacker-influenced XML through SkXMLParser, which sets up an expat parser and applies the hash salt via XML_SetHashSalt.
  2. Observe salt-dependent behavior Because the salt derived from kHashSeed controls expat’s string-hash bucket layout, craft inputs whose parse-time behavior (e.g., collision-dependent timing/ordering) varies with the salt value. (inferred)
  3. Recover the salt bits Use the observed side channel to infer the salt, which equals the low 32 bits of the kHashSeed pointer address. (inferred)
  4. Derive layout information Reconstruct part of the process’s address layout from the leaked pointer bits, undermining ASLR as a defense. (inferred)

Impact Assessment

An attacker who can induce XML parsing and observe salt-dependent hashing behavior gains a side channel that can disclose in-process memory-layout information, weakening ASLR in whatever process performs the parsing. The advisory classifies this as a LogicError causing side-channel information leakage in Skia and states no exploited-in-the-wild status. Any further escalation from the leaked address bits to a memory-corruption primitive or code execution is not demonstrated by the diff and would be (inferred).

Files Changed

  • src/xml/SkXMLParser.cpp

Audit Directions

  • Secrets used as salts/seeds
    Look for salts, seeds, tokens, or nonces derived from pointer values, addresses, or other in-process secrets whose downstream effects are externally observable.
  • Pointer-to-integer casts feeding observable logic
    Flag reinterpret_cast<size_t>/address-of patterns whose result influences hashing, ordering, or timing that an attacker can measure.
  • Third-party randomness hooks
    Audit other expat/library seeding hooks (like XML_SetHashSalt) across Skia and Chrome to confirm they use a portable, entropy-safe RNG rather than convenient but leaky values.
From a36b97ccf34e2b7e420655e806b9bc591f93e57d Mon Sep 17 00:00:00 2001
From: Kaylee Lubick <kjlubick@google.com>
Date: Tue, 23 Jun 2026 13:35:54 +0000
Subject: [PATCH] Fix salt value used for expat in parsing XML

We started setting the salt in [1] to avoid using the
secure PRNG generator on Windows [2][3] but the choice of
using a pointer was undesirable (see linked bug).

This uses SkRandom and the time to avoid leaking info while
using a hard-to-guess salt to mitigate the original
hash-flooding DOS attack without causing additional problems.
SkRandom is portable and doesn't use any external sources of
entropy, avoiding the original problem.

[1] https://review.skia.org/730076

Bug: 506377118
Fixed: 506377118
Change-Id: Ib059d2e4da6bca5e5c4c2a284d4de5693f307890
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1268116
Auto-Submit: Kaylee Lubick <kjlubick@google.com>
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Florin Malita <fmalita@google.com>
---

diff --git a/src/xml/SkXMLParser.cpp b/src/xml/SkXMLParser.cpp
index bdda61d..5807445 100644
--- a/src/xml/SkXMLParser.cpp
+++ b/src/xml/SkXMLParser.cpp
@@ -4,13 +4,16 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+#include "src/xml/SkXMLParser.h"
 
 #include "include/core/SkStream.h"
 #include "include/core/SkString.h"
 #include "include/core/SkTypes.h"
 #include "include/private/SkTemplates.h"
 #include "include/private/SkTo.h"
-#include "src/xml/SkXMLParser.h"
+#include "src/core/SkRandom.h"
+#include "src/core/SkTime.h"
+#include "src/core/SkUtils.h"
 
 #include <expat.h>
 
@@ -59,7 +62,24 @@
 
 namespace {
 
-constexpr const void* kHashSeed = &kHashSeed;
+// Return a random number based on the clock to be consistent
+// across platforms yet hard to guess and not leaking information.
+static uint32_t get_hash_salt() {
+    static const uint32_t s_salt = []() {
+        double nsecs = SkTime::GetNSecs();
+        uint64_t timeVal = sk_bit_cast<uint64_t>(nsecs);
+        uint32_t seed = static_cast<uint32_t>(timeVal ^ timeVal >> 32);
+
+        SkRandom rand(seed);
+        uint32_t salt = rand.nextU();
+        while (salt == 0) [[unlikely]] {
+            // Expat hash seed must be non-zero or the default cPRNG will be used.
+            salt = rand.nextU();
+        }
+        return salt;
+    }();
+    return s_salt;
+}
 
 const XML_Memory_Handling_Suite sk_XML_alloc = {
     sk_malloc_throw,
@@ -149,12 +169,13 @@
         return false;
     }
 
-    // Avoid calls to rand_s if this is not set. This seed helps prevent DOS
-    // with a known hash sequence so an address is sufficient. The provided
-    // seed should not be zero as that results in a call to rand_s.
-    unsigned long seed = static_cast<unsigned long>(
-        reinterpret_cast<size_t>(kHashSeed) & 0xFFFFFFFF);
-    XML_SetHashSalt(ctx.fXMLParser, seed ? seed : 1);
+    // Expat calls to rand_s if no salt is set, which is not allowed on Windows.
+    // https://crbug.com/40088338
+    // Setting the salt helps prevent DOS with a known hash sequence. Generating a
+    // random salt once per process oursevles ensures the salt is non-deterministic
+    // and unguessable, while preventing calls to rand_s inside sandboxed processes
+    // on Windows.
+    XML_SetHashSalt(ctx.fXMLParser, get_hash_salt());
 
     XML_SetUserData(ctx.fXMLParser, &ctx);
     XML_SetElementHandler(ctx.fXMLParser, start_element_handler, end_element_handler);
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.