CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

GHSA-528q-4pgm-wvg2
CVSS 6.1

Echo Chamber of Doom: Reflected XSS in go-httpbin

Amit Schendel
Amit Schendel
Senior Security Researcher•January 2, 2026•5 min read
PoC Available

Executive Summary (TL;DR)

go-httpbin < 2.18.0 contains a Reflected XSS vulnerability. By manipulating the 'Content-Type' query parameter on specific endpoints, attackers can force the server to render arbitrary JSON or Base64 input as HTML, executing malicious JavaScript in the victim's browser.

A classic tale of a feature becoming a bug. The popular debugging tool go-httpbin allowed users to control both the reflected content and the Content-Type header, creating a trivial path to Cross-Site Scripting (XSS).

The Hook: The Mirror That Bit Back

In the world of API development, httpbin is sacred ground. It is the ultimate sanity check—a server that simply echoes back whatever you throw at it. Need to verify your headers? Check httpbin. Need to see if your JSON body is formatting correctly? httpbin. It is designed to be a mirror.

The Golang port, go-httpbin, is widely used in containerized environments and CI/CD pipelines because it's fast, lightweight, and compiles to a single binary. But here lies the irony: the very purpose of the tool is to reflect input.

Security engineers often joke that an echo server is just an XSS vulnerability waiting to happen. Usually, frameworks prevent this by strictly enforcing Content-Type: application/json or sanitizing output. But go-httpbin made a critical error in its quest for flexibility: it handed the keys to the Content-Type header directly to the user. It’s like a funhouse mirror that, if you look at it from the wrong angle, reaches out and punches you in the face.

The Flaw: Trust Issues

The vulnerability resides in the core philosophy of the application: "Give the user what they want." Specifically, the endpoints /response-headers and /base64 were designed to let developers test how their clients handle specific server responses.

If a developer wanted to test how their app handles a text/html response, they could simply append ?Content-Type=text/html to the URL. The server would dutifully set the response header to text/html.

Simultaneously, the /response-headers endpoint takes all other query parameters and reflects them back in the response body as a JSON object. Do you see the train wreck coming?

If you tell the server "Set the content type to HTML" and also "Put this <script> tag in the JSON body," the browser receives a payload that it thinks is HTML (because the server said so). It parses the reflected JSON, encounters the script tag, and executes it. The browser doesn't care that the body looks like JSON; the Content-Type header is the ultimate authority here.

The Code: Analysis of the Patch

The fix, implemented in commit 0decfd1a2e88d85ca6bfb8a92421653f647cbc04, is a lesson in defensive programming. The maintainers realized they couldn't just trust the user input anymore.

The Vulnerable Logic: Previously, the code simply took the query parameter and wrote it to the response header writer. It was a direct pipe from user input to HTTP headers.

The Fix: The patch introduces a whitelist (or allowlist) strategy. They defined a map of safeContentTypes:

var safeContentTypes = map[string]bool{
    "text/plain":              true,
    "application/json":        true,
    "application/octet-stream": true,
}

They then implemented a helper function, mustEscapeResponse, which returns true if the requested content type is not in this safe list.

In the handler for /response-headers, the logic now branches. If the content type is deemed "dangerous" (e.g., text/html), the application forcibly HTML-escapes every key and value in the JSON response before sending it:

// heavily simplified pseudocode of the fix
if mustEscapeResponse(contentType) {
    // Create a new map where every string is HTML escaped
    safeHeaders := make(map[string]string)
    for k, v := range headers {
        safeHeaders[html.EscapeString(k)] = html.EscapeString(v)
    }
    writeJSON(safeHeaders)
}

This effectively neutralizes the attack. Even if the browser tries to render the JSON as HTML, the <script> tags are converted to &lt;script&gt;, rendering them harmless text.

The Exploit: Weaponizing the Echo

Let's construct the attack. We have two primary vectors here: reflected headers and base64 decoding.

Vector 1: The Header Injection

We target /response-headers. We need to do two things: set the MIME type to HTML and inject a script payload.

The Payload:

GET /response-headers?Content-Type=text/html&param=<img src=x onerror=alert(1)>

The Server Response:

HTTP/1.1 200 OK
Content-Type: text/html
 
{
  "Content-Type": "text/html",
  "param": "<img src=x onerror=alert(1)>"
}

The browser sees text/html, ignores the curly braces, parses the <img> tag, fails to load src=x, and triggers onerror=alert(1). Game over.

Vector 2: The Base64 Bypass

The /base64 endpoint is even more direct. It decodes whatever you send it.

  1. Encode <script>alert(document.domain)</script> to Base64: PHNjcmlwdD5hbGVydChkb2N1bWVudC5kb21haW4pPC9zY3JpcHQ+.
  2. Craft the URL asking for HTML content type.
GET /base64/PHNjcmlwdD5hbGVydChkb2N1bWVudC5kb21haW4pPC9zY3JpcHQ+?content-type=text/html

The server decodes the string and serves it back as text/html. The browser executes the script immediately. This is a "pure" XSS—no JSON wrapping to worry about.

The Impact: "It's just a dev tool, right?"

I hear this argument constantly: "But httpbin is just for testing! Who cares if it has XSS?"

This mindset is dangerous. go-httpbin is frequently deployed in:

  1. Internal Developer Platforms: Accessible via VPN or corporate SSO. An attacker phishing a developer can pivot from this XSS to steal SSO session tokens or access other internal dashboards via CSRF.
  2. CI/CD Environments: Often running alongside sensitive build artifacts.
  3. Public Showcases: Some companies expose instances for public API documentation testing.

If you can execute Javascript in the context of the domain hosting httpbin, you own that session. If httpbin is hosted on subdomain.corp.com and the company uses wildcard cookies for *.corp.com, the attacker potentially compromises the entire corporate session.

Mitigation: Closing the Loop

The primary fix is simple: Upgrade to version 2.18.0.

However, the maintainers recognized that some users might actually rely on the dangerous behavior for legitimate (albeit terrifying) testing scenarios. They included an escape hatch: the environment variable UNSAFE_ALLOW_DANGEROUS_RESPONSES=true.

[!WARNING] Do not enable UNSAFE_ALLOW_DANGEROUS_RESPONSES in any environment accessible by untrusted users. It effectively reverts the patch and re-opens the XSS hole.

Defense in Depth: Beyond patching, ensure your deployment includes the X-Content-Type-Options: nosniff header globally. While the exploit specifically sets the Content-Type, nosniff is a good general practice to prevent browsers from second-guessing MIME types in other edge cases.

Official Patches

mccutchenFix commit on GitHub

Fix Analysis (1)

Technical Appendix

CVSS Score
6.1/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N

Affected Systems

go-httpbin < 2.18.0

Affected Versions Detail

ProductAffected VersionsFixed Version
go-httpbin
mccutchen
< 2.18.02.18.0
AttributeDetail
GHSA IDGHSA-528q-4pgm-wvg2
CVSS6.1 (Medium)
CWECWE-79 (XSS)
Attack VectorNetwork
Privileges RequiredNone
User InteractionRequired (Phishing)

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-79
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

The software does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.

Exploit Resources

Known Exploits & Detection

GitHub AdvisoryPrimary advisory containing reproduction steps
NucleiDetection Template Available

Vulnerability Timeline

Vulnerability Timeline

Vulnerability fixed in commit 0decfd1
2025-03-20
GHSA-528q-4pgm-wvg2 Published
2025-03-21
Nuclei Template Released
2025-03-25

References & Sources

  • [1]GitHub Advisory GHSA-528q-4pgm-wvg2
  • [2]OSV GO-2025-3554

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.