Common Weakness Enumeration

CWE-208

Allowed

Observable Timing Discrepancy

Abstraction: Base · Status: Incomplete

Two separate operations in a product require different amounts of time to complete, in a way that is observable to an actor and reveals security-relevant information about the state of the product, such as whether a particular operation was successful or not.

401 vulnerabilities reference this CWE, most recent first.

GHSA-7P89-P6HX-Q4FW

Vulnerability from github – Published: 2024-09-30 17:48 – Updated: 2024-09-30 20:11
VLAI
Summary
basic-auth-connect's callback uses time unsafe string comparison
Details

Impact

basic-auth-connect <1.1.0 uses a timing-unsafe equality comparison that can leak timing information

Patches

this issue has been fixed in basic-auth-connect 1.1.0

References

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "basic-auth-connect"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.1.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-47178"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-09-30T17:48:29Z",
    "nvd_published_at": "2024-09-30T16:15:09Z",
    "severity": "HIGH"
  },
  "details": "### Impact\n\nbasic-auth-connect \u003c1.1.0 uses a timing-unsafe equality comparison that can leak timing information\n\n### Patches\n\nthis issue has been fixed in basic-auth-connect 1.1.0\n\n### References\n",
  "id": "GHSA-7p89-p6hx-q4fw",
  "modified": "2024-09-30T20:11:40Z",
  "published": "2024-09-30T17:48:29Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/expressjs/basic-auth-connect/security/advisories/GHSA-7p89-p6hx-q4fw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-47178"
    },
    {
      "type": "WEB",
      "url": "https://github.com/expressjs/basic-auth-connect/commit/bac1e6a8530e1efd0028800b9b588a37adb0d203"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/expressjs/basic-auth-connect"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "basic-auth-connect\u0027s callback uses time unsafe string comparison"
}

GHSA-7Q92-Q5VC-5R4R

Vulnerability from github – Published: 2026-09-02 15:34 – Updated: 2026-09-02 21:32
VLAI
Details

Observable Timing Discrepancy vulnerability in Drupal Commerce CyberSource allows Brute Force. This issue affects Commerce CyberSource versions: from 0.0.0 to 1.10.0.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-81159"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-02T13:18:11Z",
    "severity": "LOW"
  },
  "details": "Observable Timing Discrepancy vulnerability in Drupal Commerce CyberSource allows Brute Force. This issue affects Commerce CyberSource versions: from 0.0.0 to 1.10.0.",
  "id": "GHSA-7q92-q5vc-5r4r",
  "modified": "2026-09-02T21:32:02Z",
  "published": "2026-09-02T15:34:46Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-81159"
    },
    {
      "type": "WEB",
      "url": "https://www.drupal.org/sa-contrib-2026-106"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-7R92-3JGR-R65Q

Vulnerability from github – Published: 2026-05-06 22:40 – Updated: 2026-05-14 20:42
VLAI
Summary
pyquorum: Timing side‑channel in mul_mod
Details

Impact

The mul_mod function implements multiplication via a binary expansion loop whose execution time depends on the Hamming weight of the second operand (the exponent). An attacker who can measure the time of secret‑sharing operations (e.g., via a remote service) could progressively recover the values of shares, ultimately leading to secret reconstruction.

Patches

https://github.com/svvqt/pyquorum/releases/tag/v0.2.1

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "pyquorum"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-44368"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-06T22:40:15Z",
    "nvd_published_at": "2026-05-13T21:16:47Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nThe `mul_mod` function implements multiplication via a binary expansion loop whose execution time depends on the Hamming weight of the second operand (the exponent). An attacker who can measure the time of secret\u2011sharing operations (e.g., via a remote service) could progressively recover the values of shares, ultimately leading to secret reconstruction.\n\n### Patches\nhttps://github.com/svvqt/pyquorum/releases/tag/v0.2.1",
  "id": "GHSA-7r92-3jgr-r65q",
  "modified": "2026-05-14T20:42:45Z",
  "published": "2026-05-06T22:40:15Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/svvqt/pyquorum/security/advisories/GHSA-7r92-3jgr-r65q"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44368"
    },
    {
      "type": "WEB",
      "url": "https://github.com/svvqt/pyquorum/commit/1e9ac41dd3c305c13d7a6b7d227bf325be82d730"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/svvqt/pyquorum"
    },
    {
      "type": "WEB",
      "url": "https://github.com/svvqt/pyquorum/releases/tag/v0.2.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "pyquorum: Timing side\u2011channel in mul_mod"
}

GHSA-7RW5-9F7Q-XJ36

Vulnerability from github – Published: 2026-07-24 16:55 – Updated: 2026-07-24 16:55
VLAI
Summary
Open WebUI: Account enumeration via observable login timing discrepancy
Details

Summary

The /api/v1/auths/signin endpoint leaked whether an email address belonged to a registered account through a response-time side channel. Password verification ran bcrypt only when the email was found in the database; for a non-existent email the request returned early without hashing. The expensive bcrypt comparison therefore made valid-account attempts respond significantly slower (~180 ms) than non-existent ones (~5 ms), so an unauthenticated attacker could enumerate valid accounts by measuring response time.

Details

On signin the backend looked the user up by email and only performed the bcrypt password comparison if a record existed. A missing email short-circuited before any hashing, producing the timing gap. The built-in brute-force throttling did not prevent it: sending one request at a time with a small delay between requests stays under the rate limit while still exposing the difference.

Observed in the reporter's run (HTTP 400 for every attempt, the response time is the signal):

Email                Status   Response time
joe@example.com      400      186 ms   <- valid account
larry@example.com    400        9 ms
jose@example.com     400        6 ms
james@example.com    400        5 ms

Impact

An unauthenticated attacker can enumerate which email addresses are registered accounts, which enables targeted password-spraying against confirmed accounts. The impact is amplified by MFA not being enabled by default. No data is read or modified; the disclosure is limited to account existence.

Patched

The authentication path now runs a bcrypt verification against a constant placeholder hash whenever the email does not resolve to an active credential, so a real hash comparison executes on every attempt and the response time is the same whether or not the account exists. Fixed in 0.10.0.

Credits

