CVE
CVE-2026-61438, CVE-2026-119120, CVE-2026-119119, CVE-2026-119118, CVE-2026-119121, CVE-2026-119122, CVE-2026-62264, CVE-2026-119052
CWE
CWE-94, CWE-502, CWE-306, CWE-295, CWE-918, CWE-770, CWE-755
Affected Surface
- PyPI `praisonai` (`< 4.6.78`) and `praisonaiagents` (`< 1.6.78`) (`CVE-2026-61438` / `GHSA-26mh-57q7-jfvr`, CVSS 7.3 High)
- PyPI and Docker `crawl4ai` (`unclecode/crawl4ai`) versions `< 0.9.5` (`CVE-2026-119118`, `CVE-2026-119119`, `CVE-2026-119120`, `CVE-2026-119121`, `CVE-2026-119122`, and `GHSA-j843-8p47-rhxp`)
- npm `@sylphx/pdf-reader-mcp` versions `>= 2.2.0, < 3.0.1` when run with `MCP_TRANSPORT=http` (`CVE-2026-62264` / `GHSA-q344-5v34-gm84`, CVSS 7.5 High)
- C++ `ggml-org/llama.cpp` (`ggml-rpc` server) releases `b2877` before `b11935` (`CVE-2026-119052`, CVSS 7.5 High / v4.0 8.7 High)
TL;DR
On 29 October 2026, NVD and the GitHub Advisory Database published nine security advisories across four AI agent, web-crawling, MCP server, and LLM inference tools:
- PraisonAI
< 4.6.78(CVE-2026-61438/GHSA-26mh-57q7-jfvr, CVSS 7.3 High):JobWorkflowExecutor._exec_inline_python()attempted to sandbox inlinescript:steps in YAML workflows by walking the parsed Python AST and stripping__import__,eval,exec, andopenfrom__builtins__. However, the AST node allowlist permittedast.Importandast.ImportFrom(which compile to bytecodeIMPORT_NAMEinstructions), and the module allowlist explicitly included'os'. Any workflowscript:step containingimport os; os.system('...')passed every AST check and executed arbitrary OS commands. Fixed inpraisonai 4.6.78andpraisonaiagents 1.6.78(commit393de39408), which also closes path traversal inread_file/run_skill_script, unauthenticated0.0.0.0binding inAgentOSand the Jobs/MCP servers, andfind -execsandbox bypasses. - Crawl4AI
< 0.9.5(6 coordinated-disclosure advisories in the Docker API server and library):CVE-2026-119120(GHSA-f856-7xp9-w3cc, CVSS 7.5 High): The untrusted Docker API request filter (UNTRUSTED_FORBIDDEN_FIELDS) did not blockCosineStrategy.model_name, allowing an API caller to pointfrom_pretrained()at an attacker-controlled Hugging Face repository (triggering pickle RCE on PyTorch< 2.6or disk/memory exhaustion).CVE-2026-119119(GHSA-rhjm-7hj7-75fx, CVSS 7.5 High / v4.0 8.7 High) andGHSA-j843-8p47-rhxp:_clamp_untrusted()did not capdelay_before_return_html,mean_delay, ormax_range(allowing a caller to hold Chromium pages open indefinitely), and allowed caller-supplied regexes inRegexExtractionStrategy.customandRegexChunking.patternsthat froze the Python GIL.CVE-2026-119118(GHSA-j2qh-f73r-mg3q, CVSS v4.0 8.3 High),CVE-2026-119121(GHSA-qj46-wp7m-rgj8), andCVE-2026-119122(GHSA-w4xc-px5p-c32w): Chromium was always launched with--ignore-certificate-errorsand--no-sandbox;css_selectorandwait_forallowed page JavaScript execution even whenjs_codewas blocked; andCacheValidator.validate()(check_cache_freshness) bypassed the Docker egress proxy.
@sylphx/pdf-reader-mcp2.2.0to< 3.0.1(CVE-2026-62264/GHSA-q344-5v34-gm84, CVSS 7.5 High): When started withMCP_TRANSPORT=http, the server bound0.0.0.0:8080by default, readMCP_API_KEY, and loggedAPI key authentication enabled (X-API-Key header), but never checked theX-API-Keyheader on incoming/mcprequests. Any network client could call every PDF tool and read local PDF files on the host without authentication. Fixed in3.0.1(8.5.5current).llama.cppb2877to< b11935(CVE-2026-119052, CVSS 7.5 High / v4.0 8.7 High): Inggml/src/ggml-rpc/ggml-rpc.cpp,recv_msg()read a 64-bitsizefrom the socket after theHELLOhandshake and calledinput.resize(size)inside atryblock that caughtstd::bad_allocbut notstd::length_error. Sending asizelarger thanstd::vector::max_size()threw an uncaughtstd::length_errorand aborted therpc-serverprocess.
What to do now: Upgrade praisonai to >= 4.6.78 (4.7.21 current), crawl4ai (and the unclecode/crawl4ai Docker image) to >= 0.9.5, @sylphx/pdf-reader-mcp to >= 3.0.1 (8.5.5 current), and llama.cpp to >= b11935.
Affected packages and projects
| Ecosystem | Package / Project | CVE / GHSA | Severity | Affected versions | Fixed version | Vulnerable component |
|---|---|---|---|---|---|---|
| PyPI | praisonai, praisonaiagents | CVE-2026-61438 (GHSA-26mh-57q7-jfvr) | CVSS 7.3 High | praisonai < 4.6.78, praisonaiagents < 1.6.78 | 4.6.78 / 1.6.78 (4.7.21 / 1.7.19 current) | JobWorkflowExecutor._exec_inline_python(), sandbox_executor.py, path_safety.py, http_stream.py |
| PyPI / Docker | crawl4ai (unclecode/crawl4ai) | CVE-2026-119120 (GHSA-f856-7xp9-w3cc), CVE-2026-119119 (GHSA-rhjm-7hj7-75fx), CVE-2026-119118 (GHSA-j2qh-f73r-mg3q), CVE-2026-119121 (GHSA-qj46-wp7m-rgj8), CVE-2026-119122 (GHSA-w4xc-px5p-c32w), GHSA-j843-8p47-rhxp | CVSS 7.5 High (v4.0 up to 8.7 High) | < 0.9.5 (119120 and 119121 affect >= 0.9.0, < 0.9.5) | 0.9.5 | crawl4ai/async_configs.py, crawl4ai/cache_validator.py, deploy/docker/utils.py |
| npm | @sylphx/pdf-reader-mcp | CVE-2026-62264 (GHSA-q344-5v34-gm84) | CVSS 7.5 High | >= 2.2.0, < 3.0.1 (MCP_TRANSPORT=http) | 3.0.1 (8.5.5 current) | src/index.ts, src/mcp.ts (isApiKeyValid) |
| C++ / GitHub | ggml-org/llama.cpp | CVE-2026-119052 | CVSS 7.5 High (v4.0 8.7 High) | b2877 to < b11935 | b11935 | ggml/src/ggml-rpc/ggml-rpc.cpp (recv_msg) |
Technical analysis
1. PraisonAI (CVE-2026-61438 / GHSA-26mh-57q7-jfvr): import os inside the AST workflow sandbox
When PraisonAI executes a job workflow (praisonai workflow run <file>.yaml with PRAISONAI_ALLOW_JOB_WORKFLOWS=true), JobWorkflowExecutor._exec_inline_python() parses inline script: steps with ast.parse(code, mode="exec") and walks the tree to block unsafe nodes before calling exec() with a restricted __builtins__ dictionary (which omits __import__, eval, exec, and open).
The sandbox failed for two reasons occurring together:
# Vulnerable AST validation in JobWorkflowExecutor._exec_inline_python (< 4.6.78)
allowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'}
if isinstance(node, ast.Import):
for alias in node.names:
if alias.name.split('.')[0] not in allowed_modules:
return {"ok": False, "error": f"Import of '{alias.name}' not allowed..."}
First, allowed_modules included 'os' so workflow scripts could access os.path or os.getcwd(), without restricting attribute access on the imported os module (os.system, os.popen, os.execvp). Second, in Python, when ast.Import nodes are allowed and compiled with compile(tree, ..., "exec"), the CPython VM executes the IMPORT_NAME bytecode instruction, which resolves __import__ from the interpreter’s builtins fallback or sys.modules['os'] if os is already loaded. Consequently, a two-line workflow step:
steps:
- script: |
import os
result = os.system("id")
passed every AST check and ran arbitrary OS commands.
In v4.6.78 (commit 393de39408 and commit f47a4f97ec), PraisonAI also shipped a broader security hardening pass across praisonai, praisonaiagents, and praisonai-ts:
CommandValidator.validate()insandbox_executor.pynow blocksfind ... -exec(if cmd_name == "find" and "-exec" in command:).resolve_within_root()inpraisonaiagents/tools/path_safety.pyconfinesread_file(),run_skill_script(),_save_output_to_file(), and.praisonincludepaths to the workspace root usingos.path.realpath()andos.path.commonpath().PraisonAIMCPhttp_stream.py,jobs/server.py, and TypeScriptAgentOSConfignow default to127.0.0.1instead of0.0.0.0and refuse to bind non-loopback addresses unless an API key (api_key,PRAISONAI_JOBS_API_KEY, orPRAISONAI_AGENTOS_API_KEY) is configured.
2. Crawl4AI 0.9.5 (CVE-2026-119118 to CVE-2026-119122 and GHSA-j843-8p47-rhxp): untrusted Docker API request deserialization
Crawl4AI’s Docker server (unclecode/crawl4ai, port 11235) accepts serialized CrawlerRunConfig objects on /crawl and /crawl/stream and deserializes them with CrawlerRunConfig.load(raw, provenance=Provenance.UNTRUSTED) in crawl4ai/async_configs.py. Version 0.9.5 (PR #2368, commit 6192d5e5b5) closes six gaps in that untrusted boundary:
--- a/crawl4ai/async_configs.py
+++ b/crawl4ai/async_configs.py
@@ -222,6 +231,21 @@ UNTRUSTED_FORBIDDEN_FIELDS = {
"PDFContentScrapingStrategy": {
"image_save_dir", "save_images_locally",
},
+ # model_name is a HuggingFace repo id handed to from_pretrained: the caller
+ # would pick the weights the server downloads and unpickles.
+ "CosineStrategy": {"model_name"},
+ # Caller-supplied regexes. Python's re holds the GIL while it matches, so
+ # one catastrophic-backtracking pattern freezes the whole server.
+ "RegexExtractionStrategy": {"custom"},
+ "RegexChunking": {"patterns"},
}
- Arbitrary Hugging Face model loading (
CVE-2026-119120/GHSA-f856-7xp9-w3cc): Previously,CosineStrategywas onUNTRUSTED_ALLOWED_TYPESwithout field restrictions, so a caller could pass{"type": "CosineStrategy", "params": {"model_name": "attacker/malicious-repo"}}. The server passedmodel_namestraight totransformers/sentence-transformersfrom_pretrained(), downloading attacker-chosen weights (and executingpicklepayloads on PyTorch< 2.6). - Unbounded crawl delays and GIL-blocking regexes (
CVE-2026-119119/GHSA-rhjm-7hj7-75fxandGHSA-j843-8p47-rhxp):_clamp_untrusted()now capsdelay_before_return_html,mean_delay, andmax_rangeat60seconds and rejects custom regex patterns inRegexExtractionStrategy,RegexChunking, and extraction schemas. - Page JS injection (
CVE-2026-119121),CacheValidatorSSRF (CVE-2026-119122), and Chromium TLS verification (CVE-2026-119118):css_selectoris now passed to Playwright’spage.evaluate()as a serialized argument rather than interpolated into JS source;wait_for="js:..."is rejected forProvenance.UNTRUSTED;CacheValidator.validate()routes itsHEADandGETfreshness probes through the pinning egress proxy (egress_broker.py, which also now fails closed withEgressBlockedinstead ofexcept Exception: pass); and--ignore-certificate-errors/--allow-insecure-localhostwere removed from the default Chromium launch flags indeploy/docker/utils.py.
3. @sylphx/pdf-reader-mcp 3.0.1 (CVE-2026-62264) and llama.cpp b11935 (CVE-2026-119052)
In @sylphx/pdf-reader-mcp (>= 2.2.0, < 3.0.1), src/index.ts read const apiKey = process.env['MCP_API_KEY'] and logged API key authentication enabled (X-API-Key header) when starting the HTTP transport (MCP_TRANSPORT=http), but never passed apiKey to startHttpServer() in src/mcp.ts. At the same time, MCP_HTTP_HOST defaulted to '0.0.0.0'. Every /mcp request was accepted without checking X-API-Key. Commit 4c35f72862 (v3.0.1) changes the default MCP_HTTP_HOST to '127.0.0.1' and validates req.headers['x-api-key'] on /mcp using SHA-256 digests and crypto.timingSafeEqual():
// SylphxAI/anymd commit 4c35f72862: src/mcp.ts
const isApiKeyValid = (configuredKey: string, presented: string | string[] | undefined): boolean => {
const provided = Array.isArray(presented) ? presented[0] : presented;
if (typeof provided !== 'string' || provided.length === 0) return false;
const expected = createHash('sha256').update(configuredKey).digest();
const actual = createHash('sha256').update(provided).digest();
return timingSafeEqual(expected, actual);
};
In llama.cpp (b2877 before b11935), ggml/src/ggml-rpc/ggml-rpc.cpp implements the distributed inference RPC server. After the initial HELLO packet, recv_msg() reads a 64-bit uint64_t size from the TCP socket and resizes a std::vector<uint8_t>:
--- a/ggml/src/ggml-rpc/ggml-rpc.cpp
+++ b/ggml/src/ggml-rpc/ggml-rpc.cpp
@@ -348,7 +348,10 @@ static bool recv_msg(socket_ptr sock, std::vector<uint8_t> & input) {
}
try {
input.resize(size);
- } catch (const std::bad_alloc & e) {
+ } catch (const std::length_error &) {
+ LOG_ERROR("Failed to allocate input buffer of size %" PRIu64 "\n", size);
+ return false;
+ } catch (const std::bad_alloc &) {
LOG_ERROR("Failed to allocate input buffer of size %" PRIu64 "\n", size);
return false;
}
In C++, std::vector::resize(size) checks if (size > max_size()) before calling the allocator and throws std::length_error (which inherits from std::logic_error, not std::bad_alloc). Sending an 8-byte length prefix with size = 0xffffffffffffffff bypassed the catch (const std::bad_alloc &) handler and terminated rpc-server via std::terminate(). Commit 7ecb57f7ad (PR #31204, b11935) catches std::length_error alongside std::bad_alloc.
Detection and remediation
# 1. Check Python environments and lockfiles for praisonai and crawl4ai
pip show praisonai praisonaiagents crawl4ai 2>/dev/null || true
rg -n '"?(praisonai|praisonaiagents|crawl4ai)"?\s*([~=!<>]=|:)' \
requirements*.txt pyproject.toml uv.lock poetry.lock Pipfile.lock 2>/dev/null
# 2. Check Docker Compose / Kubernetes manifests for unclecode/crawl4ai or @sylphx/pdf-reader-mcp
rg -n 'unclecode/crawl4ai|@sylphx/pdf-reader-mcp|MCP_TRANSPORT' \
docker-compose*.yml Dockerfile* *.yaml *.json 2>/dev/null
# 3. Check running llama.cpp rpc-server processes
ps aux | grep '[r]pc-server' || true
- Upgrade
praisonaito>= 4.6.78andpraisonaiagentsto>= 1.6.78(4.7.21and1.7.19are current on PyPI). Do not setPRAISONAI_ALLOW_JOB_WORKFLOWS=trueorPRAISONAI_ALLOW_LOCAL_TOOLS=truewhen processing untrusted YAML workflows. - Upgrade
crawl4aito>= 0.9.5and pull the updatedunclecode/crawl4ai:0.9.5container image. EnsureCRAWL4AI_API_TOKENis set on every network-reachable Docker deployment. - Upgrade
@sylphx/pdf-reader-mcpto>= 3.0.1(8.5.5is current), or setMCP_HTTP_HOST=127.0.0.1if you cannot upgrade immediately. - Upgrade
llama.cppto>= b11935and never exposeggml-rpc(rpc-server) ports outside a trusted cluster network.
Timeline
- 2026-06-25: PraisonAI releases
v4.6.78(393de39408) and@sylphx/pdf-reader-mcpreleasesv3.0.1(4c35f72862). - 2026-09-29 to 2026-10-01: Researchers report the six
Crawl4AIDocker server andCacheValidatorvulnerabilities tounclecode. - 2026-10-14:
Crawl4AItags and publishesv0.9.5on PyPI and merges PR#2368(6192d5e5b5) tomainon 20 October. - 2026-10-29 (
14:17to16:34 UTC): NVD and the GitHub Advisory Database publishCVE-2026-61438(GHSA-26mh-57q7-jfvr),CVE-2026-119118throughCVE-2026-119122,CVE-2026-62264(GHSA-q344-5v34-gm84), andCVE-2026-119052.
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
- PraisonAI advisory GHSA-26mh-57q7-jfvr (CVE-2026-61438: RCE via broken AST sandbox) and commit 393de39408
- Crawl4AI v0.9.5 release PR #2368 (commit 6192d5e5b5) and SECURITY.md (GHSA-f856-7xp9-w3cc, GHSA-rhjm-7hj7-75fx, GHSA-j2qh-f73r-mg3q, GHSA-qj46-wp7m-rgj8, GHSA-w4xc-px5p-c32w)
- @sylphx/pdf-reader-mcp advisory GHSA-q344-5v34-gm84 (CVE-2026-62264) and commit 4c35f72862
- ggml-org/llama.cpp commit 7ecb57f7ad (PR #31204: catch std::length_error in ggml-rpc recv_msg, CVE-2026-119052)
- NVD: CVE-2026-61438, CVE-2026-119120, CVE-2026-62264, and CVE-2026-119052