CVEReports
CVEReports

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

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-528Q-4PGM-WVG2

CVE-2025-45286: Reflected Cross-Site Scripting via Arbitrary Content-Type Manipulation in go-httpbin

Amit Schendel
Amit Schendel
Senior Security Researcher

Oct 30, 2026·10 min read·77 visits

Executive Summary (TL;DR)

Versions of go-httpbin prior to v2.18.0 allow unauthenticated callers to set arbitrary Content-Type response headers while reflecting unescaped user input in the response body on the /response-headers and /base64 endpoints, resulting in reflected Cross-Site Scripting (CWE-80).

CVE-2025-45286 is a reflected Cross-Site Scripting (XSS) vulnerability in mccutchen/go-httpbin, a Go implementation of the HTTP request and response inspection service httpbin. In versions prior to v2.18.0, the application allows unauthenticated clients to arbitrarily control the HTTP Content-Type response header via query parameters on the /response-headers, /base64/{payload}, and /base64/decode/{payload} endpoints. Because user-controlled input is reflected in the HTTP response body without HTML entity encoding, specifying an executable media type such as text/html causes client browsers to parse and execute embedded HTML and JavaScript payloads within the security context of the go-httpbin origin.

Vulnerability Overview

The mccutchen/go-httpbin library and standalone service is a Go port of Kenneth Reitz's httpbin utility. Software developers and automated testing pipelines deploy it as a microservice or embedded HTTP handler to inspect client requests and simulate server behaviors, including custom status codes, response delays, redirects, and header reflections. Because the service is designed to echo client-supplied parameters directly back to the caller, its endpoints expose a broad attack surface if deployed on a shared domain or accessed directly via a web browser.

CVE-2025-45286 (also tracked as GHSA-528q-4pgm-wvg2 and GO-2025-3554) is a reflected Cross-Site Scripting (XSS) vulnerability classified under CWE-80 (Improper Neutralization of Script-Related HTML Tags in a Web Page), a child weakness of CWE-79. The flaw affects all releases of go-httpbin prior to version v2.18.0. It occurs across three distinct routing endpoints: /response-headers, /base64/{payload}, and /base64/decode/{payload}.

Each of these affected endpoints performs two operations: it reflects user-supplied data into the HTTP response body, and it allows the caller to specify the outgoing Content-Type header via a URL query parameter. When an attacker sets the Content-Type header to an executable document type—such as text/html, application/xhtml+xml, or image/svg+xml—and injects HTML markup into the reflected parameters, a victim's web browser interprets the response body as an active HTML document. Any JavaScript included in the payload executes within the origin context of the go-httpbin instance.

Root Cause Analysis

The root cause of CVE-2025-45286 is the combination of unrestricted HTTP response header manipulation and the absence of context-aware output encoding when generating HTTP response bodies. In web applications, returning raw or JSON-serialized user input is safe from XSS only if the browser is instructed to treat the payload as inert data (for example, via Content-Type: text/plain or Content-Type: application/json accompanied by X-Content-Type-Options: nosniff). When the client can override the Content-Type header, the trust boundary protecting the response body format breaks down.

In the /response-headers endpoint, the ResponseHeaders handler iterates over all URL query parameters (r.URL.Query()) and appends each key-value pair directly to the HTTP response headers using w.Header().Add(k, v). If the query string does not explicitly include a Content-Type parameter, the handler defaults to application/json. The handler then serializes the entire query parameter map into the response body using Go's encoding/json package via the internal helper mustMarshalJSON(w, args). If an attacker supplies Content-Type=text/html alongside another parameter containing HTML tags, the response is served with a text/html MIME type, causing the browser to scan the JSON output and render any embedded HTML tags.

A similar architectural flaw exists in the Base64 handler, which backs both the /base64/{payload} and /base64/decode/{payload} routes. This handler extracts a base64-encoded string from the URL path, decodes it into raw bytes, and writes those bytes directly to the HTTP response stream. To support flexible testing, the handler checks for a content-type query parameter (r.URL.Query().Get("content-type")), defaulting to text/plain only when the parameter is omitted.

Because the Base64 handler performs no validation on the requested content-type and writes the decoded byte slice verbatim via writeResponse(w, http.StatusOK, ct, result), an attacker can encode an arbitrary HTML document or script tag into base64 and append ?content-type=text/html to the URL. Upon receiving the response, the browser parses the decoded bytes as standard HTML markup and executes the script.