@dievus

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "open-webui"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.10.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-59218"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-24T16:55:06Z",
    "nvd_published_at": "2026-07-09T17:17:02Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\n\nThe `/api/v1/auths/signin` endpoint leaked whether an email address belonged to a registered account through a response-time side channel. Password verification ran bcrypt only when the email was found in the database; for a non-existent email the request returned early without hashing. The expensive bcrypt comparison therefore made valid-account attempts respond significantly slower (~180 ms) than non-existent ones (~5 ms), so an unauthenticated attacker could enumerate valid accounts by measuring response time.\n\n### Details\n\nOn signin the backend looked the user up by email and only performed the bcrypt password comparison if a record existed. A missing email short-circuited before any hashing, producing the timing gap. The built-in brute-force throttling did not prevent it: sending one request at a time with a small delay between requests stays under the rate limit while still exposing the difference.\n\nObserved in the reporter\u0027s run (HTTP 400 for every attempt, the response time is the signal):\n\n```\nEmail                Status   Response time\njoe@example.com      400      186 ms   \u003c- valid account\nlarry@example.com    400        9 ms\njose@example.com     400        6 ms\njames@example.com    400        5 ms\n```\n\n### Impact\n\nAn unauthenticated attacker can enumerate which email addresses are registered accounts, which enables targeted password-spraying against confirmed accounts. The impact is amplified by MFA not being enabled by default. No data is read or modified; the disclosure is limited to account existence.\n\n### Patched\n\nThe authentication path now runs a bcrypt verification against a constant placeholder hash whenever the email does not resolve to an active credential, so a real hash comparison executes on every attempt and the response time is the same whether or not the account exists. Fixed in 0.10.0.\n\n### Credits\n\n@dievus",
  "id": "GHSA-7rw5-9f7q-xj36",
  "modified": "2026-07-24T16:55:06Z",
  "published": "2026-07-24T16:55:06Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-7rw5-9f7q-xj36"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59218"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/pull/26385"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/commit/993e74912199c66c522f08ec81abe31d76985e39"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/open-webui/open-webui"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/releases/tag/v0.10.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Open WebUI: Account enumeration via observable login timing discrepancy"
}

GHSA-7W52-7JVM-M9VW

Vulnerability from github – Published: 2026-06-04 19:31 – Updated: 2026-06-11 14:06
VLAI
Summary
Shopware: Timing-attack on admin panel allowing enumeration of administrator usernames
Details

Summary

There is a Proof of Concept which is able to enumerate the usernames of administrator users. This was possible by performing a timing attack.

Details

The faulty code exists in src/Core/Framework/Api/OAuth/UserRepository.php:

public function getUserEntityByUserCredentials(
        string $username,
        #[\SensitiveParameter]
        string $password,
        string $grantType,
        ClientEntityInterface $clientEntity
    ): ?UserEntityInterface {
        if ($this->loginConfigService->getConfig()?->useDefault === false) {
            // never allow login via password if the default login is disabled (e.g. using SSO only)
            return null;
        }

        $builder = $this->connection->createQueryBuilder();
        $user = $builder->select('user.id', 'user.password')
            ->from('user')
            ->where('username = :username')
            ->setParameter('username', $username)
            ->fetchAssociative();

        // PATH 1: EARLY RETURN WHEN USERNAME IS NOT FOUND
        if (!$user) {
            return null;
        }

        // PATH 2: VERIFY PASSWORD IF USER IS FOUND
        if (!password_verify($password, (string) $user['password'])) {
            return null;
        }

        return new User(Uuid::fromBytesToHex($user['id']));
    }

Subroutine getUserEntityByUserCredentials() is called when an auth request is send to api/oauth/token. If the given username is not found an early return is done (PATH 1). Only if the user is found we verify the password using password_verify.

PHP method password_verify by default uses hashing algorithm Argon2id which by design is intentionally 'slow' by introducing a timing cost to an attempt to bruteforce hashes more costly.

Since password_verify has a notable executable time, PATH 2 where an user is found and verified will be slower on average then PATH 1 where we do an early return for non-existing users.

Proposed fix

Before doing the early return, password_verify a dummy hash.

Impact

  1. More targeted dictionary/bruteforce attacks.
  2. Spear phishing / eases social engineering.
  3. Credential stuffing from other data leaks.

Authors

Niel Duysters (@NielDuysters) and Thomas Brankaer (@tbrankaer)

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "shopware/platform"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "6.7.0.0"
            },
            {
              "fixed": "6.7.10.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "shopware/platform"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "6.6.10.18"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "shopware/core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "6.7.0.0"
            },
            {
              "fixed": "6.7.10.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "shopware/core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "6.6.10.18"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-48011"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-04T19:31:17Z",
    "nvd_published_at": "2026-06-10T22:17:00Z",
    "severity": "LOW"
  },
  "details": "### Summary\nThere is a Proof of Concept which is able to enumerate the usernames of administrator users. This was possible by performing a timing attack.\n\n### Details\nThe faulty code exists in [`src/Core/Framework/Api/OAuth/UserRepository.php`](https://github.com/shopware/shopware/blob/trunk/src/Core/Framework/Api/OAuth/UserRepository.php):\n```\npublic function getUserEntityByUserCredentials(\n        string $username,\n        #[\\SensitiveParameter]\n        string $password,\n        string $grantType,\n        ClientEntityInterface $clientEntity\n    ): ?UserEntityInterface {\n        if ($this-\u003eloginConfigService-\u003egetConfig()?-\u003euseDefault === false) {\n            // never allow login via password if the default login is disabled (e.g. using SSO only)\n            return null;\n        }\n\n        $builder = $this-\u003econnection-\u003ecreateQueryBuilder();\n        $user = $builder-\u003eselect(\u0027user.id\u0027, \u0027user.password\u0027)\n            -\u003efrom(\u0027user\u0027)\n            -\u003ewhere(\u0027username = :username\u0027)\n            -\u003esetParameter(\u0027username\u0027, $username)\n            -\u003efetchAssociative();\n\n        // PATH 1: EARLY RETURN WHEN USERNAME IS NOT FOUND\n        if (!$user) {\n            return null;\n        }\n\n        // PATH 2: VERIFY PASSWORD IF USER IS FOUND\n        if (!password_verify($password, (string) $user[\u0027password\u0027])) {\n            return null;\n        }\n\n        return new User(Uuid::fromBytesToHex($user[\u0027id\u0027]));\n    }\n```\n\nSubroutine `getUserEntityByUserCredentials()` is called when an auth request is send to `api/oauth/token`. If the given username is not found an early return is done (PATH 1). Only if the user is found we verify the password using `password_verify`.\n\nPHP method `password_verify` by default uses hashing algorithm Argon2id which by design is intentionally \u0027slow\u0027 by introducing a timing cost to an attempt to bruteforce hashes more costly.\n\nSince `password_verify` has a notable executable time, PATH 2 where an user is found and verified will be slower on average then PATH 1 where we do an early return for non-existing users.\n\n### Proposed fix\nBefore doing the early return, `password_verify` a dummy hash.\n\n### Impact\n1. More targeted dictionary/bruteforce attacks.\n2. Spear phishing / eases social engineering.\n3. Credential stuffing from other data leaks.\n\n### Authors\nNiel Duysters (@NielDuysters) and Thomas Brankaer (@tbrankaer)",
  "id": "GHSA-7w52-7jvm-m9vw",
  "modified": "2026-06-11T14:06:35Z",
  "published": "2026-06-04T19:31:17Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/shopware/shopware/security/advisories/GHSA-7w52-7jvm-m9vw"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48011"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/shopware/shopware"
    },
    {
      "type": "WEB",
      "url": "https://github.com/shopware/shopware/releases/tag/v6.6.10.18"
    },
    {
      "type": "WEB",
      "url": "https://github.com/shopware/shopware/releases/tag/v6.7.10.1"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Shopware: Timing-attack on admin panel allowing enumeration of administrator usernames"
}

