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

|
•

CVE-2025-45286
CVSS 5.3

Echo Chamber of Horrors: Weaponizing go-httpbin for Reflected XSS

Amit Schendel
Amit Schendel
Senior Security Researcher•January 3, 2026•6 min read
PoC Available

Executive Summary (TL;DR)

go-httpbin versions <= 2.17.1 contain a Reflected XSS vulnerability. Endpoints like /response-headers and /base64 allow users to define the response Content-Type while simultaneously reflecting input. Attackers can force the server to serve text/html containing malicious JavaScript.

A classic tale of a debugging tool working exactly as intended, right up until it wasn't. The popular go-httpbin service allowed attackers to coerce the server into serving HTML payloads by manipulating the Content-Type header, turning a harmless echo server into an XSS launchpad.

The Hook: When Features Bite Back

We all love httpbin. It’s the Swiss Army knife of HTTP debugging. Need to test how your client handles a 418 I'm a Teapot? It’s got you. Need to verify your headers are sending correctly? Just ask it to echo them back. It is, by design, an obedient servant that does exactly what you tell it to do.

But here is the problem with obedient servants: they don't ask questions. In the security world, we call this a "confused deputy," but in this specific case, it’s more like a "gullible parrot." The go-httpbin library (a Go port of the original Python httpbin) implemented features allowing clients to control the response headers and the response body simultaneously.

Imagine you tell a server: "Hey, please reply to me with this specific script, and oh, by the way, tell my browser it's definitely an HTML page, not JSON." The server, trying to be helpful, obliges. The result? Your browser executes the script. This isn't a complex buffer overflow or a heap spray; it's a logic flaw born from the assumption that the user knows best.

The Flaw: Trusting the Client with Content-Type

The vulnerability lies in the intersection of two features: Header Control and Data Reflection. The library exposes endpoints like /response-headers and /base64. These endpoints are designed to let developers test their HTTP clients by simulating various server responses.

In the vulnerable code, the application iterates over the query parameters provided by the user. If it finds a parameter named Content-Type, it dutifully overrides the response header. Simultaneously, it takes other parameters (or decoded base64 data) and writes them directly to the response body.

This is the critical failure: Output Encoding. The application assumed that because it usually returns JSON (application/json), it didn't need to escape HTML characters like &lt; or >. But since the user controls the Content-Type, they can switch the context to text/html. The browser sees the header, ignores the fact that the body looks like JSON, and parses any HTML tags it finds inside the reflected string.

The Code: Anatomy of a Reflected XSS

Let's look at the smoking gun in handlers.go before the patch. The logic was deceptively simple—too simple.

// Vulnerable logic (simplified)
func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) {
    // 1. Iterate over query params
    for k, v := range r.URL.Query() {
        // 2. Set headers directly from input
        w.Header().Set(k, v[0])
    }
    
    // 3. Reflect the headers back in the body as JSON
    json.NewEncoder(w).Encode(r.URL.Query())
}

See the issue? If k is Content-Type and v[0] is text/html, the header is set. Then, the json.Encoder writes the query parameters into the body. While JSON encoders escape quotes, they often do not escape HTML characters like &lt; and > by default unless specifically configured to be HTML-safe.

The fix, introduced in commit 0decfd1a2e88d85ca6bfb8a92421653f647cbc04, adds a sanity check. It implements a "safe list" of content types (application/json, text/plain, etc.).

// The Fix: Check for danger
func (h *HTTPBin) mustEscapeResponse(contentType string) bool {
    if h.unsafeAllowDangerousResponses {
        return false
    }
    // Returns true if Content-Type is NOT in the safe list
    return isDangerousContentType(contentType)
}
 
// Inside the handler
if h.mustEscapeResponse(contentType) {
    // Force escape the output if the type is dangerous (e.g., text/html)
    encodedData = html.EscapeString(encodedData)
}

They didn't just remove the feature; they neutered it. If you ask for text/html now, you get it, but the body is HTML-escaped, rendering the script inert.

The Exploit: crafting the Payload

Exploiting this requires nothing more than a web browser and a creative URL. We don't need fancy C2 servers or shellcode. We just need to construct a URL that sets the MIME type and injects the payload.

Attack Vector 1: Response Headers

The /response-headers endpoint reflects query parameters into a JSON object. We inject Content-Type=text/html and our XSS payload into a dummy parameter.

GET /response-headers?Content-Type=text/html&xss=<img src=x onerror=alert(document.domain)> HTTP/1.1
Host: vulnerable-httpbin.com

The server responds with:

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

The browser ignores the curly braces, sees the <img> tag, and fires the alert.

Attack Vector 2: Base64 Decode

The /base64/{data} endpoint is even cleaner. It decodes the input and writes it raw. If we combine this with a query param to set the header, it's game over.

  1. Payload: <script>alert('Pwned')</script>
  2. Base64 Encode: PHNjcmlwdD5hbGVydCgnUHduZWQnKTwvc2NyaXB0Pg==
  3. URL: /base64/PHNjcmlwdD5hbGVydCgnUHduZWQnKTwvc2NyaXB0Pg==?Content-Type=text/html

The response is a pure HTML page containing our script, executed immediately upon load.

The Impact: Why This Matters

You might be thinking, "It's a debugging tool, who cares?" But httpbin instances are frequently deployed in internal developer networks, sometimes even exposed to the public internet for convenience.

If an attacker targets a developer using a self-hosted go-httpbin instance:

  1. Session Hijacking: The attacker sends a phishing link pointing to the internal httpbin. The developer clicks it.
  2. Context Access: The script executes in the context of the internal domain. It can read cookies (if not HttpOnly), local storage, or perform requests to other internal tools on the same origin.
  3. Pivot: This effectively turns a harmless echo server into a beachhead for further attacks against the internal network.

It is a perfect example of how non-production tools can introduce production-level risks.

The Fix: Closing the Loophole

The remediation is straightforward: stop trusting users with the Content-Type header if you are going to reflect their input. The maintainer patched this in version v2.18.0.

To fix this in your environment:

  1. Upgrade: Pull the latest image or update your go.mod to use github.com/mccutchen/go-httpbin/v2 v2.18.0.
  2. Audit: Check if you have the environment variable UNSAFE_ALLOW_DANGEROUS_RESPONSES enabled. If you do, you are re-enabling the vulnerability. Turn it off unless you have a very specific, isolated use case.

For security teams, this serves as a reminder to inventory "dev tools" running in your environment. They often lack the hardening of production apps because everyone assumes "it's just for testing."

Official Patches

mccutchenCommit fixing the issue by escaping dangerous content types

Fix Analysis (1)

Technical Appendix

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

Affected Systems

mccutchen/go-httpbin <= v2.17.1

Affected Versions Detail

ProductAffected VersionsFixed Version
go-httpbin
mccutchen
<= 2.17.12.18.0
AttributeDetail
Attack VectorNetwork (Web)
CVSS5.3 (Medium)
CWECWE-79 (XSS)
Exploit StatusFunctional PoC Available
Componentgo-httpbin
ImpactCode Execution (Browser Context)

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')

Exploit Resources

Known Exploits & Detection

GitHub AdvisoryAdvisory containing PoC for /response-headers and /base64 endpoints

Vulnerability Timeline

Vulnerability Timeline

Patch committed to main branch
2025-03-20
GitHub Advisory Published
2025-03-21
CVE Published
2026-01-02

References & Sources

  • [1]GitHub Advisory GHSA-p4f6-h8jj-vfvf
  • [2]NVD Entry

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.