Code Analysis

Prior to version v2.18.0, the vulnerable handlers in httpbin/handlers.go trusted the client-supplied Content-Type without inspecting its media type or escaping the corresponding response body. Below is the vulnerable implementation of ResponseHeaders and Base64:

// Vulnerable implementation in httpbin/handlers.go (prior to v2.18.0)
func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) {
    args := r.URL.Query()
    for k, vs := range args {
        for _, v := range vs {
            // Attacker can inject Content-Type: text/html here
            w.Header().Add(k, v)
        }
    }
    if contentType := w.Header().Get("Content-Type"); contentType == "" {
        w.Header().Set("Content-Type", jsonContentType)
    }
    // args are marshaled without HTML escaping; unsafe if Content-Type is text/html
    mustMarshalJSON(w, args)
}
 
func (h *HTTPBin) Base64(w http.ResponseWriter, r *http.Request) {
    // ... [base64 decoding logic into 'result' byte slice] ...
    ct := r.URL.Query().Get("content-type")
    if ct == "" {
        ct = textContentType
    }
    // Raw decoded bytes written directly with user-controlled Content-Type
    writeResponse(w, http.StatusOK, ct, result)
}

In commit 0decfd1a2e88d85ca6bfb8a92421653f647cbc04, the maintainer addressed the vulnerability by introducing a strict allowlist of non-executable media types in httpbin/helpers.go and a conditional escaping mechanism in httpbin/httpbin.go:

// Patched helper in httpbin/helpers.go
var safeContentTypes = map[string]bool{
    "text/plain":               true,
    "application/json":         true,
    "application/octet-string": true,
}
 
func isDangerousContentType(ct string) bool {
    mediatype, _, err := mime.ParseMediaType(ct)
    if err != nil {
        // Treat unparseable or malformed MIME types as dangerous by default
        return true
    }
    return !safeContentTypes[mediatype]
}
 
// Method added in httpbin/httpbin.go
func (h *HTTPBin) mustEscapeResponse(contentType string) bool {
    if h.unsafeAllowDangerousResponses {
        return false
    }
    return isDangerousContentType(contentType)
}

With mustEscapeResponse in place, the handlers in httpbin/handlers.go were updated to apply html.EscapeString to all reflected data whenever a non-allowlisted Content-Type is requested:

// Patched implementation in httpbin/handlers.go (v2.18.0)
func (h *HTTPBin) ResponseHeaders(w http.ResponseWriter, r *http.Request) {
    args := r.URL.Query()
    contentType := args.Get("Content-Type")
 
    for k, vs := range args {
        for _, v := range vs {
            w.Header().Add(k, v)
        }
    }
    if contentType == "" {
        w.Header().Set("Content-Type", jsonContentType)
    }
 
    // Escape keys and values if the Content-Type is not on the safe allowlist
    if h.mustEscapeResponse(contentType) {
        tmp := make(url.Values, len(args))
        for k, vs := range args {
            for _, v := range vs {
                tmp.Add(html.EscapeString(k), html.EscapeString(v))
            }
        }
        args = tmp
    }
 
    mustMarshalJSON(w, args)
}
 
func (h *HTTPBin) Base64(w http.ResponseWriter, r *http.Request) {
    // ... [base64 decoding logic] ...
    if ct == "" {
        ct = textContentType
    }
    // HTML-escape the raw decoded bytes if Content-Type is dangerous
    if h.mustEscapeResponse(ct) {
        result = []byte(html.EscapeString(string(result)))
    }
    writeResponse(w, http.StatusOK, ct, result)
}

> [!NOTE] > Fix Completeness Assessment: In ResponseHeaders, the patched code extracts contentType := args.Get("Content-Type"), which performs a case-sensitive map lookup on url.Values. However, w.Header().Add(k, v) canonicalizes header names using textproto.CanonicalMIMEHeaderKey. If a user passes a lowercase parameter ?content-type=text/html, args.Get("Content-Type") returns an empty string "". Fortunately, this does not create a bypass: when contentType == "", the subsequent check w.Header().Set("Content-Type", jsonContentType) overwrites the lowercase header with application/json, neutralizing the HTML rendering context. Additionally, mime.ParseMediaType properly strips parameters (such as ; charset=utf-8) and converts the media type to lowercase before checking safeContentTypes, preventing parameter-based allowlist bypasses.

