---
id: GHSA-6hxq-p678-4hr2
title: >-
  SimpleWebAuthn: Registration verification does not sufficiently ensure that
  attestation certificates chain to a trust anchor
summary: >-
  SimpleWebAuthn: Registration verification does not sufficiently ensure that
  attestation certificates chain to a trust anchor
severity: low
cwe:
  - CWE-295
  - CWE-296
vendor: simplewebauthn
product: '@simplewebauthn/server'
ecosystem: npm
affected:
  - '@simplewebauthn/server <= 13.3.1'
patched:
  - '@simplewebauthn/server 13.3.2'
published: '2026-09-04'
updated: '2026-09-04'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-6hxq-p678-4hr2'
references:
  - url: >-
      https://github.com/MasterKale/SimpleWebAuthn/security/advisories/GHSA-6hxq-p678-4hr2
  - url: >-
      https://github.com/MasterKale/SimpleWebAuthn/commit/67a41fed3dfd96cab1dcf414f6d1792a72e06e35
  - url: >-
      https://github.com/MasterKale/SimpleWebAuthn/commit/8a53d70f42bcbb7c744ef1b90e6db35bc4b26d06
  - url: >-
      https://github.com/MasterKale/SimpleWebAuthn/commit/dd0d73c716a528e6645efafbd43a972b64df71f9
  - url: 'https://github.com/MasterKale/SimpleWebAuthn/releases/tag/v13.3.2'
  - url: 'https://github.com/advisories/GHSA-6hxq-p678-4hr2'
tags:
  - ghsa
  - npm
ingestedAt: '2026-09-04T18:25:57.348Z'
---

## Overview

## 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**):

```ts
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**):

```ts
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

- `@simplewebauthn/server <= 13.3.1`

## Remediation

Upgrade to a patched release:

- `@simplewebauthn/server 13.3.2`