GHSA-86J9-25M2-9W97

Vulnerability from github – Published: 2023-10-25 18:32 – Updated: 2023-11-02 17:12
VLAI
Summary
Non-constant time webhook token hash comparison in Jenkins Zanata Plugin
Details

Jenkins Zanata Plugin 0.6 and earlier does not use a constant-time comparison when checking whether the provided and expected webhook token hashes are equal.

This could potentially allow attackers to use statistical methods to obtain a valid webhook token.

As of publication of this advisory, there is no fix.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "org.jenkins-ci.plugins:zanata"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "0.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-46660"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208",
      "CWE-697"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-10-30T14:50:44Z",
    "nvd_published_at": "2023-10-25T18:17:40Z",
    "severity": "LOW"
  },
  "details": "Jenkins Zanata Plugin 0.6 and earlier does not use a constant-time comparison when checking whether the provided and expected webhook token hashes are equal.\n\nThis could potentially allow attackers to use statistical methods to obtain a valid webhook token.\n\nAs of publication of this advisory, there is no fix.",
  "id": "GHSA-86j9-25m2-9w97",
  "modified": "2023-11-02T17:12:46Z",
  "published": "2023-10-25T18:32:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46660"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jenkinsci/zanata-plugin"
    },
    {
      "type": "WEB",
      "url": "https://www.jenkins.io/security/advisory/2023-10-25/#SECURITY-2879"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2023/10/25/2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Non-constant time webhook token hash comparison in Jenkins Zanata Plugin"
}

GHSA-8859-V9JP-CPHF

Vulnerability from github – Published: 2023-10-25 18:32 – Updated: 2023-11-02 16:55
VLAI
Summary
Jenkins Multibranch Scan Webhook Trigger Plugin uses non-constant time webhook token comparison
Details

Jenkins Multibranch Scan Webhook Trigger Plugin 1.0.9 and earlier does not use a constant-time comparison when checking whether the provided and expected webhook token are equal.

This could potentially allow attackers to use statistical methods to obtain a valid webhook token.

As of publication of this advisory, there is no fix.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "igalg.jenkins.plugins:multibranch-scan-webhook-trigger"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.0.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-46656"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208",
      "CWE-697"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-10-30T14:58:39Z",
    "nvd_published_at": "2023-10-25T18:17:40Z",
    "severity": "LOW"
  },
  "details": "Jenkins Multibranch Scan Webhook Trigger Plugin 1.0.9 and earlier does not use a constant-time comparison when checking whether the provided and expected webhook token are equal.\n\nThis could potentially allow attackers to use statistical methods to obtain a valid webhook token.\n\nAs of publication of this advisory, there is no fix.",
  "id": "GHSA-8859-v9jp-cphf",
  "modified": "2023-11-02T16:55:44Z",
  "published": "2023-10-25T18:32:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46656"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jenkinsci/multibranch-scan-webhook-trigger-plugin"
    },
    {
      "type": "WEB",
      "url": "https://www.jenkins.io/security/advisory/2023-10-25/#SECURITY-2875"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2023/10/25/2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Jenkins Multibranch Scan Webhook Trigger Plugin uses non-constant time webhook token comparison"
}

GHSA-885R-HHPR-CC9P

Vulnerability from github – Published: 2023-10-25 18:32 – Updated: 2023-11-02 16:56
VLAI
Summary
Jenkins Gogs Plugin uses non-constant time webhook token comparison
Details

Jenkins Gogs Plugin 1.0.15 and earlier does not use a constant-time comparison when checking whether the provided and expected webhook token are equal.

This could potentially allow attackers to use statistical methods to obtain a valid webhook token.

As of publication of this advisory, there is no fix.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Maven",
        "name": "org.jenkins-ci.plugins:gogs-webhook"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "1.0.15"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-46657"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208",
      "CWE-697"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-10-30T14:55:53Z",
    "nvd_published_at": "2023-10-25T18:17:40Z",
    "severity": "LOW"
  },
  "details": "Jenkins Gogs Plugin 1.0.15 and earlier does not use a constant-time comparison when checking whether the provided and expected webhook token are equal.\n\nThis could potentially allow attackers to use statistical methods to obtain a valid webhook token.\n\nAs of publication of this advisory, there is no fix.",
  "id": "GHSA-885r-hhpr-cc9p",
  "modified": "2023-11-02T16:56:29Z",
  "published": "2023-10-25T18:32:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-46657"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jenkinsci/gogs-webhook-plugin"
    },
    {
      "type": "WEB",
      "url": "https://www.jenkins.io/security/advisory/2023-10-25/#SECURITY-2896"
    },
    {
      "type": "WEB",
      "url": "http://www.openwall.com/lists/oss-security/2023/10/25/2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Jenkins Gogs Plugin uses non-constant time webhook token comparison"
}

GHSA-8CH4-58QP-G3MP

Vulnerability from github – Published: 2021-06-11 17:43 – Updated: 2024-11-19 18:19
VLAI
Summary
Observable Timing Discrepancy in aaugustin websockets library
Details

The aaugustin websockets library before 9.1 for Python has an Observable Timing Discrepancy on servers when HTTP Basic Authentication is enabled with basic_auth_protocol_factory(credentials=...). An attacker may be able to guess a password via a timing attack.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "websockets"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "9.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-33880"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-203",
      "CWE-208"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-06-10T16:24:45Z",
    "nvd_published_at": "2021-06-06T15:15:00Z",
    "severity": "HIGH"
  },
  "details": "The aaugustin websockets library before 9.1 for Python has an Observable Timing Discrepancy on servers when HTTP Basic Authentication is enabled with basic_auth_protocol_factory(credentials=...). An attacker may be able to guess a password via a timing attack.",
  "id": "GHSA-8ch4-58qp-g3mp",
  "modified": "2024-11-19T18:19:55Z",
  "published": "2021-06-11T17:43:14Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-33880"
    },
    {
      "type": "WEB",
      "url": "https://github.com/aaugustin/websockets/commit/547a26b685d08cac0aa64e5e65f7867ac0ea9bc0"
    },
    {
      "type": "WEB",
      "url": "https://github.com/aaugustin/websockets"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/websockets/PYSEC-2021-95.yaml"
    },
    {
      "type": "WEB",
      "url": "https://www.oracle.com/security-alerts/cpuapr2022.html"
    },
    {
      "type": "WEB",
      "url": "https://www.oracle.com/security-alerts/cpujan2022.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Observable Timing Discrepancy in aaugustin websockets library"
}

