Advisory Details
Title: Server-Side Request Forgery in built-in web_fetch tool allows access to special-use and internal HTTP destinations
Description:
Summary
The built-in web_fetch tool accepts attacker-influenced http and https URLs and issues server-side requests without validating the resolved destination address. An attacker who can drive the agent tool plane can cause the CowAgent process to send HTTP requests to special-use, loopback, private, or other internal network destinations. I verified this against the real WebFetch implementation with an integration PoC that observed an outbound request targeting 198.18.0.1:18080.
Details
The vulnerable logic is in agent/tools/web_fetch/web_fetch.py.
WebFetch.execute() only checks that the supplied URL uses http or https. It does not classify the destination host or any resolved IP before dispatching the request:
parsed = urlparse(url)
if parsed.scheme not in ("http", "https"):
return ToolResult.fail("Error: Invalid URL (must start with http:// or https://)")
After that, the tool directly performs outbound requests with redirects enabled:
response = requests.get(
url,
headers=DEFAULT_HEADERS,
timeout=DEFAULT_TIMEOUT,
allow_redirects=True,
)
The same missing destination validation also exists in the document download path:
response = requests.get(
url,
headers=DEFAULT_HEADERS,
timeout=DEFAULT_TIMEOUT,
stream=True,
allow_redirects=True,
)
This means the tool enforces a scheme allowlist, but not a destination allowlist. In practice, if a user prompt or tool call can influence args["url"], the server will issue the request on the user's behalf.
I verified the behavior with the real WebFetch implementation, not with mocks. The PoC starts:
- a loopback canary HTTP server
- a local proxy oracle used only to observe where the tool tries to connect
Then it invokes WebFetch.execute() twice:
- A benign loopback URL to prove the code path works normally
http://198.18.0.1:18080/special-use to prove the tool does not reject a special-use IPv4 destination
The local proxy captured the original outbound target as:
{
"raw_target": "http://198.18.0.1:18080/special-use",
"host": "198.18.0.1",
"port": 18080,
"path": "/special-use"
}
This is enough to demonstrate SSRF-style server-side network access. Full /message -> model -> tool-selection E2E was attempted previously, but the local environment stopped at the model boundary because the configured DeepSeek credential returned HTTP 401 before any tool call. That limitation does not change the underlying defect: the vulnerable sink is reachable from the agent tool plane, and web_fetch is a built-in loaded tool.
PoC
Prerequisites
- A checkout of the repository
- Python environment with project dependencies sufficient to import
agent.tools.web_fetch.web_fetch
- No authentication is required for the integration-level PoC
- Note: the exploit directory named in prior notes as
CVE-2026-32019-chatgpt-on-wechat-web_fetch-special-use-ipv4-exp is not present in this workspace; the validated PoC artifacts are in the sibling directory CVE-2026-32019-exp/
Reproduction Steps
- Download the integration PoC script from: verification_test.py
- Download the control script from: control-blocked-scheme.py
- Change into the repository root.
- Run the integration PoC:
python3 verification_test.py
- Observe that the script prints
DEFECT-CONFIRMED-WITH-LIMITATIONS and records a proxy observation whose target host is 198.18.0.1.
- Run the control test:
python3 control-blocked-scheme.py
- Observe that the control input
file:///etc/passwd is rejected with Invalid URL (must start with http:// or https://), confirming the current validation only checks the scheme and does not protect against dangerous HTTP destinations.
Log of Evidence
Integration PoC output:
Verification Mode: Integration-Test
[DEFECT-CONFIRMED-WITH-LIMITATIONS] special-use IPv4 URL reached outbound fetch sink without SSRF filtering
{
"mode": "Integration-Test",
"data_flow": "[Test Input URL] -> [WebFetch.execute] -> [requests.get allow_redirects=True] -> [HTTP GET to target IP] -> [canary/proxy evidence]",
"special_use_url": "http://198.18.0.1:18080/special-use",
"loopback_url": "http://127.0.0.1:38933/loopback",
"proxy_url": "http://127.0.0.1:41291",
"loopback_result": {
"status": "success",
"result": "Title: Untitled\\n\\nContent:\\nCVE-2026-32019-SSRF-CANARY path=/loopback"
},
"special_use_result": {
"status": "success",
"result": "Title: Untitled\\n\\nContent:\\nCVE-2026-32019-SSRF-CANARY proxied_target=http://198.18.0.1:18080/special-use"
},
"proxy_observation": {
"raw_target": "http://198.18.0.1:18080/special-use",
"host": "198.18.0.1",
"port": 18080,
"path": "/special-use"
}
}
Control PoC output:
Control Mode: Integration-Test
[CONTROL-PASS] non-http(s) input was rejected by existing validation
{
"status": "error",
"result": "Error: Invalid URL (must start with http:// or https://)"
}
Impact
This is an SSRF issue. Any deployment that exposes agent interaction to untrusted or semi-trusted users is affected if those users can influence web_fetch tool inputs.
Practical impact includes:
- probing internal HTTP services from the server's network position
- reaching loopback, private, or other non-public destinations that are not accessible externally
- retrieving content from internal web dashboards, metadata-style endpoints, or development interfaces if they trust network location rather than user authentication
- using redirects to pivot into additional internal targets because redirects are enabled
The exact downstream impact depends on the network environment of the CowAgent host, but the primitive is real: the attacker gains server-side HTTP reachability they should not have.
Affected products
- Ecosystem: GitHub
- Package name: zhayujie/chatgpt-on-wechat (renamed CowAgent; Python project name
cowagent)
- Affected versions: <= 2.1.1
- Patched versions:
Severity
- Severity: High
- Vector string: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:L/A:L
Weaknesses
- CWE: CWE-918: Server-Side Request Forgery (SSRF)
Occurrences
Advisory Details
Title: Server-Side Request Forgery in built-in
web_fetchtool allows access to special-use and internal HTTP destinationsDescription:
Summary
The built-in
web_fetchtool accepts attacker-influencedhttpandhttpsURLs and issues server-side requests without validating the resolved destination address. An attacker who can drive the agent tool plane can cause the CowAgent process to send HTTP requests to special-use, loopback, private, or other internal network destinations. I verified this against the realWebFetchimplementation with an integration PoC that observed an outbound request targeting198.18.0.1:18080.Details
The vulnerable logic is in
agent/tools/web_fetch/web_fetch.py.WebFetch.execute()only checks that the supplied URL useshttporhttps. It does not classify the destination host or any resolved IP before dispatching the request:After that, the tool directly performs outbound requests with redirects enabled:
The same missing destination validation also exists in the document download path:
This means the tool enforces a scheme allowlist, but not a destination allowlist. In practice, if a user prompt or tool call can influence
args["url"], the server will issue the request on the user's behalf.I verified the behavior with the real
WebFetchimplementation, not with mocks. The PoC starts:Then it invokes
WebFetch.execute()twice:http://198.18.0.1:18080/special-useto prove the tool does not reject a special-use IPv4 destinationThe local proxy captured the original outbound target as:
{ "raw_target": "http://198.18.0.1:18080/special-use", "host": "198.18.0.1", "port": 18080, "path": "/special-use" }This is enough to demonstrate SSRF-style server-side network access. Full
/message-> model -> tool-selection E2E was attempted previously, but the local environment stopped at the model boundary because the configured DeepSeek credential returned HTTP 401 before any tool call. That limitation does not change the underlying defect: the vulnerable sink is reachable from the agent tool plane, andweb_fetchis a built-in loaded tool.PoC
Prerequisites
agent.tools.web_fetch.web_fetchCVE-2026-32019-chatgpt-on-wechat-web_fetch-special-use-ipv4-expis not present in this workspace; the validated PoC artifacts are in the sibling directoryCVE-2026-32019-exp/Reproduction Steps
python3 verification_test.pyDEFECT-CONFIRMED-WITH-LIMITATIONSand records a proxy observation whose target host is198.18.0.1.python3 control-blocked-scheme.pyfile:///etc/passwdis rejected withInvalid URL (must start with http:// or https://), confirming the current validation only checks the scheme and does not protect against dangerous HTTP destinations.Log of Evidence
Integration PoC output:
Control PoC output:
Impact
This is an SSRF issue. Any deployment that exposes agent interaction to untrusted or semi-trusted users is affected if those users can influence
web_fetchtool inputs.Practical impact includes:
The exact downstream impact depends on the network environment of the CowAgent host, but the primitive is real: the attacker gains server-side HTTP reachability they should not have.
Affected products
cowagent)Severity
Weaknesses
Occurrences
WebFetch.execute()accepts attacker-influencedurlinput and only validates that the scheme ishttporhttpsbefore dispatching to fetch handlers.requests.get(..., allow_redirects=True)with no destination-IP validation, enabling SSRF to special-use or internal addresses.requests.get(..., allow_redirects=True)without validating the destination host or redirect chain.