Xss Cross Site Scripting in Fiber with Cockroachdb
Xss Cross Site Scripting in Fiber with Cockroachdb — how this specific combination creates or exposes the vulnerability
Cross-site scripting (XSS) in a Fiber application using CockroachDB typically occurs when untrusted data from the database is reflected into HTML responses without proper escaping. Because CockroachDB is a PostgreSQL-compatible database, query results are often returned as strings or JSON; if these values are injected into HTML templates or JSON responses without sanitization, an attacker can supply malicious script that executes in the victim’s browser.
Consider a user profile endpoint that fetches display_name from CockroachDB and embeds it directly into an HTML page in Fiber:
// vulnerable pattern
app.Get("/profile/:username", func(c *fiber.Ctx) error {
var displayName string
err := db.QueryRow("SELECT display_name FROM users WHERE username = $1", c.Params("username")).Scan(&displayName)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
// unsanitized reflection into HTML
return c.SendString("<div>Hello " + displayName + "</div>")
})
If the display_name column contains <script>stealCookies()</script>, the response will execute that script for any viewer of the profile page. CockroachDB does not perform output encoding; it stores and returns the raw value, so the responsibility falls to the application layer. Additionally, if the application uses user-controlled input to construct dynamic SQL (e.g., string concatenation) and then reflects query results, the risk of injection and subsequent XSS increases, especially when combined with insufficient input validation.
The same issue can arise when serving JSON APIs that include user-generated content:
// JSON response with potential XSS via innerHTML-like usage in frontend
app.Get("/comments/:postID", func(c *fiber.Ctx) error {
rows, err := db.Query("SELECT comment_text FROM comments WHERE post_id = $1", c.Params("postID"))
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
defer rows.Close()
var comments []string
for rows.Next() {
var text string
if err := rows.Scan(&text); err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
comments = append(comments, text)
}
return c.JSON(fiber.Map{"comments": comments})
})
If the frontend inserts these comments using innerHTML, any <img src=x onerror=alert(1)> stored in CockroachDB will execute. XSS in this context is not a CockroachDB flaw but a consequence of reflecting untrusted data; however, CockroachDB’s role is to store and serve the data as-is, making it critical to treat all retrieved values as untrusted.
XSS also intersects with broader API security checks that middleBrick performs, such as Input Validation and Data Exposure. An unauthenticated scan can detect reflected script patterns in responses and highlight missing output encoding as a finding, emphasizing the need for context-aware escaping regardless of the database backend.
Cockroachdb-Specific Remediation in Fiber — concrete code fixes
Remediation focuses on context-aware output encoding and strict input handling. For HTML body content, use Go’s html/template package which automatically escapes dynamic values:
import "html/template"
// safe pattern with html/template
type ProfileData struct {
Username string
DisplayName template.HTML // only use template.HTML if you intentionally allow safe HTML
}
app.Get("/profile/:username", func(c *fiber.Ctx) error {
var data ProfileData
err := db.QueryRow("SELECT username, display_name FROM users WHERE username = $1", c.Params("username")).Scan(&data.Username, &data.DisplayName)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
tmpl := `<div>Hello {{.DisplayName}}</div>`
t, err := template.New("profile").Parse(tmpl)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return t.Execute(c.BodyWriter(), data)
})
If you must embed limited safe HTML, use template.HTMLEscapeString or a dedicated sanitizer, but avoid template.HTML unless absolutely necessary.
For JSON APIs, ensure that the frontend treats responses as text when inserting into DOM, or use structured escaping on the client. Additionally, enforce strict input validation on query parameters used in SQL to reduce injection surface:
import "github.com/asaskevich/govalidator"
app.Get("/comments/:postID", func(c *fiber.Ctx) error {
postID := c.Params("postID")
if !govalidator.IsInt(postID) {
return c.Status(fiber.StatusBadRequest).SendString("invalid post id")
}
rows, err := db.Query("SELECT comment_text FROM comments WHERE post_id = $1", postID)
if err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
defer rows.Close()
var safeComments []string
for rows.Next() {
var text string
if err := rows.Scan(&text); err != nil {
return c.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
// encode for HTML context if ever reflected back as HTML
safeComments = append(safeComments, template.HTMLEscapeString(text))
}
return c.JSON(fiber.Map{"comments": safeComments})
})
These fixes ensure that data from CockroachDB is handled defensively, aligning with the principle that databases store content, but applications must control how that content is presented to users and their browsers.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |