Go Fiber CVE-2026-42554
MEDIUMSeverity by source
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Lifecycle Timeline
3DescriptionGitHub Advisory
Summary
Description
A Cross-Site Scripting (CWE-79) vulnerability in Go Fiber allows a remote attacker to inject arbitrary HTML/JavaScript by supplying Accept: text/html on any request whose handler passes attacker-influenced data to the AutoFormat() feature. This affects github.com/gofiber/fiber/v3 (DefaultRes.AutoFormat) through version 3.1.0 and github.com/gofiber/fiber/v2 (Ctx.Format) through version 2.52.12.
The developer opts into content negotiation by calling AutoFormat(), but does not opt into raw HTML emission for a particular request; Fiber chooses that branch from attacker-controlled Accept. Five of the six branches of the same method already escape. JSON, XML, MsgPack, and CBOR all route through encoders that neutralize markup; the txt branch emits text/plain and cannot execute. The html branch is the sole outlier in a method whose name (AutoFormat) and symmetrical structure actively telegraph "safe, format-agnostic reply."
Details
The issue resides in res.go within (*DefaultRes).AutoFormat(). The method negotiates against the request Accept header, selects one of html | json | txt | xml | msgpack | cbor, and serializes the caller-supplied body accordingly.
The "html" branch concatenates the stringified body directly into HTML markup with no output encoding:
acceptcomes fromr.c.Accepts(...), i.e. is fully attacker-controlled. An attacker can force the "html" branch on anyAutoFormat()call regardless of which format the developer tested against.bis produced frombodyvia direct assignment (string/[]byte) orfmt.Sprintf("%v", body). Nohtml.EscapeStringis applied.- The resulting string is sent as
text/html; charset=utf-8, so browsers render it as active HTML.
// res.go
func (r *DefaultRes) AutoFormat(body any) error {
accept := r.c.DefaultReq.Accepts("html", "json", "txt", "xml", "msgpack", "cbor")
r.Type(accept)
var b string
switch val := body.(type) {
case string:
b = val
case []byte:
b = r.c.app.toString(val)
default:
b = fmt.Sprintf("%v", val)
}
switch accept {
case "txt":
return r.SendString(b)
case "json":
return r.JSON(body)
case "xml":
return r.XML(body)
case "html":
return r.SendString("<p>" + b + "</p>")
case "msgpack":
return r.MsgPack(body)
case "cbor":
return r.CBOR(body)
}
return r.SendString(b)
}Impact
This impacts all current v3 releases ≤ 3.1.0 containing DefaultRes.AutoFormat, and all current v2 releases ≤ 2.52.12 where the identical "<p>" + b + "</p>" construction exists in (*Ctx).Format(). Exploitation requires that an application call c.AutoFormat(v) where v (or a field stringified by %v) contains request-influenced data.
A handler that uses AutoFormat() to serve multiple representations of the same data can be turned into an HTML XSS sink when the client sends Accept: text/html, even if the developer only tested the JSON path.
This may result in:
- Reflected XSS in the application's origin via any request-derived value reaching
AutoFormat. - Stored XSS where the reflected value originates from persisted input later passed to
AutoFormat.
Proposed Patch
The injection surface is r.Type("html") followed by r.SendString(b) with unescaped caller data, where it constructs markup on the caller's behalf around a value whose HTML-ness the caller did not declare. A few options:
AutoFormat()should treatbodyas data, not markup, in the"html"branch and escape it before concatenating it into the framework-generated<p>wrapper. Callers that need raw negotiated HTML should useFormat()with an explicit HTML handler.- Introduce a sibling method that escapes, leave
AutoFormatalone for backward compatibility.
HTML-escape the value in the "html" branch before concatenating it into the <p> wrapper.
import "html"
// ...
case "html":
return r.SendString("<p>" + html.EscapeString(b) + "</p>")html.EscapeString escapes <, >, &, ', ", which is sufficient for an element-text context. Apply the same change to v2's (*Ctx).Format().
Proof of Concept
# Create project directory
mkdir fiber-xss-poc && cd fiber-xss-poc
# Initialize Go module
go mod init fiber-xss-poc
# Install Fiber v3
go get github.com/gofiber/fiber/v3
# Create the PoC file
cat > main.go << 'EOF'
package main
import (
"github.com/gofiber/fiber/v3"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
func main() {
app := fiber.New()
app.Get("/api/user", func(c fiber.Ctx) error {
user := User{
ID: 1,
Name: c.Query("name", "anonymous"),
}
return c.AutoFormat(user)
})
app.Listen(":3000")
}
EOF
# Run it
go run main.go
}Benign JSON
curl -s 'http://127.0.0.1:3000/api/user?name=Alice' -H 'Accept: application/json'
{"id":1,"name":"Alice"}HTML sink enables XSS
curl -s 'http://127.0.0.1:3000/api/user?name=<script>alert(document.domain)</script>' -H 'Accept: text/html'
<p>{1 <script>alert(document.domain)</script>}</p>AnalysisAI
Reflected cross-site scripting in Go Fiber's AutoFormat() method allows remote attackers to inject arbitrary HTML and JavaScript by sending Accept: text/html headers with attacker-controlled data passed to AutoFormat(). The vulnerability affects Fiber v3 through 3.1.0 and v2 through 2.52.12, where the HTML output branch concatenates user data directly into markup without escaping, while all other format branches (JSON, XML, MsgPack, CBOR) properly sanitize output. A proof-of-concept demonstrates script injection via query parameters when HTML content negotiation is selected by an attacker.
Technical ContextAI
Go Fiber is a web framework that provides content negotiation via the AutoFormat() method, which inspects the Accept header and serializes response data in one of six formats: HTML, JSON, TXT, XML, MsgPack, or CBOR. The vulnerability exists in the HTML branch of the format selector, which constructs an HTML paragraph element by concatenating the stringified body parameter directly: <p> + b + </p>. The Accept header is fully attacker-controlled via the Accepts() method, and the body parameter is derived from caller-supplied data via string assignment or fmt.Sprintf("%v", body), which does not apply HTML encoding. The method is used for transparent content negotiation where developers do not explicitly declare that their handler supports raw HTML markup generation. Other branches route through proper encoders (JSON, XML, MsgPack, CBOR) or emit text/plain (TXT), which cannot execute scripts. The root cause is CWE-79 (Improper Neutralization of Input During Web Page Generation).
RemediationAI
Upgrade Go Fiber immediately to v3.2.0 or later for v3 users, and v2.52.13 or later for v2 users. These patch versions apply html.EscapeString() to the body parameter before concatenating it into the HTML paragraph wrapper, neutralizing special characters (<, >, &, ', ") and preventing script injection. Update your go.mod file and run go get -u github.com/gofiber/fiber/v3@v3.2.0 (or equivalent for v2) to apply the fix. If immediate patching is not feasible, implement a temporary workaround by auditing all AutoFormat() calls in your application and replacing them with explicit format handlers that do not use AutoFormat, or by ensuring that user-influenced data is not passed to AutoFormat. Additionally, implement a Content-Security-Policy (CSP) header with script-src 'self' to provide defense-in-depth, though this does not address the root cause. Refer to the GitHub advisory at https://github.com/gofiber/fiber/security/advisories/GHSA-qjv7-627w-8qjv for official remediation details and to confirm patch versions before deployment.
Same weakness CWE-79 – Cross-site Scripting (XSS)
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-qjv7-627w-8qjv