CVE
CVE-2026-119145, CVE-2026-119144, CVE-2026-118769, CVE-2026-118765, CVE-2026-118766, CVE-2026-118767, CVE-2026-118768, CVE-2026-119286, CVE-2026-119283, CVE-2026-119284, CVE-2026-119197, CVE-2026-119196, CVE-2026-119195, CVE-2026-119194, CVE-2026-119203, CVE-2026-119204, CVE-2026-119205, CVE-2026-119206, CVE-2026-119207, CVE-2026-119208, CVE-2026-119209
CWE
CWE-22, CWE-1336, CWE-197, CWE-400, CWE-407, CWE-338
Affected Surface
- Python / Bench `frappe` (`frappe/frappe`) versions `< 15.121.0` and `>= 16.0.0, < 16.34.0` (`CVE-2026-119145` / `GHSA-9pp9-wgp9-3p3j`, CVSS 9.9 Critical; and `CVE-2026-119144` / `GHSA-6pmg-vc6m-6wrr`, CVSS 8.8 High, fixed in `15.111.0` and `16.21.0`)
- C++ `botan` (`randombit/botan`) versions `>= 2.1.0, < 3.13.0` (`CVE-2026-118769` / `GHSA-c68p-822g-jfvr`, CVSS v4.0 9.2 Critical) and `< 3.13.0` (`CVE-2026-118765` through `CVE-2026-118768`)
- PyPI `graphql-core` versions `>= 3.3.0a3, < 3.3.1` (`CVE-2026-119286` / `GHSA-mpqx-q82w-9x46`, CVSS 7.5 High)
- PyPI `joserfc` versions `< 1.7.5` (`CVE-2026-119283` / `GHSA-jpxq-7h8p-2q76`, CVSS 7.5 High) and `< 1.7.6` (`CVE-2026-119284` / `GHSA-9pg5-8c7x-5hfx`, CVSS 6.9 Medium)
- PyPI `pyasn1` versions `< 0.6.5` (`CVE-2026-119194`, `CVE-2026-119195`, `CVE-2026-119196`, and `CVE-2026-119197`, all CVSS 7.5 High)
- PyPI `pypdf` versions `< 6.21.4` (`CVE-2026-119203`, `CVE-2026-119204`, `CVE-2026-119205` fixed in `6.21.4`; `CVE-2026-119206` through `CVE-2026-119209` fixed in `6.21.3`, all CVSS 7.1 High)
TL;DR
Between 16:18 UTC and 22:17 UTC on 29 October 2026, NVD and the GitHub Advisory Database published 21 vulnerabilities across six Python and C++ packages:
- Frappe Framework
< 15.121.0and16.x < 16.34.0(CVE-2026-119145/GHSA-9pp9-wgp9-3p3j, CVSS 9.9 Critical; andCVE-2026-119144/GHSA-6pmg-vc6m-6wrr, CVSS 8.8 High): Frappe (the Python full-stack web framework backing ERPNext) patched an authenticated file-upload path traversal flaw (CVE-2026-119145) that wrote uploaded files outside the storage directory to achieve remote code execution, alongside a server-side template injection (SSTI) flaw (CVE-2026-119144, fixed in15.111.0and16.21.0) where user-controlled message fields were rendered through Frappe’s Jinja template context without neutralization. - Botan C++ cryptography library
< 3.13.0(CVE-2026-118769/GHSA-c68p-822g-jfvr, CVSS v4.0 9.2 Critical, plusCVE-2026-118765throughCVE-2026-118768): In Botan’s C FFI (src/lib/ffi/ffi_block.cpp),botan_block_cipher_block_size()castb.block_size()(size_t) directly to a signed 32-bitintwithout bounds checking (static_cast<int>(b.block_size())). If an application accepted an external cipher specification string in raw FFI ECB mode, an attacker could specify the variable-block-sizeLioncipher with a huge block size that truncated to a small or negativeint, causing the caller to under-allocate its output buffer and corrupt heap memory duringbotan_block_cipher_encrypt_blocks().Botan 3.13.0also fixesAutoSeeded_RNG::randomize()marking an unseeded RNG as seeded on a zero-length read (CVE-2026-118765, CVSS 7.3 High), OCSP redirect SSRF (CVE-2026-118766and118768), and Python FFI NUL-byte string truncation (CVE-2026-118767). graphql-core3.3.0a3to< 3.3.1(CVE-2026-119286/GHSA-mpqx-q82w-9x46, CVSS 7.5 High): Whenvalidate()aborted after reachingmax_errors(default100), it raised a module-level singletonvalidation_aborted_error = ValidationAbortedError(...). In Python, raising an existing exception instance appends the new call frame (and all local variables referenced by that frame, including the parsed ASTDocumentNode,ValidationContext, anderrorslist) to the exception’s__traceback__chain, retaining every aborted GraphQL request in memory for the lifetime of the worker process.joserfc< 1.7.6(CVE-2026-119283, CVSS 7.5 High;CVE-2026-119284, CVSS 6.9 Medium): Injoserfc < 1.7.5,jwe.decrypt_json()accepted a JWE General JSON Serializationrecipientsarray without a count limit and invoked private-keydecrypt_cek()for every recipient entry before consultingverify_all_recipients, allowing a single request to trigger thousands of RSA private-key decryptions (max_recipients = 16added in1.7.5). In< 1.7.6, compact JWS/JWE deserialization calledvalue.split(b".")before checkingvalidate_compact_value_size(value).pyasn1< 0.6.5(CVE-2026-119194toCVE-2026-119197, all CVSS 7.5 High) andpypdf< 6.21.4(CVE-2026-119203toCVE-2026-119209, all CVSS 7.1 High):pyasn1 0.6.5eliminates four quadratic BER/CER/DER decoding loops across binaryREALmantissas (119197), constructedBIT STRINGfragments (119196), constructedOCTET STRING/ANYchunks (119195), and collidingTagSethashes in schemaless containers (119194).pypdf 6.21.3and6.21.4fix seven infinite loops and memory exhaustion paths in malformed PDF streams, page trees, andclone_document_from_reader.
What to do now: Upgrade frappe to >= 15.121.0 or >= 16.34.0, botan to >= 3.13.0, graphql-core to >= 3.3.1, joserfc to >= 1.7.6 (1.7.7 current), pyasn1 to >= 0.6.5, and pypdf to >= 6.21.4.
Affected packages and projects
| Ecosystem | Package / Project | CVE / GHSA | Severity | Affected versions | Fixed version | Vulnerable component |
|---|---|---|---|---|---|---|
| Python / Bench | frappe (frappe/frappe) | CVE-2026-119145 (GHSA-9pp9-wgp9-3p3j), CVE-2026-119144 (GHSA-6pmg-vc6m-6wrr) | CVSS 9.9 Critical / 8.8 High | < 15.121.0, >= 16.0.0, < 16.34.0 (119144 fixed in 15.111.0 / 16.21.0) | 15.121.0, 16.34.0 | File-upload destination validation (119145); message-field Jinja rendering (119144) |
| C++ | botan (randombit/botan) | CVE-2026-118769 (GHSA-c68p-822g-jfvr), CVE-2026-118765..118768 | CVSS v4.0 9.2 Critical / 7.3 High | >= 2.1.0, < 3.13.0 (118765: >= 3.7.0, < 3.13.0) | 3.13.0 | src/lib/ffi/ffi_block.cpp (botan_block_cipher_block_size), auto_rng.cpp, ocsp.cpp, botan3.py |
| PyPI | graphql-core | CVE-2026-119286 (GHSA-mpqx-q82w-9x46) | CVSS 7.5 High | >= 3.3.0a3, < 3.3.1 | 3.3.1 | src/graphql/validation/validate.py (validation_aborted_error singleton) |
| PyPI | joserfc | CVE-2026-119283 (GHSA-jpxq-7h8p-2q76), CVE-2026-119284 (GHSA-9pg5-8c7x-5hfx) | CVSS 7.5 High / 6.9 Medium | < 1.7.5 (119283), < 1.7.6 (119284) | 1.7.6 (1.7.7 current) | src/joserfc/_rfc7516/json.py, registry.py, compact.py |
| PyPI | pyasn1 | CVE-2026-119194, CVE-2026-119195, CVE-2026-119196, CVE-2026-119197 | CVSS 7.5 High (all 4) | < 0.6.5 (119194: >= 0.3.3, < 0.6.5) | 0.6.5 | pyasn1/codec/ber/decoder.py (RealPayloadDecoder, BitStringPayloadDecoder, OctetStringPayloadDecoder, _decodeComponentsSchemaless) |
| PyPI | pypdf | CVE-2026-119203 through CVE-2026-119209 (7 advisories) | CVSS 7.1 High (all 7) | < 6.21.4 (119206..119209: < 6.21.3) | 6.21.4 | PDF stream decoding, page label tree traversal, strict mode object loading, and clone_document_from_reader |
Technical analysis
1. graphql-core 3.3.1 (CVE-2026-119286): how a module-level exception singleton leaked every aborted GraphQL AST in Python
In GraphQL.js (JavaScript), creating a single module-level validationAbortedError object and throwing it whenever a query exceeds maxErrors (100) is harmless because JavaScript Error objects capture their stack trace once at construction time (new Error(...)).
When graphql-core (3.3.0a3) ported that pattern verbatim to Python in src/graphql/validation/validate.py, it defined a module-level instance validation_aborted_error = ValidationAbortedError(...) and ran raise validation_aborted_error inside on_error():
--- a/src/graphql/validation/validate.py
+++ b/src/graphql/validation/validate.py
@@ -30,11 +30,6 @@ class ValidationAbortedError(GraphQLError):
"""Error when a validation has been aborted (error limit reached)."""
-
-
-validation_aborted_error = ValidationAbortedError(
- "Too many validation errors, error limit reached. Validation aborted."
-)
-
@@ -113,7 +108,10 @@ def validate(
def on_error(error: GraphQLError) -> None:
if len(errors) >= max_errors:
- raise validation_aborted_error
+ # Unlike GraphQL.js, create a new error each time, because raising a
+ # shared error would add the frames of every validation to its traceback.
+ msg = "Too many validation errors, error limit reached. Validation aborted."
+ raise ValidationAbortedError(msg)
In CPython, raise existing_exc attaches a brand-new traceback frame (tb_next) onto existing_exc.__traceback__ without discarding the traceback frames from earlier raise statements. Every frame in that growing linked list holds strong references to its f_locals, including the ValidationContext, the full parsed DocumentNode AST, and the errors list for that request. Sending repeated unauthenticated GraphQL queries with 101 unknown fields pinned every aborted request’s AST and context in memory forever until the Python worker process was killed by the OOM killer. Commit 3c319fd9f4 (v3.3.1) instantiates a fresh ValidationAbortedError(msg) on each abort.
2. joserfc 1.7.5 / 1.7.6 (CVE-2026-119283 and CVE-2026-119284) and pyasn1 0.6.5 (CVE-2026-119194 to CVE-2026-119197)
In joserfc (< 1.7.5, CVE-2026-119283 / GHSA-jpxq-7h8p-2q76), extract_general_json() and _perform_decrypt() in src/joserfc/_rfc7516/ accepted a JWE General JSON Serialization object ({"protected": "...", "recipients": [...]}) with an arbitrary number of entries in recipients and ran decrypt_recipient(alg, enc, recipient, tag) on every single entry before checking verify_all_recipients. An attacker could submit one JWE containing thousands of recipient blocks targeting an RSA-OAEP or RSA1_5 endpoint and force the server to execute thousands of expensive RSA private-key operations in a single HTTP request. Commit d6dc8df6c7 (1.7.5) enforces JWERegistry.max_recipients = 16 via registry.validate_recipient_count(recipients), and commit 397e04f4bb (1.7.6, CVE-2026-119284) validates the total byte length of compact JWS and JWE strings before calling value.split(b".").
In pyasn1 (< 0.6.5, PR #132), four separate ASN.1 BER/CER/DER decoders accumulated multi-kilobyte inputs quadratically:
- Binary
REALmantissa slicing (CVE-2026-119197, commitce3ec33907):RealPayloadDecoder.valueDecoderbuilt the integer mantissapone byte at a time insidewhile chunk: p <<= 8; p |= chunk[0]; chunk = chunk[1:], copying the remainingbytesslice and shifting a growing Python bignum on every byte.0.6.5replaces the loop with a single C-level call:p = int.from_bytes(bytes(chunk), 'big'). - Constructed
BIT STRINGandOCTET STRING/ANYconcatenation (CVE-2026-119196andCVE-2026-119195):BitStringPayloadDecoder(73ba7b043c) andOctetStringPayloadDecoder/AnyPayloadDecoder(4ce00797c5) repeatedly prepended or concatenated growing bit/byte objects across thousands of 1-byte constructed fragments instead of collecting chunks into a list and joining once. - Schemaless
TagSethash collisions (CVE-2026-119194, commita36e3a3d06):_decodeComponentsSchemalessinserted every component’sTagSetinto aseteven though it only needed to know whether more than one distinctTagSetappeared, allowing colliding long tag IDs to trigger $O(n^2)$ set insertions.
3. Botan 3.13.0 (CVE-2026-118769 and CVE-2026-118765) and Frappe 15.121.0 / 16.34.0 (CVE-2026-119145 and CVE-2026-119144)
In Botan 2.1.0 through 3.12.x, the C FFI function botan_block_cipher_block_size(botan_block_cipher_t bc) in src/lib/ffi/ffi_block.cpp returned a signed int so negative values could represent FFI error codes, but cast the cipher’s size_t block size directly without checking std::in_range<int>(bs):
--- a/src/lib/ffi/ffi_block.cpp
+++ b/src/lib/ffi/ffi_block.cpp
@@ -58,7 +59,18 @@ int botan_block_cipher_set_key(botan_block_cipher_t bc, const uint8_t key[], siz
int botan_block_cipher_block_size(botan_block_cipher_t bc) {
- return BOTAN_FFI_VISIT(bc, [](const auto& b) { return static_cast<int>(b.block_size()); });
+ return BOTAN_FFI_VISIT(bc, [](const auto& b) -> int {
+ const size_t bs = b.block_size();
+ if(bs == 0) {
+ return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
+ }
+
+ if(std::in_range<int>(bs)) {
+ return static_cast<int>(bs);
+ } else {
+ return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
+ }
+ });
}
Because Botan supports the parameterized Lion(hash, stream_cipher, block_size) block cipher constructor when initializing a cipher by name string, an attacker who controlled the cipher spec string passed to botan_block_cipher_init(&bc, cipher_name) could request a size_t block size that wrapped int on truncation (CVE-2026-118769, CVSS v4.0 9.2 Critical). Separately, in AutoSeeded_RNG (CVE-2026-118765, commit a7389222ac), calling clear() followed by randomize(out, 0) set the internal seeded flag to true before checking whether any entropy had been polled.
In Frappe Framework, CVE-2026-119145 (GHSA-9pp9-wgp9-3p3j, CVSS 9.9 Critical) allowed authenticated users to traverse out of the site’s public/files or private/files upload directory when saving uploaded files to disk, writing executable files into the application tree. CVE-2026-119144 (GHSA-6pmg-vc6m-6wrr, CVSS 8.8 High) allowed authenticated users with standard operational roles to inject server-side template expressions into message fields that Frappe evaluated in an unsandboxed server context.
Detection and remediation
# 1. Check Python environments and lockfiles for graphql-core, joserfc, pyasn1, pypdf, and frappe
pip show graphql-core joserfc pyasn1 pypdf frappe 2>/dev/null || true
rg -n '"?(graphql-core|joserfc|pyasn1|pypdf|frappe)"?\s*([~=!<>]=|:)' \
requirements*.txt pyproject.toml uv.lock poetry.lock Pipfile.lock apps.txt 2>/dev/null
# 2. Check installed Botan shared library and CLI version on Linux / macOS build hosts
botan version 2>/dev/null || pkg-config --modversion botan-3 2>/dev/null || true
- Upgrade Frappe Framework deployments (
bench update --patch) to>= 15.121.0on the v15 LTS branch or>= 16.34.0on v16. - Upgrade Botan to
>= 3.13.0, especially in any C, Python, Rust, or Go FFI consumer that passes caller-supplied cipher strings tobotan_block_cipher_initor callsbotan_ocsp_verify. - Upgrade Python libraries:
graphql-core(and downstream Strawberry, Ariadne, or Graphene servers) to>= 3.3.1.joserfcto>= 1.7.6(1.7.7current).pyasn1to>= 0.6.5.pypdfto>= 6.21.4.
Timeline
- 2026-08-06 to 2026-09-24: Botan merges commit
c6089ab7fa(CVE-2026-118769),joserfcreleases1.7.5(d6dc8df6c7) and1.7.6(397e04f4bb), andpyasn1merges PR#132(v0.6.5). - 2026-10-15: Frappe publishes
GHSA-9pp9-wgp9-3p3j(15.121.0/16.34.0) andGHSA-6pmg-vc6m-6wrr(15.111.0/16.21.0). - 2026-10-25 to 2026-10-28:
graphql-corereleasesv3.3.1(3c319fd9f4) andpypdfreleasesv6.21.3andv6.21.4(06593f9937). - 2026-10-29 (
16:18to22:17 UTC): NVD and the GitHub Advisory Database publishCVE-2026-119144,CVE-2026-119145,CVE-2026-118765throughCVE-2026-118769,CVE-2026-119194throughCVE-2026-119197,CVE-2026-119203throughCVE-2026-119209,CVE-2026-119283,CVE-2026-119284, andCVE-2026-119286.
From research to remediation
Check whether this pattern exists in your codebase
Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.
References
- graphql-core advisory GHSA-mpqx-q82w-9x46 (CVE-2026-119286) and commit 3c319fd9f4
- joserfc advisories GHSA-jpxq-7h8p-2q76 (CVE-2026-119283) and GHSA-9pg5-8c7x-5hfx (CVE-2026-119284)
- pyasn1 PR #132 (v0.6.5) and commits ce3ec33907, 73ba7b043c, 4ce00797c5, and a36e3a3d06 (CVE-2026-119194 to CVE-2026-119197)
- Botan advisory GHSA-c68p-822g-jfvr (CVE-2026-118769) and commit c6089ab7fa (v3.13.0)
- Frappe advisories GHSA-9pp9-wgp9-3p3j (CVE-2026-119145) and GHSA-6pmg-vc6m-6wrr (CVE-2026-119144)
- pypdf v6.21.3 / v6.21.4 commits 06593f9937, ea4ac66313, and f176db1a1f (CVE-2026-119203 to CVE-2026-119209)