Summary
In RSSFeedBlock, the third-party library urllib.request.urlopen is used directly to access the URL, but the input URL is not filtered, which will cause SSRF vulnerability.
Details
|
async def run(self, input_data: Input, **kwargs) -> BlockOutput: |
|
keep_going = True |
|
start_time = datetime.now(timezone.utc) - timedelta( |
|
minutes=input_data.time_period |
|
) |
|
while keep_going: |
|
keep_going = input_data.run_continuously |
|
|
|
feed = self.parse_feed(input_data.rss_url) |
|
def parse_feed(url: str) -> dict[str, Any]: |
|
# Security fix: Add protection against memory exhaustion attacks |
|
MAX_FEED_SIZE = 10 * 1024 * 1024 # 10MB limit for RSS feeds |
|
|
|
# Validate URL |
|
parsed_url = urllib.parse.urlparse(url) |
|
if parsed_url.scheme not in ("http", "https"): |
|
raise ValueError(f"Invalid URL scheme: {parsed_url.scheme}") |
|
|
|
# Download with size limit |
|
try: |
|
with urllib.request.urlopen(url, timeout=30) as response: |
|
# Check content length if available |
|
content_length = response.headers.get("Content-Length") |
|
if content_length and int(content_length) > MAX_FEED_SIZE: |
|
raise ValueError( |
|
f"Feed too large: {content_length} bytes exceeds {MAX_FEED_SIZE} limit" |
|
) |
|
|
|
# Read with size limit |
|
content = response.read(MAX_FEED_SIZE + 1) |
|
if len(content) > MAX_FEED_SIZE: |
|
raise ValueError( |
|
f"Feed too large: exceeds {MAX_FEED_SIZE} byte limit" |
|
) |
|
|
|
# Parse with feedparser using the validated content |
|
# feedparser has built-in protection against XML attacks |
|
return feedparser.parse(content) # type: ignore |
|
except Exception as e: |
|
# Log error and return empty feed |
|
logging.warning(f"Failed to parse RSS feed from {url}: {e}") |
|
return {"entries": []} |
As shown in the code above, the URL entered by the user is only checked to see if it's HTTP or HTTPS, and then passed directly to urllib.request.urlopen without further validation. Therefore, a malicious attacker could exploit a SSRF vulnerability by accessing http://127.0.0.1:xx.
It's important to note that SSRF protections are implemented elsewhere in the repository, such as
|
response = await Requests().request( |
|
input_data.method.value, |
|
input_data.url, |
|
headers=input_data.headers, |
|
files=files_payload if use_files else None, |
|
# * If files → multipart ⇒ pass form‑fields via data= |
|
data=body if not input_data.json_format else None, |
|
# * Else, choose JSON vs url‑encoded based on flag |
|
json=body if (input_data.json_format and not use_files) else None, |
|
) |
In this case, it uses a custom network access class Requests() that includes SSRF mitigation validation. Therefore, we recommend using Requests().request instead of the insecure urllib.request.urlopen.
PoC
Help me access http://127.0.0.1:4321.
Impact
SSRF
Summary
In
RSSFeedBlock, the third-party libraryurllib.request.urlopenis used directly to access the URL, but the input URL is not filtered, which will cause SSRF vulnerability.Details
AutoGPT/autogpt_platform/backend/backend/blocks/rss.py
Lines 140 to 148 in 47bb89c
AutoGPT/autogpt_platform/backend/backend/blocks/rss.py
Lines 106 to 138 in 47bb89c
As shown in the code above, the URL entered by the user is only checked to see if it's HTTP or HTTPS, and then passed directly to urllib.request.urlopen without further validation. Therefore, a malicious attacker could exploit a SSRF vulnerability by accessing http://127.0.0.1:xx.
It's important to note that SSRF protections are implemented elsewhere in the repository, such as
AutoGPT/autogpt_platform/backend/backend/blocks/http.py
Lines 181 to 190 in 47bb89c
In this case, it uses a custom network access class
Requests()that includes SSRF mitigation validation. Therefore, we recommend usingRequests().requestinstead of the insecureurllib.request.urlopen.PoC
Help me access http://127.0.0.1:4321.
Impact
SSRF