Exploitation

Exploiting CVE-2025-45286 requires no authentication or specialized configuration; the default setup of go-httpbin prior to v2.18.0 is vulnerable out of the box. Because this is a reflected XSS vulnerability, successful exploitation requires user interaction (UI:R), meaning an attacker must entice a victim into navigating to a crafted URL in a web browser.

Vector 1: /response-headers Endpoint

To exploit the /response-headers endpoint, the attacker constructs a URL containing Content-Type=text/html alongside an arbitrary query parameter holding the HTML/JavaScript payload:

GET /response-headers?Content-Type=text/html&xss=%3Cimg/src/onerror=alert(%27xss%27)%3E HTTP/1.1
Host: vulnerable-httpbin.example.com

The vulnerable server responds with an HTTP 200 status, sets the Content-Type header to text/html, and outputs the JSON representation of the query parameters:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 69
 
{"Content-Type":["text/html"],"xss":["<img/src/onerror=alert('xss')>"]}

When the victim's browser receives this response, it parses the body as an HTML document, encounters the <img> tag, fails to load the invalid src attribute, and immediately executes the onerror JavaScript handler.

Vector 2: /base64/{payload} and /base64/decode/{payload} Endpoints

To exploit the base64 decoding endpoints, the attacker first base64-encodes the desired HTML payload. For example, <img/src/onerror=alert('xss')> encodes to PGltZy9zcmMvb25lcnJvcj1hbGVydCgneHNzJyk+. The attacker then places this encoded string into the URL path and appends ?content-type=text/html:

GET /base64/PGltZy9zcmMvb25lcnJvcj1hbGVydCgneHNzJyk+?content-type=text/html HTTP/1.1
Host: vulnerable-httpbin.example.com

The identical payload also functions against /base64/decode/PGltZy9zcmMvb25lcnJvcj1hbGVydCgneHNzJyk+?content-type=text/html. The server decodes the path segment and returns the exact HTML string with a text/html header:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 30
 
<img/src/onerror=alert('xss')>

Impact Assessment

CVE-2025-45286 carries a CVSS v3.1 base score of 6.1 (Medium) with the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N, and a CVSS v4.0 score of 5.1 (Medium). The Scope is marked as Changed (S:C) because although the vulnerable component is the go-httpbin web server, the security impact manifests within the client's web browser environment.

For standalone go-httpbin deployments running on dedicated, isolated origins without authentication state, the practical impact of XSS is limited to client-side phishing, content spoofing, or browser-based request forgery against internal network resources accessible from the victim's machine. Because go-httpbin does not natively manage user accounts or sensitive databases, an attacker cannot extract application-specific credentials from a standalone instance.

