CVE-2026-43795
Overview
Impact:
Description: Processing maliciously crafted web content may lead to an unexpected Safari crash
Researchers: wwwlk
Key insight. The nested credProps lookup reused the outer iterator and compared the submap’s find() result against the OUTER map’s end(), so a missing ‘rk’ key dereferenced an iterator from the wrong container.
Patch Details
diff --git a/Source/WebCore/Modules/webauthn/AuthenticationExtensionsClientOutputs.cpp b/Source/WebCore/Modules/webauthn/AuthenticationExtensionsClientOutputs.cpp
index 39563d3ba66d..897f6a34e6a9 100644
--- a/Source/WebCore/Modules/webauthn/AuthenticationExtensionsClientOutputs.cpp
+++ b/Source/WebCore/Modules/webauthn/AuthenticationExtensionsClientOutputs.cpp
@@ -49,9 +49,10 @@ std::optional<AuthenticationExtensionsClientOutputs> AuthenticationExtensionsCli
it = decodedMap.find(cbor::CBORValue("credProps"));
if (it != decodedMap.end() && it->second.isMap()) {
CredentialPropertiesOutput credProps;
- it = it->second.getMap().find(cbor::CBORValue("rk"));
- if (it != decodedMap.end() && it->second.isBool())
- credProps.rk = it->second.getBool();
+ const auto& credPropsMap = it->second.getMap();
+ auto credPropsIt = credPropsMap.find(cbor::CBORValue("rk"));
+ if (credPropsIt != credPropsMap.end() && credPropsIt->second.isBool())
+ credProps.rk = credPropsIt->second.getBool();
clientOutputs.credProps = credProps;
}
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
index a8af4b1fa479..3b6c2d114d04 100644
--- a/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
@@ -31,6 +31,7 @@
#if ENABLE(WEB_AUTHN)
+#include <WebCore/AuthenticationExtensionsClientOutputs.h>
#include <WebCore/CBORReader.h>
#include <limits>
#include <utility>
@@ -764,6 +765,20 @@ TEST(CBORReaderTest, TestUnsupportedSimplevalue)
}
}
+TEST(CBORReaderTest, AuthExtensionsFromCBOR_CredPropsWithoutRk)
+{
+ // CBOR encoding of {"credProps": {}} — credProps map present but no "rk" key.
+ // a1 -- map(1)
+ // 69 -- text(9)
+ // 63726564 50726f7073 -- "credProps"
+ // a0 -- map(0)
+ Vector<uint8_t> cborData { 0xa1, 0x69, 0x63, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, 0x73, 0xa0 };
+ auto result = WebCore::AuthenticationExtensionsClientOutputs::fromCBOR(cborData);
+ ASSERT_TRUE(result.has_value());
+ ASSERT_TRUE(result->credProps.has_value());
+ EXPECT_FALSE(result->credProps->rk);
+}
+
} // namespace TestWebKitAPI
#endif // ENABLE(WEB_AUTHN)
Background
Advisory: Apple Security Advisory
| Attribute | Value |
|---|---|
| CVE | CVE-2026-43795 |
| Bugzilla | 313452 |
| Component | WebCore |
| Bug Class | OOB |
| Severity | medium |
| Commit | ce11a67281dafaa7… |
| Advisory | Apple Advisory |
Terminology
- CBOR — Concise Binary Object Representation, the binary map/array format WebAuthn uses for authenticator data and extension outputs.
- credProps extension — A WebAuthn client extension whose output is a map that may contain a boolean ‘rk’ (resident key) flag.
- Iterator container mismatch — Comparing or dereferencing an iterator against a different container’s end() is undefined behavior and can read invalid memory.
Root Cause Analysis
This fixes a logic error — comparing and dereferencing a hash-map iterator against the wrong container — in WebAuthn CBOR parsing. AuthenticationExtensionsClientOutputs::fromCBOR decodes the top-level CBOR map (decodedMap), finds the ‘credProps’ entry, and then tried to look up the nested ‘rk’ key by REUSING the same iterator variable: it = it->second.getMap().find(cbor::CBORValue(“rk”)), then tested if (it != decodedMap.end() && it->second.isBool()). The find() runs on the nested credProps submap and returns an iterator into THAT submap, but the code compared it against decodedMap.end() — the end of the OUTER map — and reassigned the outer iterator in the process. Comparing iterators from two different containers is undefined behavior, and when ‘rk’ is absent from credProps the submap’s find() returns the submap’s end iterator; testing it against the wrong end and then dereferencing it->second reads past/into an invalid iterator, causing an out-of-bounds read / crash. The fix takes a stable reference to the nested map (const auto& credPropsMap = it->second.getMap()), searches it with a separate iterator (credPropsIt), and compares against credPropsMap.end() before reading credPropsIt->second. The restored invariant is that an iterator is only compared and dereferenced against its own container. The regression test decodes {“credProps”: {}} (credProps present, no ‘rk’) and expects a valid result with credProps->rk false.
Attack Path
1. Return a crafted assertion
A malicious authenticator/site supplies a WebAuthn response whose CBOR client-extension outputs contain a credProps map with no ‘rk’ key.
2. Parse the extension outputs
WebKit calls AuthenticationExtensionsClientOutputs::fromCBOR, which searches the credProps submap for ‘rk’.
3. Compare against the wrong end
The submap’s end iterator is compared to the outer map’s end (undefined behavior) and then dereferenced.
4. Crash / OOB read
Dereferencing the invalid iterator reads out of bounds, crashing the WebContent process.
Impact Assessment
An out-of-bounds read / crash in the WebContent process when parsing attacker-supplied WebAuthn extension-output CBOR. The primitive is a mis-compared/mis-dereferenced iterator on the parsing path, which the advisory frames as a crash; it is a memory-safety bug reachable wherever WebAuthn assertion/attestation responses are processed.
Audit Directions
Same file: nested map lookups
Audit AuthenticationExtensionsClientOutputs and nearby WebAuthn CBOR parsers for find() results compared to a different map’s end() or reused iterator variables across nested maps.
CBOR getMap()/find patterns
Grep for getMap().find(…) followed by comparison to an outer .end(); ensure each comparison uses the same map the find() ran on.
Changed Functions
| Function | File | Change | Note |
|---|---|---|---|
AuthenticationExtensionsClientOutputs::fromCBOR |
Source/WebCore/Modules/webauthn/AuthenticationExtensionsClientOutputs.cpp |
modified | Searches the nested credProps map with its own iterator (credPropsIt) compared against credPropsMap.end(), instead of reusing the outer iterator and comparing to decodedMap.end(). |
CBORReaderTest.AuthExtensionsFromCBOR_CredPropsWithoutRk |
Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp |
added | Regression test decoding {“credProps”:{}} to ensure a missing ‘rk’ key no longer misuses the iterator. |
Files Changed
Source Files
Source/WebCore/Modules/webauthn/AuthenticationExtensionsClientOutputs.cpp
Test Files
Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
Regression Test
The fix ships this proof-of-concept / regression test:
diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
index a8af4b1fa479..3b6c2d114d04 100644
--- a/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebCore/CBORReaderTest.cpp
@@ -31,6 +31,7 @@
#if ENABLE(WEB_AUTHN)
+#include <WebCore/AuthenticationExtensionsClientOutputs.h>
#include <WebCore/CBORReader.h>
#include <limits>
#include <utility>
@@ -764,6 +765,20 @@ TEST(CBORReaderTest, TestUnsupportedSimplevalue)
}
}
+TEST(CBORReaderTest, AuthExtensionsFromCBOR_CredPropsWithoutRk)
+{
+ // CBOR encoding of {"credProps": {}} — credProps map present but no "rk" key.
+ // a1 -- map(1)
+ // 69 -- text(9)
+ // 63726564 50726f7073 -- "credProps"
+ // a0 -- map(0)
+ Vector<uint8_t> cborData { 0xa1, 0x69, 0x63, 0x72, 0x65, 0x64, 0x50, 0x72, 0x6f, 0x70, 0x73, 0xa0 };
+ auto result = WebCore::AuthenticationExtensionsClientOutputs::fromCBOR(cborData);
+ ASSERT_TRUE(result.has_value());
+ ASSERT_TRUE(result->credProps.has_value());
+ EXPECT_FALSE(result->credProps->rk);
+}
+
} // namespace TestWebKitAPI
#endif // ENABLE(WEB_AUTHN)