Xss Cross Site Scripting in Adonisjs with Cockroachdb
Xss Cross Site Scripting in Adonisjs with Cockroachdb — how this specific combination creates or exposes the vulnerability
Cross-site scripting (XSS) in an AdonisJS application using CockroachDB typically arises when untrusted data supplied by the client is rendered in HTML responses without proper escaping. CockroachDB, being a PostgreSQL-compatible distributed database, stores the data as provided; it does not introduce or remove HTML characters. Therefore, the risk is not in CockroachDB itself but in how AdonisJS retrieves and presents that data.
For example, if an AdonisJS route reads a user profile from CockroachDB and injects the stored bio directly into an EJS template without escaping, any HTML or script previously saved by an attacker could execute in other users’ browsers. A stored XSS payload might look like <script>stealCookies()</script>, persisted in a profiles table column and later rendered by an escape()-omitted template. Even when using the Fetch API or an ORM like Lucid to query CockroachDB, the framework does not automatically sanitize output; developers must apply context-aware escaping in templates or via libraries.
AdonisJS encourages the use of template-level escaping, yet misconfigurations or manual HTML assembly (e.g., string concatenation for emails or API responses) can bypass these safeguards. An attacker might first exploit a reflected XSS in a search endpoint that builds SQL-like fragments in JavaScript on the client, then trick a victim into visiting a crafted link. If the application also writes user-controlled strings into HTTP headers, there is potential for header injection that aids the chain. CockroachDB’s role is limited to persistence; the vulnerability is triggered when the application dynamically inserts unchecked data into the response stream.
Consider a route that fetches a comment by ID and renders it with raw output:
const comment = await Comment.query().where('id', request.param('id')).first()
return response.send(comment.body)
If comment.body contains <img src=x onerror=alert(1)>, the response delivers executable script to the browser. The fix is not database-specific but involves output encoding appropriate to the context (HTML, attribute, JavaScript, or URL), and leveraging AdonisJS view helpers or sanitization libraries before sending content to the client.
Cockroachdb-Specific Remediation in Adonisjs — concrete code fixes
Remediation centers on ensuring data is escaped for the output context and validating inputs before they reach CockroachDB. Below are concrete patterns for AdonisJS with CockroachDB using Lucid ORM and native queries.
- Use template escaping: In AdonisJS Edge templates, always rely on built-in escaping. Do not disable it with
@unsafe()unless you have fully sanitized the content. - Validate and sanitize inputs on the server, regardless of database constraints. Use schema validation to enforce safe strings.
- Apply context-aware output encoding when generating HTML, JSON, or URLs programmatically.
Example 1: Safe HTML rendering with Edge templates
Assume a CommentsController fetching a comment from CockroachDB and rendering it safely:
// app/Controllers/Http/CommentsController.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import Comment from 'App/Models/Comment'
export default class CommentsController {
public async show({ params, view }: HttpContextContract) {
const comment = await Comment.query()
.where('id', params.id)
.preload('author')
.firstOrFail()
// Edge will auto-escape {{ comment.body }} by default
return view.render('comments/show', { comment })
}
}
In the corresponding Edge template (resources/views/comments/show.edge), ensure you do not use unescaped interpolation for raw HTML:
<article>
<h3>By {{ comment.author.name }}</h3>
<p>{{ comment.body }}</p> <!-- auto-escaped -->
</article>
Example 2: Sanitizing before storage and strict validation
When accepting user input that may be stored in CockroachDB, validate first and store the raw value; escape on output. Here is an example using Zod schema validation:
import { schema } from '@ioc:Adonis/Core/Validator'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
const commentSchema = schema.create({
body: schema.string({ trim: true, escapeHtml: false }), // store raw, escape later
authorId: schema.number([rules.exists({ table: 'authors', key: 'id' })])
})
export async function storeComment({ request, response }: HttpContextContract) {
const payload = request.validate({ schema: commentSchema })
const comment = await Comment.create(payload)
return response.redirect().back()
}
Example 3: Native query with safe parameter binding
When using a native query to interact with CockroachDB, always use bindings to avoid injection, and escape output separately:
const result = await Database.from('comments')
.where('id', request.input('id'))
.select('body', 'author_name')
.limit(1)
if (result.length === 0) {
return response.notFound()
}
// result[0].body must be escaped in the response
return response.content(result[0].body)
For email or non-HTML contexts, ensure you do not treat stored data as HTML. If you must render user content as HTML (e.g., a rich-text field), use a dedicated sanitizer (like DOMPurify on the server side via a trusted library) before insertion and still apply output encoding for the context.
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 |