Email Injection in Express with Cockroachdb
Email Injection in Express with Cockroachdb — how this specific combination creates or exposes the vulnerability
Email injection occurs when user-controlled data is concatenated into email headers or commands without validation or escaping. In an Express application using CockroachDB, this typically manifests in two scenarios: constructing SQL statements with string interpolation for email-related fields, and composing email messages (e.g., notifications or transactional mail) using data stored in or submitted to the database.
Consider an endpoint that stores a user profile with an email address and later sends a confirmation email by building a shell command or query string. If the email value contains newline characters or shell metacharacters (e.g., %0a, %0d, or injected headers like Cc: or Bcc:), an attacker can inject additional headers or commands. With CockroachDB, if input is interpolated into dynamic SQL or passed to external utilities, the database can become a conduit for injection despite being a safe, type-safe driver when used with parameterized queries. The risk is not the database itself but the surrounding application logic that builds commands or queries using untrusted email input.
For example, an Express route that builds a SQL string like SELECT * FROM users WHERE email = '${email}' allows newline injection to terminate the intended query and append malicious commands or data exfiltration logic. Even when using the CockroachDB Node.js driver, failing to use prepared statements or parameterization permits injection through email fields that are later used in dynamic SQL or command construction. The database faithfully executes what the application sends, so malformed or malicious email content can lead to unintended operations, information leakage, or header smuggling when the same data is used to compose emails.
Another vector involves background jobs or scripts that read email addresses from CockroachDB and pass them to a mail utility or external process. If the email value contains shell metacharacters, the utility may interpret them as control characters, enabling command injection. This often occurs when concatenating email values into strings that are executed via child_process or similar mechanisms, turning what appears to be a benign data field into an injection vector.
To mitigate, always treat email input as untrusted. Validate format with a strict allowlist, enforce length limits, and sanitize newlines and control characters. Most importantly, avoid building SQL or shell commands by string concatenation. Use parameterized SQL with the CockroachDB driver and avoid passing email values to shell commands. If email values must be used in external processes, use safe APIs that accept arguments as arrays and never build command strings from user input.
Cockroachdb-Specific Remediation in Express — concrete code fixes
Remediation centers on eliminating string interpolation for SQL and ensuring email values are never used to construct commands or dynamic queries. Use parameterized queries with placeholders supported by the CockroachDB Node.js driver. This ensures email values are sent as data, not executable SQL.
Secure parameterized query example
const { Client } = require('pg'); // CockroachDB wire-compatible driver
const client = new Client({
connectionString: process.env.DATABASE_URL,
});
await client.connect();
app.post('/register', async (req, res) => {
const { email, name } = req.body;
// Validate email format before using it
if (!/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email)) {
return res.status(400).json({ error: 'Invalid email format' });;
}
// Use parameterized query to prevent injection
const result = await client.query(
'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING id',
[email, name]
);
res.json({ id: result.rows[0].id });
});
This approach ensures the email value is passed separately from the SQL text, neutralizing injection attempts that rely on newlines or SQL metacharacters in the email address.
Safe email composition without command injection
If sending emails directly from Node.js (e.g., via an SMTP client), avoid building email commands by concatenation. Use a well-maintained library that handles header encoding and line breaks safely. For example, with nodemailer, pass headers as structured objects rather than raw strings:
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false,
});
app.post('/send-verify', async (req, res) => {
const { recipient, token } = req.body;
// Validate recipient email format
if (!/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(recipient)) {
return res.status(400).json({ error: 'Invalid recipient' });
}
// Send email using structured data, not string concatenation
const info = await transporter.sendMail({
from: '[email protected]',
to: recipient,
subject: 'Verify your account',
text: `Your code is: ${token}`,
// Avoid setting raw headers with user input; use structured fields
});
res.json({ messageId: info.messageId });
});
Additionally, if your workflow involves reading email addresses from CockroachDB and passing them to external processes, prefer APIs that accept arguments as arrays or structured data rather than building command strings. For example, when using child_process in Node.js, always use the array form:
const { execFile } = require('child_process');
const email = await getEmailFromCockroachDB(userId);
// Safe: arguments are passed as an array, not concatenated
execFile('mailutil', ['--send-to', email, '--subject', 'Welcome'], (err) => {
if (err) { /* handle error */ }
});
Avoid exec or shell forms with string interpolation when email values are involved. Combining parameterized SQL for storage and safe libraries for email handling closes the injection paths specific to Express and CockroachDB integrations.