However, the severity increases substantially when go-httpbin is deployed under a shared corporate domain (for example, mounted at a subpath like https://api.example.com/httpbin/ or hosted on a subdomain where parent domain cookies are scoped with Domain=.example.com). In such architectures, arbitrary JavaScript execution allows an attacker to read non-HttpOnly session cookies (T1539), extract Cross-Site Request Forgery (CSRF) tokens, access localStorage or sessionStorage data, and issue authenticated asynchronous HTTP requests (fetch or XMLHttpRequest) to other services sharing the same origin.

From a threat intelligence perspective, the Exploit Prediction Scoring System (EPSS) assigns CVE-2025-45286 a score of 0.00267 (0.27%, 18.89th percentile), indicating a low likelihood of widespread automated exploitation. The vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog, though CISA's Vulnrichment SSVC assessment notes that proof-of-concept payloads are publicly documented (poc).

Remediation

The primary remediation for CVE-2025-45286 is to upgrade mccutchen/go-httpbin to version v2.18.0 or later. Projects embedding go-httpbin as a Go module library should update their go.mod dependency and rebuild the binary:

go get -u github.com/mccutchen/go-httpbin/v2@v2.18.0
go mod tidy

Version v2.18.0 introduces an opt-in backwards-compatibility setting for environments that explicitly depend on unescaped responses for non-browser testing. Operators must verify that the CLI flag -unsafe-allow-dangerous-responses, the environment variable UNSAFE_ALLOW_DANGEROUS_RESPONSES=true, and the functional option httpbin.WithUnsafeAllowDangerousResponses() are disabled in any deployment reachable by web browsers.

If an immediate software upgrade is not feasible, administrators can mitigate the vulnerability at the reverse proxy or Web Application Firewall (WAF) layer. For NGINX deployments fronting go-httpbin, configure the proxy to strip client-controlled Content-Type headers on the vulnerable routes and enforce X-Content-Type-Options: nosniff:

location /response-headers {
    proxy_pass http://go-httpbin-backend;
    proxy_hide_header Content-Type;
    add_header Content-Type "application/json; charset=utf-8" always;
    add_header X-Content-Type-Options "nosniff" always;
}
 
location ~ ^/base64/ {
    proxy_pass http://go-httpbin-backend;
    proxy_hide_header Content-Type;
    add_header Content-Type "text/plain; charset=utf-8" always;
    add_header X-Content-Type-Options "nosniff" always;
}

Additionally, deploys of go-httpbin should always be isolated on a dedicated, sandboxed domain (for example, httpbin-sandbox.example.net) rather than hosted on a subpath or subdomain of a primary production domain, preventing any potential cross-origin credential or cookie exposure.

Official Patches

mccutchenGit commit fixing CVE-2025-45286 by escaping responses with non-allowlisted Content-Type headers
mccutchengo-httpbin v2.18.0 release containing the security patch
GitHubOfficial GitHub Security Advisory GHSA-528q-4pgm-wvg2

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
EPSS Probability
0.27%
Top 81% most exploited

Affected Systems

github.com/mccutchen/go-httpbingithub.com/mccutchen/go-httpbin/v2go-httpbin standalone server

Affected Versions Detail

Product
Affected Versions
Fixed Version
go-httpbin
mccutchen
< 2.18.02.18.0
AttributeDetail
Vulnerability TypeReflected Cross-Site Scripting (CWE-80 / CWE-79)
Attack VectorNetwork (Crafted URL via HTTP GET)
CVSS v3.1 Score6.1 Medium (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
EPSS Score0.27% (18.89th Percentile)
Affected Endpoints/response-headers, /base64/{payload}, /base64/decode/{payload}
Exploit StatusPublic Proof-of-Concept (PoC)
CISA KEV StatusNot Listed
Patched Versiongo-httpbin v2.18.0

MITRE ATT&CK Mapping

T1189Drive-by Compromise
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
T1539Steal Web Session Cookie
Credential Access
T1185Browser Session Hijacking
Collection
CWE-80
Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)

The application receives input from an upstream component, but does not neutralize or incorrectly neutralizes script-related HTML tags such as <script>, <img>, or <iframe> before reflecting them back into web content presented to a user.

Known Exploits & Detection

GitHub Security AdvisoryOfficial advisory containing proof-of-concept URLs for /response-headers, /base64/{payload}, and /base64/decode/{payload}.

Vulnerability Timeline

Vulnerability patched in mccutchen/go-httpbin via commit 0decfd1a2e88d85ca6bfb8a92421653f647cbc04
2025-03-20
GitHub Security Advisory GHSA-528q-4pgm-wvg2 published and go-httpbin v2.18.0 released
2025-03-21
CVE-2025-45286 reserved by MITRE
2025-04-22
CVE-2025-45286 officially published to CVE.org and NVD
2026-01-02
CISA ADP Vulnrichment assigned CWE-80 and published SSVC evaluation
2026-01-06
NVD completed official analysis and CVSS v3.1 scoring
2026-06-17

References & Sources

  • [1]GitHub Security Advisory GHSA-528q-4pgm-wvg2
  • [2]GitHub Advisory Database Entry GHSA-528q-4pgm-wvg2
  • [3]Fix Commit 0decfd1a2e88d85ca6bfb8a92421653f647cbc04
  • [4]go-httpbin Release v2.18.0
  • [5]mccutchen/go-httpbin Repository
  • [6]National Vulnerability Database (NVD) - CVE-2025-45286
  • [7]CVE.org Record - CVE-2025-45286
  • [8]CVE List V5 JSON Record - CVE-2025-45286
  • [9]Shodan CVEDB - CVE-2025-45286
  • [10]Wiz Vulnerability Database - CVE-2025-45286
  • [11]Red Hat Customer Portal - CVE-2025-45286
Related Vulnerabilities
CVE-2025-45286

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.

More Reports

•36 minutes ago•CVE-2026-118763
7.4

CVE-2026-118763: Cross-Origin Credential Exposure in @sigstore/oci

A credential exposure vulnerability exists in the @sigstore/oci library prior to version 0.7.2. The RegistryClient implementation stores sensitive authentication headers, including Bearer tokens, Basic authentication credentials, and custom Docker configuration headers, as client-wide defaults on its shared HTTP client instance. When uploading binary blobs via the OCI distribution specification, the client extracts the target upload URI from the server-supplied Location header and dispatches an independent HTTP PUT request. If a compromised or untrusted registry returns a cross-origin URI in the Location header, the client transmits the stored authentication credentials directly to the third-party host.

Alon Barad
Alon Barad
3 views•10 min read
•about 4 hours ago•CVE-2026-119282
7.3

CVE-2026-119282: OS Command Injection via Plugin Options in Nx (@nx/maven and @nx/gradle)

An OS command injection and argument injection vulnerability exists in the Nx build system and its official Maven (@nx/maven) and Gradle (@nx/gradle) plugins. When constructing the project dependency graph, the plugins invoke underlying Java build wrappers via subshells while interpolating unsanitized plugin options directly from nx.json into the command arguments. An attacker who supplies a crafted nx.json file via a repository or pull request can execute arbitrary shell commands with the privileges of the user or CI/CD runner invoking any Nx command that computes the project graph.

Amit Schendel
Amit Schendel
6 views•10 min read
•about 5 hours ago•CVE-2026-59978
7.5

CVE-2026-59978: Persistent Denial of Service via Array Injection in AdminNeo

AdminNeo versions 4.6.2 through 5.4.1 contain an improper input validation vulnerability (CWE-20) in the version verification endpoint (?script=version). An unauthenticated remote attacker can submit a crafted HTTP POST request containing an array parameter for 'version', which is serialized into a shared server-side temporary cache file without type checking or authentication. On subsequent requests, the application deserializes this cached array and passes it to cookie() and rawurlencode(), triggering an uncaught fatal TypeError in PHP 8.x environments and causing a persistent 24-hour Denial of Service (DoS) for all users.

Amit Schendel
Amit Schendel
6 views•8 min read
•about 6 hours ago•GHSA-FGXM-5HVV-X4VH
5.3

GHSA-fgxm-5hvv-x4vh: Private Repository Enumeration via Go Module Discovery and HTTP Response Discrepancies in Soft Serve

Charmbracelet Soft Serve versions 0.5.0 through 0.12.2 contain an authorization bypass and observable response discrepancy vulnerability in the HTTP Git server. Remote attackers can determine the existence, exact names, and clone URLs of private repositories by issuing crafted Go remote import path discovery requests (?go-get=1) or by observing differential HTTP status codes across Git Smart HTTP, Dumb HTTP, and Git LFS endpoints.

Alon Barad
Alon Barad
7 views•12 min read
•about 7 hours ago•GHSA-F3FJ-9625-RV3M
5.9

GHSA-f3fj-9625-rv3m: Race Condition in Soft Serve Repository Cache Invalidation

A Time-of-Check to Time-of-Use (TOCTOU) race condition in Charmbracelet Soft Serve versions 0.6.0 through 0.12.2 allows unauthenticated users to retain read access to repositories after their visibility is changed from public to private. The flaw stems from premature cache invalidation in the SetPrivate method prior to committing the visibility update to the underlying database. Concurrent read requests arriving during the database transaction window repopulate the non-expiring in-memory LRU cache with stale public metadata, bypassing access controls across HTTP, SSH, and Git protocols until the server process is restarted.

Alon Barad
Alon Barad
5 views•10 min read
•about 8 hours ago•CVE-2026-119283
7.5

CVE-2026-119283: Unbounded JWE Recipients Array Causes CPU Exhaustion in Authlib joserfc

A resource consumption vulnerability exists in the Authlib joserfc Python library prior to version 1.7.5. When processing JSON Web Encryption (JWE) objects formatted using General JSON Serialization, the library fails to enforce an upper bound on the number of elements within the recipients array. An unauthenticated attacker can supply a JWE containing thousands of recipient entries targeting an RSA key management algorithm, forcing the server to perform an equivalent number of computationally expensive RSA private-key decryption operations per request and exhausting available CPU resources.

Alon Barad
Alon Barad
5 views•9 min read