T09 · Insecure Skill Coding Practices
Error
- Location
- r2.py:158
- Finding
- Signed Authorization Headers May Be Forwarded to an Unvalidated Redirect Destination## Vulnerability Details **File Location**: `r2.py`, lines 158–174 **Vulnerability Type**: Authorization header exposure through automatic cross-origin redirects **Risk Level**: High ```python _validate_url(url) headers = _aws_headers(method, canonical_uri, query, body) req = urllib.request.Request( url, data=body if body else None, headers=headers, method=method, ) # Create restricted opener (HTTPS only) opener = urllib.request.build_opener( urllib.request.HTTPSHandler() ) try: with opener.open(req, timeout=30) as resp: # nosec B310 return resp.status, resp.read() ``` ### Technical Analysis The code validates only the initial URL before creating the request. The opener constructed by `urllib.request.build_opener()` includes standard redirect handling in addition to the explicitly supplied HTTPS handler. Redirect destinations are therefore not passed through `_validate_url()`. Request headers supplied through the `Request` constructor can be copied to a redirected request. This may include the AWS Signature Version 4 `Authorization` header, the R2 access-key identifier contained in its credential scope, `x-amz-date`, and `x-amz-content-sha256`. HTTPS enforcement alone does not prevent disclosure because an attacker-controlled redirect destination can also use HTTPS. Moreover, the current hostname check at line 139 uses: ```python if not parsed.netloc.endswith("cloudflarestorage.com"): raise ValueError("Unexpected host") ``` A suffix comparison without a hostname boundary is weaker than comparison against the exact expected R2 hostname. Validation should use `parsed.hostname` and an exact allowlist. ### Attack Path 1. A user invokes an operation such as `download`, `list`, or `delete`. 2. `_aws_headers()` generates a signed request containing the access-key identifier and AWS Signature Version 4 authentication material. 3. The Cloudflare endpoint, ...[truncated 1289 chars]
- Remediation
- ## Remediation Suggestions - Disable automatic redirects by installing a custom `urllib.request.HTTPRedirectHandler` that rejects every redirect. - If redirects are operationally required, validate every redirect target before following it. - Require `parsed.scheme == "https"` and compare `parsed.hostname` against the exact expected hostname: ```python expected_host = f"{ACCOUNT_ID}.r2.cloudflarestorage.com" if parsed.scheme != "https" or parsed.hostname != expected_host: raise ValueError("Unexpected destination") ``` - Reject URLs containing user information, unexpected ports, fragments, or other authority ambiguity. - Never forward an existing `Authorization` header across origins. - Regenerate the AWS Signature Version 4 header only after an approved redirect destination and canonical request have been validated. - Add automated tests covering cross-origin redirects, same-origin redirects, HTTPS-to-HTTP redirects, suffix-confusion hostnames, and redirects containing user information.
