Xss Cross Site Scripting in Cockroachdb
How XSS Cross-Site Scripting Manifests in CockroachDB
XSS vulnerabilities in CockroachDB applications typically arise when user-supplied data is stored in the database and later rendered in web interfaces without proper sanitization. In CockroachDB's context, this often occurs through SQL injection combined with XSS payloads, or when application logic fails to escape HTML content before storing it in database columns.
A common CockroachDB-specific scenario involves stored XSS attacks where malicious scripts are inserted into text columns. For example, consider a web application that allows users to store comments or profile information in a CockroachDB table:
CREATE TABLE user_comments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
comment_text STRING,
created_at TIMESTAMP DEFAULT now()
);
INSERT INTO user_comments (user_id, comment_text)
VALUES ('00000000-0000-0000-0000-000000000001',
'<script>alert("XSS!");</script>');When this data is later retrieved and displayed without escaping, the script executes in other users' browsers. CockroachDB itself doesn't sanitize data - it stores whatever the application sends, making the application layer responsible for XSS prevention.
Another CockroachDB-specific pattern involves JSONB columns where attackers can embed XSS payloads. Consider this schema:
CREATE TABLE user_profiles (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
profile_data JSONB
);
INSERT INTO user_profiles (profile_data)
VALUES ('{"bio": "<img src=x onerror=alert(1)>"}');The JSONB storage doesn't provide any XSS protection - the application must handle sanitization before storing or escaping before rendering.
Stored XSS in CockroachDB becomes particularly dangerous when combined with SQL injection vulnerabilities. An attacker might use SQL injection to insert malicious scripts, then rely on the application to display them to other users. This creates a two-stage attack: database compromise followed by client-side exploitation.
CockroachDB-Specific Detection
Detecting XSS vulnerabilities in CockroachDB applications requires examining both the database schema and the application's data handling patterns. Start by scanning your CockroachDB tables for columns that might store user-generated content:
-- Find text-based columns that could store XSS payloads
SELECT table_name, column_name, data_type
FROM information_schema.columns
WHERE table_schema = 'public'
AND data_type IN ('STRING', 'VARCHAR', 'CHAR', 'JSONB', 'BYTES');This query identifies columns where XSS payloads could be stored. Pay special attention to columns with names like 'content', 'description', 'bio', 'comment', or similar text fields.
For active detection, use middleBrick's API security scanner to test your CockroachDB-backed endpoints. The scanner automatically tests for XSS by injecting payloads and checking if they're reflected in responses. middleBrick's 12 security checks include XSS testing across all scanned endpoints, even those backed by CockroachDB.
middleBrick specifically tests for:
- Reflected XSS in API responses
- Stored XSS by checking if payloads persist in database-backed responses
- DOM-based XSS patterns in client-side rendered content
- SQL injection combined with XSS payloads
The scanner provides severity ratings and remediation guidance specific to your application's architecture. For CockroachDB applications, middleBrick can identify if XSS payloads are successfully stored and retrieved from the database.
Manual testing should include attempting to store XSS payloads in your CockroachDB tables through application interfaces, then verifying if they're properly escaped when displayed. Test various payload types including script tags, event handlers, and data URLs.
CockroachDB-Specific Remediation
Remediating XSS in CockroachDB applications requires a defense-in-depth approach. The primary strategy is to sanitize data before it enters the database, but also to escape content when rendering it in applications.
For Go applications using CockroachDB, use the html/template package which automatically escapes HTML content:
package main
import (
"database/sql"
"html/template"
"net/http"
"github.com/cockroachdb/cockroach-go/v2/crdb"
)
type Comment struct {
ID string
UserID string
Comment string
CreatedAt string
}
func getComment(db *sql.DB, id string) (*Comment, error) {
var c Comment
err := crdb.ExecuteTx(db, func(tx *sql.Tx) error {
return tx.QueryRow(
"SELECT id, user_id, comment_text, created_at FROM user_comments WHERE id = $1",
id,
).Scan(&c.ID, &c.UserID, &c.Comment, &c.CreatedAt)
})
return &c, err
}
func commentHandler(w http.ResponseWriter, r *http.Request) {
commentID := r.URL.Query().Get("id")
comment, err := getComment(db, commentID)
if err != nil {
http.Error(w, "Comment not found", 404)
return
}
// Use html/template which auto-escapes content
tmpl := template.Must(template.New("comment").Parse(`
<div class="comment">
<p>{{.Comment}}</p>
<small>Posted {{.CreatedAt}}</small>
</div>
`))
tmpl.Execute(w, comment)
}For applications using CockroachDB with JavaScript/Node.js, implement input sanitization before database insertion:
const { Client } = require('@cockroachdb/pg@libpq');
const DOMPurify = require('dompurify');
async function createComment(db, userId, commentText) {
// Sanitize input before storing
const sanitizedComment = DOMPurify.sanitize(commentText, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href']
});
const client = new Client();
await client.connect();
try {
await client.query(
'INSERT INTO user_comments (user_id, comment_text) VALUES ($1, $2)',
[userId, sanitizedComment]
);
} finally {
await client.end();
}
}For Python applications using CockroachDB's psycopg2 driver:
import psycopg2
from django.utils.html import escape
class Comment:
def __init__(self, db_conn):
self.conn = db_conn
def create_comment(self, user_id, comment_text):
# Escape HTML before storing
escaped_comment = escape(comment_text)
with self.conn.cursor() as cur:
cur.execute(
"INSERT INTO user_comments (user_id, comment_text) VALUES (%s, %s) RETURNING id",
(user_id, escaped_comment)
)
return cur.fetchone()[0]Consider implementing database-level constraints for critical applications:
-- Add a check constraint to prevent script tags
ALTER TABLE user_comments
ADD CONSTRAINT no_script_tags
CHECK (comment_text NOT LIKE '%<script%>' AND comment_text NOT LIKE '%</script>%');While this won't catch all XSS vectors, it provides an additional layer of protection. For JSONB columns, validate the structure before insertion:
CREATE OR REPLACE FUNCTION validate_profile_data(data JSONB)
RETURNS BOOLEAN AS $$
BEGIN
-- Check for script tags in any string field
IF data ? 'bio' THEN
IF position('<script' in data->>'bio') > 0 THEN
RETURN FALSE;
END IF;
END IF;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;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 |