GHSA-8FCF-V89G-XPG6

Vulnerability from github – Published: 2026-09-22 20:40 – Updated: 2026-09-22 20:40
VLAI
Summary
Traefik: BasicAuth singleflight coalescing reintroduces an unauthenticated username-enumeration timing oracle
Details

Summary

Traefik's BasicAuth middleware coalesces concurrent credential checks through a singleflight.Group to avoid hashing the same password many times at once. Since v3.6.11 the deduplication key was built from the submitted password plus the stored secret, so it depended on server state: a non-existent username collapsed onto one shared key while each configured username produced its own. Under attacker-controlled concurrency, a probe request arriving inside a leader request's in-flight window is served the leader's fast coalesced result when the username does not exist, but computes its own hash (slow) when the username exists — reintroducing, only in the concurrent case, the unauthenticated username-enumeration timing oracle that GHSA-g3hg-j4jv-cwfr had hardened for sequential probing. The fix derives the singleflight key from the submitted credentials (username and password) only, so it no longer depends on whether the account exists or on any stored secret. Traefik v2 is not affected: the v2.11 BasicAuth middleware does not use singleflight coalescing, and Digest authentication is not affected. The impact is limited to username enumeration; no credential disclosure or authentication bypass is possible.

The vulnerability originates on the v3.6 line, which has reached end of life; users on v3.6 or earlier v3.x must upgrade to v3.7.13 to receive the fix.

Patches

  • https://github.com/traefik/traefik/releases/tag/v3.7.13

For more information

If you have any questions or comments about this advisory, please open an issue.

