Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactHeap buffer overflow in Sync
DescriptionHeap buffer overflow in Sync
ComponentSync
Bug ClassOOB
Tracker443196747
Fix commit0e63d7ab6292 (chromium/src) +18/-2
CISA KEVNot listed
Creditedraven at KunLun lab
Disclosed2025-10-07

Changed Functions

FunctionChangeNotes
TEST_F
components/trusted_vault/securebox_unittest.cc
modified

Files Changed

  • components/trusted_vault/securebox.cc
  • components/trusted_vault/securebox_unittest.cc
From 0e63d7ab62928f5645a42484fbf47cba43b0128f Mon Sep 17 00:00:00 2001
From: Mikel Astiz <[email protected]>
Date: Fri, 26 Sep 2025 11:49:35 -0700
Subject: [PATCH] [TrustedVault] Fix public import missing size validation

`SecureBoxPublicKey::CreateByImport()` should have safeguards against
input data not matching the expected size, and return null in that case.

Bug: 443196747
Change-Id: I0996dbe383a51b1fd8269fbe429c78f24f283989
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6990129
Reviewed-by: Maksim Moskvitin <[email protected]>
Commit-Queue: Mikel Astiz <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1521442}
---

diff --git a/components/trusted_vault/securebox.cc b/components/trusted_vault/securebox.cc
index 384c7c5..ad63561 100644
--- a/components/trusted_vault/securebox.cc
+++ b/components/trusted_vault/securebox.cc
@@ -63,11 +63,16 @@
   return result;
 }
 
-// Creates public EC_KEY from |public_key_bytes|. |public_key_bytes| must be
-// a X9.62 formatted NIST P-256 point.
+// Creates public EC_KEY from |public_key_bytes|. Returns nullptr if
+// |public_key_bytes| does not represent a X9.62 formatted NIST P-256 point.
 bssl::UniquePtr<EC_KEY> ECPublicKeyFromBytes(
     base::span<const uint8_t> public_key_bytes,
     const crypto::OpenSSLErrStackTracer& err_tracer) {
+  if (public_key_bytes.size() != kECPointLength) {
+    // |public_key_bytes| doesn't represent a valid NIST P-256 point.
+    return nullptr;
+  }
+
   bssl::UniquePtr<EC_KEY> ec_key(
       EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
   DCHECK(ec_key);
diff --git a/components/trusted_vault/securebox_unittest.cc b/components/trusted_vault/securebox_unittest.cc
index dfd08987..45622b3 100644
--- a/components/trusted_vault/securebox_unittest.cc
+++ b/components/trusted_vault/securebox_unittest.cc
@@ -25,6 +25,7 @@
 
 using testing::Eq;
 using testing::IsEmpty;
+using testing::IsNull;
 using testing::Ne;
 using testing::NotNull;
 using testing::SizeIs;
@@ -43,6 +44,16 @@
   const std::vector<uint8_t> kTestPayload = StringToBytes("TEST_PAYLOAD");
 };
 
+TEST_F(SecureBoxTest, ShouldReturnNullIfCreateByImportWithIncorrectSize) {
+  // Sizes other than `kPublicKeyLengthInBytes` should return null.
+  EXPECT_THAT(SecureBoxPublicKey::CreateByImport(std::vector<uint8_t>(64, 1)),
+              IsNull());
+  EXPECT_THAT(SecureBoxPublicKey::CreateByImport(std::vector<uint8_t>(66, 1)),
+              IsNull());
+  EXPECT_THAT(SecureBoxPublicKey::CreateByImport(std::vector<uint8_t>()),
+              IsNull());
+}
+
 TEST_F(SecureBoxTest, ShouldExportAndImportPublicKey) {
   std::unique_ptr<SecureBoxKeyPair> key_pair =
       SecureBoxKeyPair::GenerateRandom();
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/trusted_vault/securebox_unittest.cc b/components/trusted_vault/securebox_unittest.cc
index dfd08987..45622b3 100644
--- a/components/trusted_vault/securebox_unittest.cc
+++ b/components/trusted_vault/securebox_unittest.cc
@@ -25,6 +25,7 @@
 
 using testing::Eq;
 using testing::IsEmpty;
+using testing::IsNull;
 using testing::Ne;
 using testing::NotNull;
 using testing::SizeIs;
@@ -43,6 +44,16 @@
   const std::vector<uint8_t> kTestPayload = StringToBytes("TEST_PAYLOAD");
 };
 
+TEST_F(SecureBoxTest, ShouldReturnNullIfCreateByImportWithIncorrectSize) {
+  // Sizes other than `kPublicKeyLengthInBytes` should return null.
+  EXPECT_THAT(SecureBoxPublicKey::CreateByImport(std::vector<uint8_t>(64, 1)),
+              IsNull());
+  EXPECT_THAT(SecureBoxPublicKey::CreateByImport(std::vector<uint8_t>(66, 1)),
+              IsNull());
+  EXPECT_THAT(SecureBoxPublicKey::CreateByImport(std::vector<uint8_t>()),
+              IsNull());
+}
+
 TEST_F(SecureBoxTest, ShouldExportAndImportPublicKey) {
   std::unique_ptr<SecureBoxKeyPair> key_pair =
       SecureBoxKeyPair::GenerateRandom();
Loading diff…

Original Bug Report

reported by [email protected]

out of bound in function ECPublicKeyFromBytes

Steps to reproduce the problem

my chromim commit is 6a99accd9be43e397fe4e41571a7e1f5c656ab0d

  1. Apply my patch and build Chromium.(This patch only removes the account check that is unrelated to the vulnerability. Since Chromium generally does not have Chrome accounts, I have temporarily disabled it.)
  2. out\asan\chrome.exe –no-sandbox https://accounts.google.com/
  3. Enter the code in the browser’s address bar
jaavscript:let buffer = new ArrayBuffer(1);let view = new Uint8Array(buffer);view[0] = 4;chrome.addTrustedSyncEncryptionRecoveryMethod(()=>{console.log("123")},"test", buffer,2);

you will see the asan output

Problem Description

the function https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/trusted_vault_encryption_keys_extension.mojom;l=28;drc=e3ad182cacc3a02eb6a13091a867815fd17a129c;bpv=0;bpt=1
AddTrustedRecoveryMethod(string gaia_id, array<uint8> public_key, int32 method_type_hint) => ();

This function receives a public_key sent from the renderer, but it does not perform any length validation. As a result, if the renderer sends malicious data, it will be passed directly to the EC_POINT_oct2point function for parsing, which leads to an out-of-bounds read.

Since the renderer parameters are not properly checked here, an exploit prerequisite is either an XSS on accounts.google.com (allowing us to execute arbitrary JavaScript), or a renderer RCE that can send arbitrary IPC messages.

let buffer = new ArrayBuffer(1);
let view = new Uint8Array(buffer);
view[0] = 4;
chrome.addTrustedSyncEncryptionRecoveryMethod(()=>{console.log("123")},"test", buffer,2);

When this JavaScript snippet is executed on the accounts.google.com page, the buffer with length 1 is passed to EC_POINT_oct2point for parsing, resulting in an out-of-bounds read in the browser process.

Summary

out of bound in function ECPublicKeyFromBytes

Custom Questions

Type of crash:

browser

Reporter credit:

raven at KunLun Lab

Additional Data

Category: Security
Chrome Channel: Not sure
Regression: N/A \

View on issue tracker