CVE-2026-47390
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
PraisonAI is a multi-agent teams system. Prior to version 4.6.40 of PraisonAI, corresponding to version 1.6.40 of praisonaiagents, spider_tools URL validation can be bypassed using alternate loopback host encodings. The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1. It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request. As a result, certain URLs may bypass the protection and still reach loopback services. After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services. This is a server-side request forgery protection bypass. PraisonAI version 4.6.40 and praisonaiagents version 1.6.40 contain a patch.
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
5.5
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
PraisonAI is a multi-agent teams system. Prior to version 4.6.40 of PraisonAI, corresponding to version 1.6.40 of praisonaiagents, spider_tools URL validation can be bypassed using alternate loopback host encodings. The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1. It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request. As a result, certain URLs may bypass the protection and still reach loopback services. After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services. This is a server-side request forgery protection bypass. PraisonAI version 4.6.40 and praisonaiagents version 1.6.40 contain a patch.
- Record
CVE-2026-47390- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-46278
5.5
PraisonAI is a multi-agent teams system. Prior to version 4.6.40 of PraisonAI, corresponding to version 1.6.40 of praisonaiagents, spider_tools URL validation can be bypassed using alternate loopback host encodings. The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1. It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request. As a result, certain URLs may bypass the protection and still reach loopback services. After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services. This is a server-side request forgery protection bypass. PraisonAI version 4.6.40 and praisonaiagents version 1.6.40 contain a patch.
- Record
EUVD-2026-46278- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-5c6w-wwfq-7qqm
5.5
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
Summary
PraisonAI's spider_tools URL validation can be bypassed using alternate loopback host encodings.
The affected component is:
praisonaiagents/tools/spider_tools.py
The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1.
It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request.
As a result, URLs such as the following bypass the protection and still reach loopback services:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services.
This is a server-side request forgery protection bypass.
Details
The affected code is in:
praisonaiagents/tools/spider_tools.py
The vulnerable flow is:
attacker-controlled URL
-> spider_tools._validate_url(...)
-> weak exact-host blocklist check
-> validation passes for alternate loopback encodings
-> scrape_page(...)
-> requests.Session.get(attacker_url)
-> loopback service is reached
The validation appears to block only exact local hostnames or exact IPv4 strings. For example, it blocks simple forms such as:
localhost
127.0.0.1
However, equivalent loopback forms are not rejected before the request is made.
Confirmed bypass examples:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
These values can resolve or be interpreted as loopback addresses by the HTTP client / underlying networking stack, while bypassing the string-based validation.
The issue is not that spider_tools can fetch arbitrary URLs. The issue is that it attempts to provide SSRF protection, but the protection can be bypassed with alternate representations of loopback addresses.
PoC
The following PoC is non-destructive. It starts a local HTTP server on 127.0.0.1:8765, then sends several alternate loopback URL forms through the real spider_tools validation/fetch path.
The expected secure behavior is that all loopback variants should be rejected before any HTTP request is made.
The actual vulnerable behavior is that the alternate loopback forms pass validation and reach the local server.
Full PoC
#!/usr/bin/env python3
"""PoC for PraisonAI spider_tools localhost-alias SSRF bypass."""
from __future__ import annotations
import sys
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[3] / "repos" / "praisonai"
AGENTS_ROOT = REPO_ROOT / "src" / "praisonai-agents"
SPIDER_TOOLS = AGENTS_ROOT / "praisonaiagents/tools/spider_tools.py"
def verify_source() -> None:
expected = [
"def _validate_url",
"requests.Session",
".get(",
]
text = SPIDER_TOOLS.read_text(encoding="utf-8")
for needle in expected:
if needle not in text:
raise RuntimeError(f"source verification failed: {needle!r} not found in {SPIDER_TOOLS}")
class LocalHandler(BaseHTTPRequestHandler):
hits: list[tuple[str, str | None]] = []
body = b"LOCAL-SPIDER-SSRF-SECRET"
def do_GET(self) -> None: # noqa: N802
self.__class__.hits.append((self.path, self.headers.get("Host")))
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(self.body)))
self.end_headers()
self.wfile.write(self.body)
def log_message(self, format:…
- Record
GHSA-5c6w-wwfq-7qqm- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
NVD
5.5
PraisonAI is a multi-agent teams system. Prior to version 4.6.40 of PraisonAI, corresponding to version 1.6.40 of praisonaiagents, spider_tools URL validation can be bypassed using alternate loopback host encodings. The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1. It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request. As a result, certain URLs may bypass the protection and still reach loopback services. After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services. This is a server-side request forgery protection bypass. PraisonAI version 4.6.40 and praisonaiagents version 1.6.40 contain a patch.
- Record
CVE-2026-47390- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSV
5.5
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
PraisonAI is a multi-agent teams system. Prior to version 4.6.40 of PraisonAI, corresponding to version 1.6.40 of praisonaiagents, spider_tools URL validation can be bypassed using alternate loopback host encodings. The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1. It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request. As a result, certain URLs may bypass the protection and still reach loopback services. After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services. This is a server-side request forgery protection bypass. PraisonAI version 4.6.40 and praisonaiagents version 1.6.40 contain a patch.
- Record
CVE-2026-47390- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVGHSA-5c6w-wwfq-7qqm
5.5
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
Summary
PraisonAI's spider_tools URL validation can be bypassed using alternate loopback host encodings.
The affected component is:
praisonaiagents/tools/spider_tools.py
The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1.
It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request.
As a result, URLs such as the following bypass the protection and still reach loopback services:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services.
This is a server-side request forgery protection bypass.
Details
The affected code is in:
praisonaiagents/tools/spider_tools.py
The vulnerable flow is:
attacker-controlled URL
-> spider_tools._validate_url(...)
-> weak exact-host blocklist check
-> validation passes for alternate loopback encodings
-> scrape_page(...)
-> requests.Session.get(attacker_url)
-> loopback service is reached
The validation appears to block only exact local hostnames or exact IPv4 strings. For example, it blocks simple forms such as:
localhost
127.0.0.1
However, equivalent loopback forms are not rejected before the request is made.
Confirmed bypass examples:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
These values can resolve or be interpreted as loopback addresses by the HTTP client / underlying networking stack, while bypassing the string-based validation.
The issue is not that spider_tools can fetch arbitrary URLs. The issue is that it attempts to provide SSRF protection, but the protection can be bypassed with alternate representations of loopback addresses.
PoC
The following PoC is non-destructive. It starts a local HTTP server on 127.0.0.1:8765, then sends several alternate loopback URL forms through the real spider_tools validation/fetch path.
The expected secure behavior is that all loopback variants should be rejected before any HTTP request is made.
The actual vulnerable behavior is that the alternate loopback forms pass validation and reach the local server.
Full PoC
#!/usr/bin/env python3
"""PoC for PraisonAI spider_tools localhost-alias SSRF bypass."""
from __future__ import annotations
import sys
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[3] / "repos" / "praisonai"
AGENTS_ROOT = REPO_ROOT / "src" / "praisonai-agents"
SPIDER_TOOLS = AGENTS_ROOT / "praisonaiagents/tools/spider_tools.py"
def verify_source() -> None:
expected = [
"def _validate_url",
"requests.Session",
".get(",
]
text = SPIDER_TOOLS.read_text(encoding="utf-8")
for needle in expected:
if needle not in text:
raise RuntimeError(f"source verification failed: {needle!r} not found in {SPIDER_TOOLS}")
class LocalHandler(BaseHTTPRequestHandler):
hits: list[tuple[str, str | None]] = []
body = b"LOCAL-SPIDER-SSRF-SECRET"
def do_GET(self) -> None: # noqa: N802
self.__class__.hits.append((self.path, self.headers.get("Host")))
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(self.body)))
self.end_headers()
self.wfile.write(self.body)
def log_message(self, format:…
- Record
GHSA-5c6w-wwfq-7qqm- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Weakness
- CWE-918
- Updated
- 2026-11-02
OSVPYSEC-2026-2902
5.5
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
Summary
PraisonAI's spider_tools URL validation can be bypassed using alternate loopback host encodings.
The affected component is:
praisonaiagents/tools/spider_tools.py
The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1.
It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request.
As a result, URLs such as the following bypass the protection and still reach loopback services:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services.
This is a server-side request forgery protection bypass.
Details
The affected code is in:
praisonaiagents/tools/spider_tools.py
The vulnerable flow is:
attacker-controlled URL
-> spider_tools._validate_url(...)
-> weak exact-host blocklist check
-> validation passes for alternate loopback encodings
-> scrape_page(...)
-> requests.Session.get(attacker_url)
-> loopback service is reached
The validation appears to block only exact local hostnames or exact IPv4 strings. For example, it blocks simple forms such as:
localhost
127.0.0.1
However, equivalent loopback forms are not rejected before the request is made.
Confirmed bypass examples:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
These values can resolve or be interpreted as loopback addresses by the HTTP client / underlying networking stack, while bypassing the string-based validation.
The issue is not that spider_tools can fetch arbitrary URLs. The issue is that it attempts to provide SSRF protection, but the protection can be bypassed with alternate representations of loopback addresses.
PoC
The following PoC is non-destructive. It starts a local HTTP server on 127.0.0.1:8765, then sends several alternate loopback URL forms through the real spider_tools validation/fetch path.
The expected secure behavior is that all loopback variants should be rejected before any HTTP request is made.
The actual vulnerable behavior is that the alternate loopback forms pass validation and reach the local server.
Full PoC
#!/usr/bin/env python3
"""PoC for PraisonAI spider_tools localhost-alias SSRF bypass."""
from __future__ import annotations
import sys
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[3] / "repos" / "praisonai"
AGENTS_ROOT = REPO_ROOT / "src" / "praisonai-agents"
SPIDER_TOOLS = AGENTS_ROOT / "praisonaiagents/tools/spider_tools.py"
def verify_source() -> None:
expected = [
"def _validate_url",
"requests.Session",
".get(",
]
text = SPIDER_TOOLS.read_text(encoding="utf-8")
for needle in expected:
if needle not in text:
raise RuntimeError(f"source verification failed: {needle!r} not found in {SPIDER_TOOLS}")
class LocalHandler(BaseHTTPRequestHandler):
hits: list[tuple[str, str | None]] = []
body = b"LOCAL-SPIDER-SSRF-SECRET"
def do_GET(self) -> None: # noqa: N802
self.__class__.hits.append((self.path, self.headers.get("Host")))
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(self.body)))
self.end_headers()
self.wfile.write(self.body)
def log_message(self, format:…
- Record
PYSEC-2026-2902- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
OSVPYSEC-2026-2941
5.5
PraisonAI spider_tools SSRF protection bypass via alternate loopback host encodings
Summary
PraisonAI's spider_tools URL validation can be bypassed using alternate loopback host encodings.
The affected component is:
praisonaiagents/tools/spider_tools.py
The tool contains a URL validation function intended to block local or unsafe targets before fetching attacker-controlled URLs. However, the validation only blocks a small set of exact host strings such as localhost and 127.0.0.1.
It does not normalize hostnames, resolve DNS, parse numeric IPv4 variants, or validate the final resolved IP address before making the request.
As a result, URLs such as the following bypass the protection and still reach loopback services:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
After the weak validation passes, scrape_page() calls requests.Session.get() on the attacker-controlled URL. This allows an attacker who can influence URLs passed to scrape_page, crawl, or extract_text to induce SSRF requests against loopback-only services.
This is a server-side request forgery protection bypass.
Details
The affected code is in:
praisonaiagents/tools/spider_tools.py
The vulnerable flow is:
attacker-controlled URL
-> spider_tools._validate_url(...)
-> weak exact-host blocklist check
-> validation passes for alternate loopback encodings
-> scrape_page(...)
-> requests.Session.get(attacker_url)
-> loopback service is reached
The validation appears to block only exact local hostnames or exact IPv4 strings. For example, it blocks simple forms such as:
localhost
127.0.0.1
However, equivalent loopback forms are not rejected before the request is made.
Confirmed bypass examples:
http://localhost.:8765/
http://127.1:8765/
http://0177.0.0.1:8765/
http://0x7f000001:8765/
http://2130706433:8765/
These values can resolve or be interpreted as loopback addresses by the HTTP client / underlying networking stack, while bypassing the string-based validation.
The issue is not that spider_tools can fetch arbitrary URLs. The issue is that it attempts to provide SSRF protection, but the protection can be bypassed with alternate representations of loopback addresses.
PoC
The following PoC is non-destructive. It starts a local HTTP server on 127.0.0.1:8765, then sends several alternate loopback URL forms through the real spider_tools validation/fetch path.
The expected secure behavior is that all loopback variants should be rejected before any HTTP request is made.
The actual vulnerable behavior is that the alternate loopback forms pass validation and reach the local server.
Full PoC
#!/usr/bin/env python3
"""PoC for PraisonAI spider_tools localhost-alias SSRF bypass."""
from __future__ import annotations
import sys
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[3] / "repos" / "praisonai"
AGENTS_ROOT = REPO_ROOT / "src" / "praisonai-agents"
SPIDER_TOOLS = AGENTS_ROOT / "praisonaiagents/tools/spider_tools.py"
def verify_source() -> None:
expected = [
"def _validate_url",
"requests.Session",
".get(",
]
text = SPIDER_TOOLS.read_text(encoding="utf-8")
for needle in expected:
if needle not in text:
raise RuntimeError(f"source verification failed: {needle!r} not found in {SPIDER_TOOLS}")
class LocalHandler(BaseHTTPRequestHandler):
hits: list[tuple[str, str | None]] = []
body = b"LOCAL-SPIDER-SSRF-SECRET"
def do_GET(self) -> None: # noqa: N802
self.__class__.hits.append((self.path, self.headers.get("Host")))
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(self.body)))
self.end_headers()
self.wfile.write(self.body)
def log_message(self, format:…
- Record
PYSEC-2026-2941- CVSS 3.1
- 5.5 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
praisonaiagentsPyPI |
through 1.6.39 | 1.6.40 |
praisonaiPyPI |
through 4.6.39 | 4.6.40 |
praisonaiagentsPyPI |
before 1.6.40, plus listed versions 0.0.10.0.100.0.1000.0.1010.0.102 Show 45 moreShow less0.0.1030.0.1040.0.1050.0.1060.0.1070.0.1080.0.1090.0.110.0.1100.0.1110.0.1120.0.1130.0.1140.0.1150.0.1160.0.1170.0.1180.0.1190.0.120.0.1200.0.1210.0.1220.0.1230.0.1240.0.1250.0.1260.0.1270.0.1280.0.1290.0.130.0.1300.0.1310.0.1320.0.1330.0.1340.0.1350.0.1360.0.1370.0.1380.0.1390.0.140.0.1400.0.1410.0.1420.0.143 |
1.6.40 |
praisonaiPyPI |
before 4.6.40, plus listed versions 0.0.10.0.100.0.110.0.120.0.13 Show 45 moreShow less0.0.140.0.150.0.160.0.170.0.180.0.190.0.20.0.200.0.210.0.220.0.230.0.240.0.250.0.260.0.270.0.280.0.290.0.30.0.300.0.310.0.320.0.330.0.340.0.350.0.360.0.370.0.380.0.390.0.40.0.400.0.410.0.420.0.430.0.440.0.450.0.460.0.470.0.480.0.490.0.50.0.500.0.520.0.530.0.540.0.55 |
4.6.40 |
History
| Recorded | Changed | Sources |
|---|---|---|
| aliases | EUVD | |
| first indexed | CVE List, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-47390 is a medium vulnerability (CVSS 5.5) in Mervinpraison Praisonai, published May 29, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.18%, the 6th percentile. Fixed in praisonaiagents 1.6.40.
References
github.com/MervinPraison/PraisonAI/security/advisories/GHSA-5c6w-wwfq-7qqm
github.com/MervinPraison/PraisonAI/pull/1684
github.com/MervinPraison/PraisonAI/commit/b0d8f777528f3253a0cfb0a3ef65455da6ae32f6
github.com/advisories/GHSA-5c6w-wwfq-7qqm
github.com/CVEProject/cvelistV5/tree/main/cves/2026/47xxx/CVE-2026-47390.json
nvd.nist.gov/vuln/detail/CVE-2026-47390
github.com/MervinPraison/PraisonAI
pypi.org/project/praisonai
pypi.org/project/praisonaiagents
Left out here: 1,199 versions and the rest of 4 source descriptions. The JSON record has them.