Original Description ## Summary Confirmed. `checkPassword` derives the `singleflight` key from the *stored secret*, so the key encodes whether the submitted username exists: - username absent, `secret == ""`, key `= len(P) + ":" + P` - username present, key `= len(P) + ":" + P + secret_T` Every non-existent username therefore lands on one shared key, while every configured username gets its own. `singleflight.Group.Do` makes a follower on an equal key block on the leader's in-flight computation and return the leader's result. So an attacker who sends a leader request with a junk username and password `P`, then sends the probe for target `T` with the same `P` late inside the leader's window, reads user existence directly off the probe's latency: coalesced (fast) means `T` does not exist, own hash (slow) means `T` does exist. This is the exact information leak that the `notFoundSecret` dummy hash at line 127 exists to remove. Sequential probing is fully equalised (measured ratio 1.00x, so the fix for `cwfr` / `8j2h` does work); the leak reappears only under attacker-controlled concurrency. Confirmed on the current `v3.7` head, which already carries the `8mrf` singleflight fix, and on `master` (no later fix exists). ## Affected code - `pkg/middlewares/auth/basic_auth.go:125` (`checkPassword`) ## Code analysis `pkg/middlewares/auth/basic_auth.go:119-131` matches the finding verbatim, including the cited line 125:
func (b *basicAuth) checkPassword(user, password string) bool {   // :119
    secret := b.auth.Secrets(user, b.auth.Realm)                   // "" when the user is absent

    key := strconv.Itoa(len(password)) + ":" + password + secret   // :124
    match, _, _ := b.singleflightGroup.Do(key, func() (any, error) {   // :125
        if secret == "" {
            _ = b.checkSecret(password, b.notFoundSecret)          // :127  dummy hash, equal cost
            return false, nil
        }
        return b.checkSecret(password, secret), nil
    })
    return match.(bool)
}
Two independent properties combine: 1. **The dummy hash equalises the cost of one lookup.** `notFoundSecret` is a configured user's real hash (`slices.Collect(maps.Values(users))[0]`), so absent and present users each perform exactly one hash of the same algorithm and cost. That is why the sequential control below is flat. 2. **The key partitions on existence, so coalescing is not equalised.** The dummy hash was placed *inside* the closure (commit `122175ac2`, PR #12803), which is what pulls absent users into `Do` at all. Before that refactor, `secret == ""` returned `false` before `Do` was ever called. Git archaeology of the whole sequence in this one function: | Commit | Date | Effect | |---|---|---| | `6f469ee1e` | 2024-10-10 | Introduces `singleflight` to dedupe concurrent hashes (`Only calculate basic auth hashes once for concurrent requests`). Absent users returned `false` before `Do`. | | `122175ac2` (PR #12803) | 2026-03-17 | Fix for `cwfr`. Moves the empty-secret branch inside the closure, which makes the key existence-dependent for the first time. | | `8c4fc8957` | 2026-04-13 | Fix for `8j2h`: `notFoundSecret` was resolving to `""`, so the dummy hash was a no-op. | | `b5ace8eb5` (PR #13572) | 2026-07-28 | Fix for `8mrf`: adds the `len(password) + ":"` prefix so distinct (password, secret) pairs cannot alias. Keeps the secret in the key and keeps the empty-secret branch inside the closure. | J15 is the residue of that last fix. It does **not** depend on the key collision `8mrf` closed: the oracle works precisely *because* the keys differ. The prior analysis of `8mrf` recommended keeping "the empty-secret (unconfigured) path out of any key that a configured user can share"; the shipped patch only delimited the key, so the existence dependency survived. Affected range: `>= v3.6.11` (the `122175ac2` refactor) through current `v3.7` head and `master`. Not the v2 line, and not earlier v3 releases, which returned early for absent users. Digest auth does not use `singleflight` and is unaffected. Impact scope: username enumeration only. No credential disclosure, no authentication bypass, no result sharing across identities. ## Reproduction Go tests written directly in `package auth`, driving the real `NewBasic` handler over a real HTTP server (`httptest`), with real `bcrypt` / `apr1` hashes and no instrumentation of the vulnerable logic. Files: `pkg/middlewares/auth/zz_scanpoc_J15{,b,c}_test.go`, deleted after the run. **Commands**
cd /Users/emile/go/src/github.com/traefik/traefik
go test -count=1 -run TestZZScanPoCJ15      -v ./pkg/middlewares/auth/...
go test -count=1 -run TestZZScanPoCJ15Costs -v ./pkg/middlewares/auth/...
go test -count=1 -run TestZZScanPoCJ15H2    -v ./pkg/middlewares/auth/...
Probe shape, exactly the claimed scenario: calibrate `D` with one request, launch a leader with a junk username and password `P`, sleep `0.9 * D`, then send the probe with password `P` and either a configured (`alice`) or an absent (`bob`) username, and time the probe. `classify=OK` means `present > 2 * absent`, i.e. the oracle answered correctly. **Observed, main PoC (test 1)**
[bcrypt-cost12] SEQUENTIAL control: absent=249.568275ms present=249.10215ms ratio=1.00x
[bcrypt-cost12] CONCURRENT D=245.521625ms frac=0.90 round 0: absent=21.750833ms present=242.081792ms ratio=11.1x  classify=OK
[bcrypt-cost12] CONCURRENT D=245.521625ms frac=0.90 round 1: absent=20.197667ms present=245.234958ms ratio=12.1x  classify=OK
[bcrypt-cost12] CONCURRENT D=245.521625ms frac=0.90 round 2: absent=25.675958ms present=243.981375ms ratio=9.5x   classify=OK
[bcrypt-cost10] SEQUENTIAL control: absent=61.4374ms present=61.049608ms ratio=0.99x
[bcrypt-cost10] CONCURRENT D=60.54675ms frac=0.90 round 0: absent=5.572875ms present=60.8345ms   ratio=10.9x  classify=OK
[bcrypt-cost10] CONCURRENT D=60.54675ms frac=0.90 round 1: absent=4.042292ms present=61.988792ms ratio=15.3x  classify=OK
[bcrypt-cost10] CONCURRENT D=60.54675ms frac=0.90 round 2: absent=4.53825ms  present=61.557791ms ratio=13.6x  classify=OK
[apr1-short-pw] SEQUENTIAL control: absent=360.7µs present=373.116µs ratio=1.03x
[apr1-short-pw] CONCURRENT D=370.792µs frac=0.90 round 0: absent=378.167µs present=409.458µs ratio=1.1x  classify=FAIL
[apr1-short-pw] CONCURRENT D=370.792µs frac=0.90 round 1: absent=352.416µs present=333.875µs ratio=0.9x  classify=FAIL
[apr1-short-pw] CONCURRENT D=370.792µs frac=0.90 round 2: absent=374.209µs present=349.125µs ratio=0.9x  classify=FAIL
[apr1-8000B-pw] SEQUENTIAL control: absent=22.159325ms present=21.999433ms ratio=0.99x
[apr1-8000B-pw] CONCURRENT D=22.457583ms frac=0.90 round 0: absent=22.089458ms present=22.516708ms ratio=1.0x   classify=FAIL
[apr1-8000B-pw] CONCURRENT D=22.457583ms frac=0.90 round 1: absent=698.042µs  present=21.877ms    ratio=31.3x  classify=OK
[apr1-8000B-pw] CONCURRENT D=22.457583ms frac=0.90 round 2: absent=1.570875ms present=21.945417ms ratio=14.0x  classify=OK
The **sequential control is the decisive part**: 1.00x / 0.99x / 1.03x / 0.99x on every algorithm. The constant-time countermeasure is intact for one-request-at-a-time probing, so the 10x to 15x concurrent separation is attributable to the coalescing and to nothing else. That rules out the alternative explanation that this is just `cwfr` / `8j2h` still unfixed. **Observed, per-algorithm hash cost (test 2)**
bcrypt cost10 / short pw        -> 60.5919ms per hash
bcrypt cost12 / short pw        -> 242.384558ms per hash
apr1 / short pw                 -> 128.333µs per hash
apr1 / 8000-byte pw             -> 42.575816ms per hash
**Observed, single HTTP/2 connection (test 3)** Both probes multiplexed as two streams over one TLS connection, which pins them to a single Traefik process even behind an L4 load balancer fronting several replicas:
h2 single-connection: D=63.048ms
h2 round 0: absent=7.931459ms present=65.87375ms  ratio=8.3x  classify=OK
h2 round 1: absent=4.255667ms present=64.193291ms ratio=15.1x classify=OK
h2 round 2: absent=6.696417ms present=64.695208ms ratio=9.7x  classify=OK
**Conclusion: REPRODUCED**, 9/9 correct classifications on bcrypt, single-shot, no statistics. Claim-by-claim audit of the finding text: _(truncated ; full analysis in the linked internal report)_ ## Documentation grounding **Not working-as-intended. The governing project document puts this class explicitly in scope.** - `docs/content/security/` (header-underscores, request-path, content-length, http2-header-memory, multi-tenant-kubernetes) has no page covering BasicAuth, the timing posture or the singleflight dedup. Grep for `timing|basicauth|basic auth|enumerat|singleflight` across that directory: no match. No governing security doc, hence no WAI signal from there. - `docs/content/contributing/security-decisions.md`, section **Authentication Middleware Correctness**, is the settled public position and it is directly on point: > **Our position.** In scope: credential or identity handling that leaks across requests or users, **observable timing differences that disclose whether a principal exists**, and credentials forwarded to a destination the operator did not authorise. > > **Where the line is.** Choosing a weak authentication mechanism, or configuring it permissively, is the operator's decision. **The middleware failing to deliver what its documentation promises is ours.** _(truncated ; full analysis in the linked internal report)_ ## Precedent in comparable projects Corpus refreshed 2026-08-24 for nginx, ingress-nginx, kong, caddy, apisix, nginx-plus; envoy (2026-06-29), envoy-gateway (2026-06-15), haproxy (2026-07-16) and istio (2026-05-12) are staler. No exact analogue of a request-deduplication timing oracle. Adjacent prior art: - **Envoy, CVE-2026-47775, medium**: "OAuth2 Filter: Padding Oracle via AES-256-CBC Cookie Decryption". A side-channel oracle inside an auth filter, published as a medium CVE. Framed on the observability of the discrepancy, not on the difficulty of measuring it. - **Envoy Gateway, CVE-2026-53715 / GHSA-8fv2-88gg-hm7q, medium**: "Wasm cache ServeHTTP reads mappingPath2Cache without lock". A concurrency defect in a shared per-process cache in the request path, treated as a real medium CVE and fixed by correcting the shared-state handling. - **APISIX, CVE-2025-62232, high**: basic-auth credential exposure. Same component, unrelated mechanism (logging). Takeaway: the industry treats side-channel oracles in auth filters, and concurrency defects in shared per-process request-path caches, as genuine publishable CVEs of roughly this severity. Nothing in the corpus argues the class is by design. The strongest precedent, however, is not a competitor: it is Traefik's own two published CVEs on this exact guarantee. ## Recommended fix Assign for fix. No fix exists: `gh search prs --repo traefik/traefik "singleflight"` returns only PR #13572 (the merged `8mrf` key-collision fix) and `"basic auth timing"` only PR #12803 / #12796; `git log --all` on the checkout shows `b5ace8eb5` as the last change to `pkg/middlewares/auth/` and `master` (`174e5d811`, a merge of `v3.7`) carries nothing later. **Fix shape: remove the secret from the key and qualify it by username.** Something along the lines of
key := strconv.Itoa(len(user)) + ":" + user + ":" + password
with the dummy-hash branch left inside the closure. This is strictly better than the current key on all four counts: - **It closes J15**: the key no longer encodes existence, so two absent users no longer share a bucket that a present user is excluded from. Coalescing then happens only for an identical `(user, password)` pair, which leaks nothing an attacker did not already supply. - **It closes `8mrf` structurally** rather than by delimiting: the stored hash never enters the key, so no choice of password can alias a configured user's key. The `len` prefix is still needed, now on `user`, to keep `("ab", "c")` and `("a", "bc")` apart. - **It preserves the purpose of `6f469ee1e`**: the case that commit exists for is a burst of concurrent requests carrying the *same* credentials, which is exactly what a username-qualified key still dedupes. - **It keeps the constant-time property**: one hash of `notFoundSecret` for absent users, one hash of `secret` for present ones, unchanged. Do not fix this by making the dummy branch share the leader's timing envelope; as the finding correctly notes, that only helps if the key stops depending on `secret == ""`. Secondary, low cost: restore the "Timing attacks" admonition that PR #12803 added to the BasicAuth page. It is the statement of the guarantee, it is the thing `security-decisions.md` holds the project to, and it is currently absent from the `v3.7` docs tree. If filed: new cluster slug `basicauth-singleflight-existence-oracle`, sibling of `basicauth-singleflight-key-collision`, affected range `>= v3.6.11` through the current `v3.6` / `v3.7` heads, v2 unaffected, digest auth unaffected. Correct the 40x claim and the `$apr1$` "trivial" claim in the published description per the audit table above. ## Provenance Found by an external automated code scan (`CLAUDE-SECURITY-20260824-122205`) of `pkg/middlewares`, `pkg/proxy`, `pkg/server`, `pkg/muxer` and `pkg/tls` on branch `v3.7` at commit `d5072ce7b8765c9574246072e05dd81d84950da7`, then triaged with the `advisory-check` process : mechanism-level duplicate check against the existing advisory corpus, CVE-policy gate, security-documentation grounding, comparable-project precedent, and a mandatory reproduction attempt. Triage outcome : **Likely Valid**, confidence High, reproduced (yes). Expected publication likelihood at triage time : High. Scanner finding id : F16. Internal report : `findings/scan-20260824/verdicts/J15.md` in the security-advisor repository.
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.7.12"
      },
      "package": {
        "ecosystem": "Go",
        "name": "Traefik"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.6.11"
            },
            {
              "fixed": "3.7.13"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-88010"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-208"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-22T20:40:49Z",
    "nvd_published_at": "2026-09-22T16:18:06Z",
    "severity": "MODERATE"
  },
  "details": "## Summary\n\nTraefik\u0027s BasicAuth middleware coalesces concurrent credential checks through a `singleflight.Group` to avoid hashing the same password many times at once. Since v3.6.11 the deduplication key was built from the submitted password plus the stored secret, so it depended on server state: a non-existent username collapsed onto one shared key while each configured username produced its own. Under attacker-controlled concurrency, a probe request arriving inside a leader request\u0027s in-flight window is served the leader\u0027s fast coalesced result when the username does not exist, but computes its own hash (slow) when the username exists \u2014 reintroducing, only in the concurrent case, the unauthenticated username-enumeration timing oracle that GHSA-g3hg-j4jv-cwfr had hardened for sequential probing. The fix derives the singleflight key from the submitted credentials (username and password) only, so it no longer depends on whether the account exists or on any stored secret. Traefik v2 is not affected: the v2.11 BasicAuth middleware does not use singleflight coalescing, and Digest authentication is not affected. The impact is limited to username enumeration; no credential disclosure or authentication bypass is possible.\n\nThe vulnerability originates on the v3.6 line, which has reached end of life; users on v3.6 or earlier v3.x must upgrade to v3.7.13 to receive the fix.\n\n## Patches\n\n- https://github.com/traefik/traefik/releases/tag/v3.7.13\n\n## For more information\n\nIf you have any questions or comments about this advisory, please [open an issue](https://github.com/traefik/traefik/issues).\n\n\u003cdetails\u003e\n\u003csummary\u003eOriginal Description\u003c/summary\u003e\n\n## Summary\n\nConfirmed. `checkPassword` derives the `singleflight` key from the *stored secret*, so the key encodes whether the submitted username exists:\n\n- username absent, `secret == \"\"`, key `= len(P) + \":\" + P`\n- username present, key `= len(P) + \":\" + P + secret_T`\n\nEvery non-existent username therefore lands on one shared key, while every configured username gets its own. `singleflight.Group.Do` makes a follower on an equal key block on the leader\u0027s in-flight computation and return the leader\u0027s result. So an attacker who sends a leader request with a junk username and password `P`, then sends the probe for target `T` with the same `P` late inside the leader\u0027s window, reads user existence directly off the probe\u0027s latency: coalesced (fast) means `T` does not exist, own hash (slow) means `T` does exist.\n\nThis is the exact information leak that the `notFoundSecret` dummy hash at line 127 exists to remove. Sequential probing is fully equalised (measured ratio 1.00x, so the fix for `cwfr` / `8j2h` does work); the leak reappears only under attacker-controlled concurrency. Confirmed on the current `v3.7` head, which already carries the `8mrf` singleflight fix, and on `master` (no later fix exists).\n\n## Affected code\n\n- `pkg/middlewares/auth/basic_auth.go:125` (`checkPassword`)\n\n## Code analysis\n\n`pkg/middlewares/auth/basic_auth.go:119-131` matches the finding verbatim, including the cited line 125:\n\n```go\nfunc (b *basicAuth) checkPassword(user, password string) bool {   // :119\n\tsecret := b.auth.Secrets(user, b.auth.Realm)                   // \"\" when the user is absent\n\n\tkey := strconv.Itoa(len(password)) + \":\" + password + secret   // :124\n\tmatch, _, _ := b.singleflightGroup.Do(key, func() (any, error) {   // :125\n\t\tif secret == \"\" {\n\t\t\t_ = b.checkSecret(password, b.notFoundSecret)          // :127  dummy hash, equal cost\n\t\t\treturn false, nil\n\t\t}\n\t\treturn b.checkSecret(password, secret), nil\n\t})\n\treturn match.(bool)\n}\n```\n\nTwo independent properties combine:\n\n1. **The dummy hash equalises the cost of one lookup.** `notFoundSecret` is a configured user\u0027s real hash (`slices.Collect(maps.Values(users))[0]`), so absent and present users each perform exactly one hash of the same algorithm and cost. That is why the sequential control below is flat.\n2. **The key partitions on existence, so coalescing is not equalised.** The dummy hash was placed *inside* the closure (commit `122175ac2`, PR #12803), which is what pulls absent users into `Do` at all. Before that refactor, `secret == \"\"` returned `false` before `Do` was ever called.\n\nGit archaeology of the whole sequence in this one function:\n\n| Commit | Date | Effect |\n|---|---|---|\n| `6f469ee1e` | 2024-10-10 | Introduces `singleflight` to dedupe concurrent hashes (`Only calculate basic auth hashes once for concurrent requests`). Absent users returned `false` before `Do`. |\n| `122175ac2` (PR #12803) | 2026-03-17 | Fix for `cwfr`. Moves the empty-secret branch inside the closure, which makes the key existence-dependent for the first time. |\n| `8c4fc8957` | 2026-04-13 | Fix for `8j2h`: `notFoundSecret` was resolving to `\"\"`, so the dummy hash was a no-op. |\n| `b5ace8eb5` (PR #13572) | 2026-07-28 | Fix for `8mrf`: adds the `len(password) + \":\"` prefix so distinct (password, secret) pairs cannot alias. Keeps the secret in the key and keeps the empty-secret branch inside the closure. |\n\nJ15 is the residue of that last fix. It does **not** depend on the key collision `8mrf` closed: the oracle works precisely *because* the keys differ. The prior analysis of `8mrf` recommended keeping \"the empty-secret (unconfigured) path out of any key that a configured user can share\"; the shipped patch only delimited the key, so the existence dependency survived.\n\nAffected range: `\u003e= v3.6.11` (the `122175ac2` refactor) through current `v3.7` head and `master`. Not the v2 line, and not earlier v3 releases, which returned early for absent users. Digest auth does not use `singleflight` and is unaffected.\n\nImpact scope: username enumeration only. No credential disclosure, no authentication bypass, no result sharing across identities.\n\n## Reproduction\n\nGo tests written directly in `package auth`, driving the real `NewBasic` handler over a real HTTP server (`httptest`), with real `bcrypt` / `apr1` hashes and no instrumentation of the vulnerable logic. Files: `pkg/middlewares/auth/zz_scanpoc_J15{,b,c}_test.go`, deleted after the run.\n\n**Commands**\n\n```\ncd /Users/emile/go/src/github.com/traefik/traefik\ngo test -count=1 -run TestZZScanPoCJ15      -v ./pkg/middlewares/auth/...\ngo test -count=1 -run TestZZScanPoCJ15Costs -v ./pkg/middlewares/auth/...\ngo test -count=1 -run TestZZScanPoCJ15H2    -v ./pkg/middlewares/auth/...\n```\n\nProbe shape, exactly the claimed scenario: calibrate `D` with one request, launch a leader with a junk username and password `P`, sleep `0.9 * D`, then send the probe with password `P` and either a configured (`alice`) or an absent (`bob`) username, and time the probe. `classify=OK` means `present \u003e 2 * absent`, i.e. the oracle answered correctly.\n\n**Observed, main PoC (test 1)**\n\n```\n[bcrypt-cost12] SEQUENTIAL control: absent=249.568275ms present=249.10215ms ratio=1.00x\n[bcrypt-cost12] CONCURRENT D=245.521625ms frac=0.90 round 0: absent=21.750833ms present=242.081792ms ratio=11.1x  classify=OK\n[bcrypt-cost12] CONCURRENT D=245.521625ms frac=0.90 round 1: absent=20.197667ms present=245.234958ms ratio=12.1x  classify=OK\n[bcrypt-cost12] CONCURRENT D=245.521625ms frac=0.90 round 2: absent=25.675958ms present=243.981375ms ratio=9.5x   classify=OK\n[bcrypt-cost10] SEQUENTIAL control: absent=61.4374ms present=61.049608ms ratio=0.99x\n[bcrypt-cost10] CONCURRENT D=60.54675ms frac=0.90 round 0: absent=5.572875ms present=60.8345ms   ratio=10.9x  classify=OK\n[bcrypt-cost10] CONCURRENT D=60.54675ms frac=0.90 round 1: absent=4.042292ms present=61.988792ms ratio=15.3x  classify=OK\n[bcrypt-cost10] CONCURRENT D=60.54675ms frac=0.90 round 2: absent=4.53825ms  present=61.557791ms ratio=13.6x  classify=OK\n[apr1-short-pw] SEQUENTIAL control: absent=360.7\u00b5s present=373.116\u00b5s ratio=1.03x\n[apr1-short-pw] CONCURRENT D=370.792\u00b5s frac=0.90 round 0: absent=378.167\u00b5s present=409.458\u00b5s ratio=1.1x  classify=FAIL\n[apr1-short-pw] CONCURRENT D=370.792\u00b5s frac=0.90 round 1: absent=352.416\u00b5s present=333.875\u00b5s ratio=0.9x  classify=FAIL\n[apr1-short-pw] CONCURRENT D=370.792\u00b5s frac=0.90 round 2: absent=374.209\u00b5s present=349.125\u00b5s ratio=0.9x  classify=FAIL\n[apr1-8000B-pw] SEQUENTIAL control: absent=22.159325ms present=21.999433ms ratio=0.99x\n[apr1-8000B-pw] CONCURRENT D=22.457583ms frac=0.90 round 0: absent=22.089458ms present=22.516708ms ratio=1.0x   classify=FAIL\n[apr1-8000B-pw] CONCURRENT D=22.457583ms frac=0.90 round 1: absent=698.042\u00b5s  present=21.877ms    ratio=31.3x  classify=OK\n[apr1-8000B-pw] CONCURRENT D=22.457583ms frac=0.90 round 2: absent=1.570875ms present=21.945417ms ratio=14.0x  classify=OK\n```\n\nThe **sequential control is the decisive part**: 1.00x / 0.99x / 1.03x / 0.99x on every algorithm. The constant-time countermeasure is intact for one-request-at-a-time probing, so the 10x to 15x concurrent separation is attributable to the coalescing and to nothing else. That rules out the alternative explanation that this is just `cwfr` / `8j2h` still unfixed.\n\n**Observed, per-algorithm hash cost (test 2)**\n\n```\nbcrypt cost10 / short pw        -\u003e 60.5919ms per hash\nbcrypt cost12 / short pw        -\u003e 242.384558ms per hash\napr1 / short pw                 -\u003e 128.333\u00b5s per hash\napr1 / 8000-byte pw             -\u003e 42.575816ms per hash\n```\n\n**Observed, single HTTP/2 connection (test 3)**\n\nBoth probes multiplexed as two streams over one TLS connection, which pins them to a single Traefik process even behind an L4 load balancer fronting several replicas:\n\n```\nh2 single-connection: D=63.048ms\nh2 round 0: absent=7.931459ms present=65.87375ms  ratio=8.3x  classify=OK\nh2 round 1: absent=4.255667ms present=64.193291ms ratio=15.1x classify=OK\nh2 round 2: absent=6.696417ms present=64.695208ms ratio=9.7x  classify=OK\n```\n\n**Conclusion: REPRODUCED**, 9/9 correct classifications on bcrypt, single-shot, no statistics.\n\nClaim-by-claim audit of the finding text:\n\n_(truncated ; full analysis in the linked internal report)_\n\n## Documentation grounding\n\n**Not working-as-intended. The governing project document puts this class explicitly in scope.**\n\n- `docs/content/security/` (header-underscores, request-path, content-length, http2-header-memory, multi-tenant-kubernetes) has no page covering BasicAuth, the timing posture or the singleflight dedup. Grep for `timing|basicauth|basic auth|enumerat|singleflight` across that directory: no match. No governing security doc, hence no WAI signal from there.\n- `docs/content/contributing/security-decisions.md`, section **Authentication Middleware Correctness**, is the settled public position and it is directly on point:\n\n  \u003e **Our position.** In scope: credential or identity handling that leaks across requests or users, **observable timing differences that disclose whether a principal exists**, and credentials forwarded to a destination the operator did not authorise.\n  \u003e\n  \u003e **Where the line is.** Choosing a weak authentication mechanism, or configuring it permissively, is the operator\u0027s decision. **The middleware failing to deliver what its documentation promises is ours.**\n\n_(truncated ; full analysis in the linked internal report)_\n\n## Precedent in comparable projects\n\nCorpus refreshed 2026-08-24 for nginx, ingress-nginx, kong, caddy, apisix, nginx-plus; envoy (2026-06-29), envoy-gateway (2026-06-15), haproxy (2026-07-16) and istio (2026-05-12) are staler.\n\nNo exact analogue of a request-deduplication timing oracle. Adjacent prior art:\n\n- **Envoy, CVE-2026-47775, medium**: \"OAuth2 Filter: Padding Oracle via AES-256-CBC Cookie Decryption\". A side-channel oracle inside an auth filter, published as a medium CVE. Framed on the observability of the discrepancy, not on the difficulty of measuring it.\n- **Envoy Gateway, CVE-2026-53715 / GHSA-8fv2-88gg-hm7q, medium**: \"Wasm cache ServeHTTP reads mappingPath2Cache without lock\". A concurrency defect in a shared per-process cache in the request path, treated as a real medium CVE and fixed by correcting the shared-state handling.\n- **APISIX, CVE-2025-62232, high**: basic-auth credential exposure. Same component, unrelated mechanism (logging).\n\nTakeaway: the industry treats side-channel oracles in auth filters, and concurrency defects in shared per-process request-path caches, as genuine publishable CVEs of roughly this severity. Nothing in the corpus argues the class is by design. The strongest precedent, however, is not a competitor: it is Traefik\u0027s own two published CVEs on this exact guarantee.\n\n## Recommended fix\n\nAssign for fix. No fix exists: `gh search prs --repo traefik/traefik \"singleflight\"` returns only PR #13572 (the merged `8mrf` key-collision fix) and `\"basic auth timing\"` only PR #12803 / #12796; `git log --all` on the checkout shows `b5ace8eb5` as the last change to `pkg/middlewares/auth/` and `master` (`174e5d811`, a merge of `v3.7`) carries nothing later.\n\n**Fix shape: remove the secret from the key and qualify it by username.** Something along the lines of\n\n```go\nkey := strconv.Itoa(len(user)) + \":\" + user + \":\" + password\n```\n\nwith the dummy-hash branch left inside the closure. This is strictly better than the current key on all four counts:\n\n- **It closes J15**: the key no longer encodes existence, so two absent users no longer share a bucket that a present user is excluded from. Coalescing then happens only for an identical `(user, password)` pair, which leaks nothing an attacker did not already supply.\n- **It closes `8mrf` structurally** rather than by delimiting: the stored hash never enters the key, so no choice of password can alias a configured user\u0027s key. The `len` prefix is still needed, now on `user`, to keep `(\"ab\", \"c\")` and `(\"a\", \"bc\")` apart.\n- **It preserves the purpose of `6f469ee1e`**: the case that commit exists for is a burst of concurrent requests carrying the *same* credentials, which is exactly what a username-qualified key still dedupes.\n- **It keeps the constant-time property**: one hash of `notFoundSecret` for absent users, one hash of `secret` for present ones, unchanged.\n\nDo not fix this by making the dummy branch share the leader\u0027s timing envelope; as the finding correctly notes, that only helps if the key stops depending on `secret == \"\"`.\n\nSecondary, low cost: restore the \"Timing attacks\" admonition that PR #12803 added to the BasicAuth page. It is the statement of the guarantee, it is the thing `security-decisions.md` holds the project to, and it is currently absent from the `v3.7` docs tree.\n\nIf filed: new cluster slug `basicauth-singleflight-existence-oracle`, sibling of `basicauth-singleflight-key-collision`, affected range `\u003e= v3.6.11` through the current `v3.6` / `v3.7` heads, v2 unaffected, digest auth unaffected. Correct the 40x claim and the `$apr1$` \"trivial\" claim in the published description per the audit table above.\n\n## Provenance\n\nFound by an external automated code scan (`CLAUDE-SECURITY-20260824-122205`) of `pkg/middlewares`, `pkg/proxy`, `pkg/server`, `pkg/muxer` and `pkg/tls` on branch `v3.7` at commit `d5072ce7b8765c9574246072e05dd81d84950da7`, then triaged with the `advisory-check` process : mechanism-level duplicate check against the existing advisory corpus, CVE-policy gate, security-documentation grounding, comparable-project precedent, and a mandatory reproduction attempt.\n\nTriage outcome : **Likely Valid**, confidence High, reproduced (yes). Expected publication likelihood at triage time : High.\n\nScanner finding id : F16. Internal report : `findings/scan-20260824/verdicts/J15.md` in the security-advisor repository.\n\n\u003c/details\u003e\n\n---",
  "id": "GHSA-8fcf-v89g-xpg6",
  "modified": "2026-09-22T20:40:49Z",
  "published": "2026-09-22T20:40:49Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/security/advisories/GHSA-8fcf-v89g-xpg6"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-88010"
    },
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/pull/13816"
    },
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/commit/ddc1bf4660b85fd61fafdd821eb8216fb1a0b130"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/traefik/traefik"
    },
    {
      "type": "WEB",
      "url": "https://github.com/traefik/traefik/releases/tag/v3.7.13"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "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",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Traefik: BasicAuth singleflight coalescing reintroduces an unauthenticated username-enumeration timing oracle"
}

No mitigation information available for this CWE.

CAPEC-462: Cross-Domain Search Timing

An attacker initiates cross domain HTTP / GET requests and times the server responses. The timing of these responses may leak important information on what is happening on the server. Browser's same origin policy prevents the attacker from directly reading the server responses (in the absence of any other weaknesses), but does not prevent the attacker from timing the responses to requests that the attacker issued cross domain.

CAPEC-541: Application Fingerprinting

An adversary engages in fingerprinting activities to determine the type or version of an application installed on a remote target.

CAPEC-580: System Footprinting

An adversary engages in active probing and exploration activities to determine security information about a remote target system. Often times adversaries will rely on remote applications that can be probed for system configurations.