Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
📦 npm
Not in CISA KEV

SimpleWebAuthn: Registration verification does not sufficiently ensure that attestation certificates chain to a trust anchorGHSA-6hxq-p678-4hr2

Fix: MasterKale/SimpleWebAuthn@67a41fe

GHSA-6hxq-p678-4hr2 is a security vulnerability in @simplewebauthn/server. A fix is available for @simplewebauthn/server — see the affected versions and patch details below.

Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Sep 4, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

464other npm packages depend on this — each one inherits the vulnerability until it's patched upstream
@simplewebauthn/servernpm
4.2Mdownloads / week

Description

Summary

validateCertificatePath() does not verify that an attestation's certificate chain actually terminates at a configured trust anchor. When walking the chain it stops at the first self-signed certificate it finds (which could be user-supplied), and exits early.

This happens before the configured Apple/Google/etc trust anchor (which is concatenated to the end of the chain) is reached.

A user can therefore register a credential and have the server accept it as if it were backed by a genuine Apple / Android SafetyNet / Yubikey / etc.

Details

packages/server/src/helpers/validateCertificatePath.ts:

The configured trust anchor is appended to the end of the untrusted chain (line 83):

const x5cWithTrustAnchor = x5cCertsParsed.concat([anchor]);

The walk then verifies each cert was signed by the next, but breaks on the first self-signed cert (lines 104–116):

if (issuer.subject === issuer.issuer) {
  // Root cert detected, make sure it signed itself
  const issuerSignedIssuer = await issuer.verify(
    { publicKey: issuer.publicKey, signatureOnly: true },
    WebCrypto,
  );
  if (!issuerSignedIssuer) {
    throw new InvalidSubjectAndIssuer();
  }
  break;   // <-- exits before the appended trust anchor is ever checked if user supplied self-signed cert comes first
}

The success condition is therefore "the certs form an internally-consistent chain ending in some self-signed cert" Rather than "the chain terminates at one of the configured trust anchors."

Exploit shape

attacker sends:  x5c = [ forgedLeaf (signed by attacker root),
                         attackerSelfSignedRoot ]

library builds:  [ forgedLeaf, attackerSelfSignedRoot, <configured Apple/Google/etc root> ]

walk:  forgedLeaf -> attackerSelfSignedRoot        (verifies, attacker controls both)
       attackerSelfSignedRoot is self-signed        -> break
       attackerSelfSignedRoot -> configured root    (NEVER CHECKED)

return true. The configured anchor never gets checked.

As far as observed, all attestation enforcement uses validateCertificatePath when using MDS etc.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
📦npm@simplewebauthn/serverall versions13.3.2npm install @simplewebauthn/server@13.3.2

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for @simplewebauthn/server, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update @simplewebauthn/server to 13.3.2 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-6hxq-p678-4hr2 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Frequently Asked Questions

## Summary `validateCertificatePath()` does not verify that an attestation's certificate chain actually terminates at a configured trust anchor. When walking the chain it stops at the first self-signed certificate it finds (which could be user-supplied), and exits early. This happens before the configured Apple/Google/etc trust anchor (which is concatenated to the end of the chain) is reached. A user can therefore register a credential and have the server accept it as if it were backed by a genuine Apple / Android SafetyNet / Yubikey / etc. ## Details `packages/server/src/helpers/validateCe
O3 Security · Impact-Aware SCA

Is GHSA-6hxq-p678-4hr2 in your dependencies?

Find it across npm, including transitive dependencies.

SimpleWebAuthn: Registration verification does not…