HTTP response splitting with cloud storage
Description
This vulnerability occurs when an nginx proxy configuration uses a permissive regular expression to route requests to cloud storage buckets (such as AWS S3 or Google Cloud Storage). By default, regular expressions match newline characters, allowing attackers to inject CRLF (Carriage Return Line Feed) sequences into the proxied request. This enables HTTP Response Splitting attacks, where a single malicious request can be interpreted as multiple HTTP requests, potentially redirecting the server to fetch resources from an attacker-controlled bucket instead of the legitimate one.
For example, a vulnerable nginx configuration might look like:
location ~ /docs/([^/]*/[^/]*)? {
proxy_pass https://bucket.s3.amazonaws.com/docs-website/$1.html;
}An attacker can exploit this by crafting a URL containing encoded newlines to manipulate the proxied request path and inject malicious HTTP headers.
Remediation
Modify the nginx regular expression to explicitly prevent newline characters from being matched in the capture group. This can be achieved by restricting the character class or using the 's' modifier flag appropriately.
Recommended Fix:
1. Update the regular expression to exclude newline characters by using a more restrictive character class:
location ~ /docs/([a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+)$ {
proxy_pass https://bucket.s3.amazonaws.com/docs-website/$1.html;
}2. Alternatively, explicitly exclude whitespace and control characters:location ~ /docs/([^/\s\r\n]+/[^/\s\r\n]+)$ {
proxy_pass https://bucket.s3.amazonaws.com/docs-website/$1.html;
}3. Validate and sanitize the captured path variable before using it in the proxy_pass directive4. Consider implementing additional security controls such as:
• Whitelist allowed bucket names and paths
• Add strict input validation on the application layer
• Implement Content Security Policy (CSP) headers to limit resource loading
• Use the '$' anchor to ensure the pattern matches to the end of the path
5. After implementing changes, test thoroughly with payloads containing URL-encoded newlines (%0d%0a) to verify the fix