Patched in June, Published in October: Two PraisonAI CVEs and the Fix That Needed a Second Fix
NVD published CVE-2026-57118 and CVE-2026-57143 against PraisonAI within 170 milliseconds of each other at 19:16Z on 12 October 2026. Both are GitHub-assigned, both are still vulnStatus: Received, and both describe problems the project fixed on 17 June 2026. The CVE numbers themselves give it away — 57118 and 57143 sit in a block allocated months before the 108xxx and 109xxx records this site has been reading all week. These are June advisories arriving in October’s feed.
That lag is the reason to write about them rather than a reason to skip them. A four-month gap between patch and public record is the window in which your SCA scanner says nothing, your dependency bot opens no PR, and your inventory of “known-vulnerable agent frameworks” is silently wrong. PraisonAI has 9,230 stars and 1,478 forks and was pushed again this morning; praisonaiagents is at 1.7.12 on PyPI. Anyone who pinned in June and has not moved is in range.
CVE-2026-57118: the endpoints with no door
The record (9.8 critical, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H, CWE-306 and CWE-862) says that prior to praisonaiagents 1.6.59, AgentTeam.launch and the Agents alias registered GET /{path}/list, POST /{path} and POST /{path}/{agent_id} “without access-control checks before listing agents or calling agent.chat.” An exposed server therefore lets unauthenticated clients enumerate agents, consume model resources, reach connected private context, and trigger tools and workflow side effects. GHSA-x8cv-xmq7-p8xp was published 17 June at 07:32Z; praisonaiagents 1.6.59 went to PyPI at 07:24Z the same morning, eight minutes earlier. Fix first, advisory second, same hour — that part is exactly how it should go.
So we read the commit the advisory points at, b4270173 (“feat(auth): implement API key authentication middleware for AgentOS”, 17 June 07:23Z). It adds an authorisation check to all three handlers, and the check is this:
def _authorise_launch_request(request) -> bool:
token = _launch_auth_token()
if not token:
return True
auth = request.headers.get("Authorization", "")
if auth.startswith("Bearer ") and auth[7:] == token:
return True
return request.headers.get("X-Auth-Token") == token
The token comes from the environment variable PRAISONAI_LAUNCH_AUTH_TOKEN. If that variable is not set, every request is authorised. As shipped on 17 June, an operator who upgraded to 1.6.59 and changed nothing else was running the same unauthenticated endpoints the 9.8 describes. The mechanism was added; it was off by default.
This is a shape this site keeps finding in agent frameworks, and it is worth naming because it is so consistent. agno’s AgentOS carries if not settings or not settings.os_security_key: return True, which we wrote about on Sunday; Wukong’s ParamAspect passed an empty UserInfo through a null check, which we covered in Yaqi Chao’s batch. In every case the authentication code exists, is correct when engaged, and admits everyone when the operator has not configured it. CWE-306 is the right identifier and it is also slightly misleading: the authentication is not missing, it is optional, and optional on an HTTP server that answers from the network is the same thing wearing a better name.
The fix that finished the job — two months later
Here is the part that changes the remediation advice, and we found it by following the code to main rather than stopping at the advisory. The fail-open branch is still there today. What is also there, and was not there in June, is a bind guard. On 20 August 2026, commit 5d5d4c3a (“fix: enforce launch auth + fail-closed bind on Agent.launch”) moved both helpers into a shared module, praisonaiagents/agent/launch_security.py, and added resolve_launch_host. Its logic, read at main HEAD:
- Token set → bind the requested host unchanged; auth protects the endpoint.
- Token unset and loopback host → bind unchanged, local development unaffected.
- Token unset and non-loopback host → auto-generate a
secrets.token_urlsafe(32), export it intoPRAISONAI_LAUNCH_AUTH_TOKENso every route enforces it, and print it once.
That is a genuinely good design, and the module’s own docstring explains the reasoning better than most: the two launch paths “must enforce identical request authorisation and must not silently bind all interfaces without a token,” and the helpers live in one place “so the two launch paths cannot drift apart.” It closes the exposure case without refusing to start, and a follow-up the same morning (855cc0b9) made the generated token per-process rather than per-launch so a later launch cannot lock out an already-serving endpoint’s clients. The June comparison by == has also become secrets.compare_digest.
The August work came from the maintainer’s own issue #4083, filed 20 August and titled, with unusual candour for a self-filed ticket, “Agent.launch() serves HTTP with no authentication on 0.0.0.0 while the multi-agent launch enforces a token — close the asymmetry.” The issue is about the single-agent path, which genuinely had no check at all; the multi-agent path CVE-2026-57118 names did get its check in June. But the guard that makes a fail-open check meaningful on an internet-facing bind arrived with it, and not before.
We pinned the version. pyproject.toml reads 1.6.168 at both August commits, and praisonaiagents 1.6.168 was published to PyPI on 19 August — before them. The next release is 1.7.0, published 21 August 2026. So the practical guidance diverges from the advisory: the CVE says “fixed in 1.6.59,” and 1.6.59 does add the access-control checks it describes, but if your deployment binds anything other than loopback and you do not set the environment variable yourself, 1.7.0 is the first release in which that matters.
CVE-2026-57143: the search tool the model aims
The second record (8.8, AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:L, CWE-20 and CWE-918) is the cleaner story and the more interesting threat model. Prior to 1.6.62, searxng_search and the search_web SearxNG provider passed the LLM-controlled searxng_url parameter straight to requests.get with no validation of scheme, host, port or resolved address. Prompt-injected content can therefore point the default search tool at internal JSON services, distinguish open from closed internal ports by response behaviour, and attempt cloud-metadata requests — with the returned JSON flowing back into agent context. The S:C scope change in the vector is correctly assigned for once: the vulnerable component and the impacted component are not the same system.
Note what the attacker’s input channel is. There is no API to call and no credential to steal. A web page the agent reads, a document it summarises, a tool result it ingests — anything that reaches the model and persuades it to pass a different searxng_url. SSRF where the parameter is chosen by a language model reading attacker-authored text is SSRF with a much wider front door than the classic form, and the UI:R in the vector is carrying an assumption about how agents get used that is worth arguing with.
The fix (2a855c47, 17 June 10:04Z, released as 1.6.62 to PyPI at 10:03Z) adds a new 55-line module, tools/url_safety.py, and calls it from both sinks — returning [{"error": "SearxNG URL blocked by SSRF policy"}] from the tool and raising from the provider. It resolves the hostname with getaddrinfo and rejects loopback, private, link-local, multicast and unspecified addresses. It also shipped with regression tests, including one asserting http://169.254.169.254/latest/meta-data/ is blocked.
The June version had a structural weakness we can state precisely because we read both: _allowlist_hosts() merged the operator-supplied SEARXNG_URL_ALLOWLIST with the hardcoded loopback names, and an allowlist hit returned True before any address classification. An operator who allowlisted an internal hostname was therefore exempting it from the metadata and private-range checks entirely, not just from the loopback check they intended. At main HEAD this is fixed properly: is_safe_http_url now classifies every resolved address and an allowlist entry exempts only the loopback class, with a docstring that says so — “private, link-local, multicast and unspecified addresses stay blocked even when the host is allowlisted, so an entry can never be abused to reach cloud metadata.” The module has also grown an is_ambiguous_numeric_host check rejecting octal and hex dotted-quads, written against a resolver parser differential (glibc’s inet_aton reading 0177.0.0.1 as loopback where getaddrinfo on macOS reads 177.0.0.1), attributed in-comment to a later advisory. That is a maintainer iterating on a control rather than closing a ticket.
Two things are still true at main HEAD, and we note them as observations rather than as a claimed vulnerability. First, searxng_tools.py line 56 is requests.get(url, params=params, timeout=10) — allow_redirects defaults to True, so the address the validator classified is not necessarily the only address the client connects to. Second, validate-then-fetch re-resolves the hostname between the getaddrinfo call and the request, which is the ordinary DNS-rebinding window for every validator of this shape. Both are well-known limits of host-based SSRF validation and neither is specific to this project; the durable fix for both is egress policy at the network layer rather than a cleverer string check.
What to do
- Move to
praisonaiagents1.7.0 or later — not 1.6.59 or 1.6.62 as the records state. 1.6.59 adds the auth check but leaves it fail-open; the fail-closed bind guard first ships in 1.7.0 (21 August 2026). Current PyPI is 1.7.12. - Set
PRAISONAI_LAUNCH_AUTH_TOKENexplicitly anyway. Relying on the auto-generated token means the credential is printed to a log once and regenerated per process. Set it yourself, from a secret store, and you control rotation. - Assume exposure if you ran
launch()on a non-loopback host before August. The endpoints invoked agents with whatever tools and context those agents held. Review model-provider spend, review what the agents could reach, and rotate credentials those tools used. - Do not treat the SSRF fix as a substitute for egress control. Redirects and re-resolution sit outside what a URL validator can decide. Agents that fetch URLs the model chooses belong behind an egress proxy with an allowlist, with the cloud metadata endpoint blocked at the network and IMDSv2 enforced.
- Re-scan on CVE publication date, not patch date. This pair is a four-month example of why a clean SCA report in July meant nothing about July. If you maintain an inventory of agent frameworks, pull the vendor’s own advisory feed rather than waiting for NVD to catch up.
Verification note. Both CVE identifiers, publication timestamps (19:16:38.940Z and 19:16:39.110Z, 12 October 2026), vulnStatus: Received, CVSS 3.1 vectors and base scores, CWE assignments, source identifier (security-advisories@github.com) and full descriptions were read first-hand from the NVD 2.0 API. Advisory titles, severities and publication timestamps for GHSA-x8cv-xmq7-p8xp and GHSA-4pcv-mg8v-vrgf were read first-hand from the GitHub advisories API. Commits b4270173, 2a855c47, 5d5d4c3a and 855cc0b9 — their authors, timestamps, messages, file lists and diffs — and issue #4083’s title, author, state and body were read first-hand from the GitHub API. All code excerpts are quoted verbatim from files fetched directly: agents/agents.py at commit b4270173 and at main, tools/url_safety.py at tag v4.6.62 and at main, tools/searxng_tools.py at main, and agent/launch_security.py at main. Version-to-release mapping was established by reading pyproject.toml at the August commits and cross-checking praisonaiagents publication timestamps on the PyPI JSON API; 1.6.168 (19 August) precedes both August commits and 1.7.0 (21 August) follows them. Star, fork and push counts are from the GitHub API. We did not install PraisonAI, start a launch() server, send a request to any deployment, execute a prompt injection, or attempt any SSRF against any host. The fail-open reading, the comparison to agno and Wukong, the redirect and re-resolution observations, and the recommendation to target 1.7.0 rather than the advisory-named versions are our editorial analysis. We have no evidence of exploitation and imply none.
Sources:
- NVD — CVE-2026-57118, PraisonAI unauthenticated agent listing and invocation (9.8, CWE-306/862, fixed in 1.6.59)
- NVD — CVE-2026-57143, SSRF via LLM-controlled
searxng_url(8.8, CWE-20/918, fixed in 1.6.62) - GHSA-x8cv-xmq7-p8xp — “AgentTeam.launch Exposes Unauthenticated Remote Agent Listing and Invocation Endpoints” (17 June 2026)
- GHSA-4pcv-mg8v-vrgf — SSRF in SearxNG /
search_webtools via attacker-controlledsearxng_url(17 June 2026) - MervinPraison/PraisonAI issue #4083 — “close the asymmetry” between the single-agent and multi-agent launch paths (20 August 2026)
- PraisonAI
agent/launch_security.pyatmain— the fail-closed bind guard and the fail-open token check - PraisonAI
tools/url_safety.pyatmain— per-class address checking and the ambiguous-numeric-host rejection