HIGH email injectionactixcockroachdb

Email Injection in Actix with Cockroachdb

Email Injection in Actix with Cockroachdb — how this specific combination creates or exposes the vulnerability

Email injection occurs when user-controlled input is concatenated into email headers or commands without validation or escaping. In an Actix web application using CockroachDB, this typically happens when building email-related features such as contact forms, password resets, or notification dispatches. If a developer interpolates user-supplied fields like email, name, or subject directly into a SQL INSERT that writes to a CockroachDB table, and then later uses that data in mail headers, the stage is set for injection.

Consider a route that accepts POST parameters and stores them in CockroachDB using a dynamic query string. An attacker can supply a payload such as email=test%40example.com%0D%0CCc:%20evil@example.com or email=test%40example.com%0D%0BSubject:%20Malicious. If the application does not sanitize newlines (\r and \n) before using the value in an SMTP command or header, the injected lines can alter the semantics of the message, adding recipients, changing subjects, or injecting additional headers.

With CockroachDB, which uses PostgreSQL wire protocol and SQL syntax, the typical vector is not SQL injection in the email header itself, but rather stored tainted data that later becomes unsafe when used in application-level email routines. However, if the same user input is also used to construct SQL without parameterization, an attacker might achieve both SQL injection and email injection in a single attack chain. For example, a crafted email string containing a single quote and newline can break out of a literal and introduce a second statement or comment, while also manipulating mail headers when the record is later read and processed by an email worker.

The risk is compounded when the Actix service retrieves user data from CockroachDB and passes it directly to an email library or SMTP client without normalization. CRLF sequences in the email field can cause the mail server or library to interpret injected lines as separate headers, leading to spam relay, open redirect in headers, or metadata poisoning. Because the scan categories include Input Validation and Unsafe Consumption, middleBrick would flag such flows as high severity, noting both the potential for header injection and the presence of unvalidated data persisted in a distributed SQL store like CockroachDB.

Real-world patterns seen in the wild include concatenating email into a format! string that forms the body of an email, or building a mail command with string interpolation. These patterns bypass the safety of typed queries and make it trivial for an attacker to inject extra headers. The combination of Actix’s async routing, CockroachDB’s transactional guarantees, and insufficient sanitization creates a scenario where tainted data can persist, propagate, and be re-expressed in SMTP streams.

Cockroachdb-Specific Remediation in Actix — concrete code fixes

Remediation focuses on strict input validation, canonicalization of email fields, and strict use of parameterized statements. Never build email headers or SQL commands via string concatenation with user input. Treat the email address as a structured field, normalize it, and enforce format constraints before storage or transmission.

1. Canonicalize and validate email input

Normalize the email by trimming whitespace, lowercasing the domain part, and rejecting strings containing newline or carriage return characters. Use a strict allowlist regex for email syntax and reject any input containing \r or \n.

use regex::Regex;

fn sanitize_email(raw: &str) -> Result<String, &'static str> {
    // Reject newlines and carriage returns to prevent header injection
    if raw.contains('\r') || raw.contains('\n') {
        return Err("invalid character in email");
    }
    let email = raw.trim().to_lowercase();
    let re = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap();
    if !re.is_match(&email) {
        return Err("invalid email format");
    }
    Ok(email)
}

2. Use parameterized queries with CockroachDB

When inserting or updating user records, always use prepared statements with bound parameters. This prevents SQL injection and ensures email values are stored safely without altering query structure.

// Using `sqlx` with CockroachDB in Actix
use sqlx::PgPool;

async fn create_user(pool: &PgPool, email: &str, name: &str) -> Result<(), sqlx::Error> {
    let email = sanitize_email(email)?.to_string();
    sqlx::query(
        "INSERT INTO users (email, name, created_at) VALUES ($1, $2, NOW())"
    )
    .bind(email)
    .bind(name)
    .execute(pool)
    .await?;
    Ok(())
}

3. Escape data before email composition

When reading records from CockroachDB to construct emails, apply header encoding to unsafe characters. Use libraries that handle MIME encoding rather than manually concatenating headers.

use lettre::message::Mailbox;

fn build_mailbox(email: &str, name: &str) -> Mailbox {
    // lettre safely encodes display names and validates address syntax
    format!(r#"{} <{}>", name, email).parse().expect("valid mailbox")
}

4. Enforce schema constraints in CockroachDB

Define table constraints that reject malformed email values at the database level. A check constraint can reduce the risk of corrupted data feeding downstream email workflows.

-- CockroachDB schema definition
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email STRING NOT NULL,
    name STRING NOT NULL,
    created_at TIMESTAMPTZ NOT NULL,
    CONSTRAINT valid_email CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$')
);

5. Secure the Actix handler

Ensure the handler validates input before any database interaction and applies the same canonicalization logic on reads. Avoid passing raw user strings into SMTP libraries or templates that build headers.

use actix_web::{web, HttpResponse};

async fn submit_contact(
    form: web::Form<ContactForm>,
    pool: web::Data<PgPool>
) -> HttpResponse {
    let email = match sanitize_email(&form.email) {
        Ok(e) => e,
        Err(_) => return HttpResponse::BadRequest().body("invalid email"),
    };
    create_user(&pool, &email, &form.name).await.unwrap_or_else(|_| {
        HttpResponse::InternalServerError().body("failed to store user")
    });
    HttpResponse::Ok().body("submitted safely")
}

Frequently Asked Questions

Why is newline stripping important for email fields stored in CockroachDB?
CockroachDB preserves all characters, so newline (\r, \n) bytes entered by an attacker remain intact. If those values are later used in SMTP commands or email headers without canonicalization, CRLF injection can add recipients or headers, enabling email spoofing or spam relay.
Does using CockroachDB’s parameterized queries fully prevent email injection?
Parameterized queries prevent SQL injection and safely store the raw string, but they do not stop application-level email injection. You must still validate, canonicalize, and encode email values before composing headers or SMTP messages, regardless of the database backend.