Hallucination Attacks in Actix with Cockroachdb
Hallucination Attacks in Actix with Cockroachdb — how this specific combination creates or exposes the vulnerability
A hallucination attack in the context of an Actix web service backed by CockroachDB occurs when an application returns plausible but incorrect or fabricated data in response to a user query. This typically arises from improper query construction, misuse of ORM features, or unchecked assumptions about record existence. In Actix, handlers often deserialize query results into Rust structs; if the logic fills missing fields from alternate sources or defaults without strict validation, the response can silently invent values that appear authoritative.
With CockroachDB, which provides strong consistency and SQL compliance, the database itself will not hallucinate—rows either exist or they do. However, application-layer code can hallucinate by:
- Assuming a row exists after an INSERT without verifying the returned row count, then populating a response with default or synthetic data.
- Using partial updates or upserts where the merge logic reconstructs an object and inadvertently fabricates fields that were not explicitly stored.
- Mapping rows to domain models with unchecked Option fields, then replacing None with placeholder values rather than returning a 404 or validation error.
An example scenario: an Actix handler queries a users table by ID. If the row is missing, the handler constructs a user object with hardcoded defaults and returns 200 OK. The client receives a seemingly valid user record that does not exist in CockroachDB, leading to authorization or logic errors downstream. Because CockroachDB returns accurate execution results, the hallucination is purely an application-layer failure—often rooted in missing null checks or incorrect error handling in Actix extractors and responders.
Insecure deserialization patterns can exacerbate this. If Actix uses Serde to deserialize JSON request bodies directly into database models without validating foreign-key constraints against CockroachDB, an attacker can supply IDs that do not exist, and the application may hallucinate related entities (e.g., returning a fabricated tenant or role). The combination of Actix’s async flexibility and CockroachDB’s strict SQL semantics means developers must explicitly handle empty results rather than relying on framework defaults or ORM convenience methods.
Cockroachdb-Specific Remediation in Actix — concrete code fixes
Remediation centers on strict handling of query results, explicit error mapping, and avoiding default fabrication. In Actix, ensure each database interaction validates presence and correctness before constructing responses. Use proper SQL checks and structured error handling rather than filling missing data with synthetic values.
Example: Safe query with explicit missing-row handling
use actix_web::{web, HttpResponse, Result};
use sqlx::postgres::PgPoolOptions;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, sqlx::FromRow)]
struct User {
id: i32,
email: String,
tenant_id: i32,
}
async fn get_user_by_id(path: web::Path, pool: web::Data<PgPoolOptions>) -> Result<HttpResponse> {
let user_id = path.into_inner();
// Explicitly query and handle Option
let user_result: Result<Option<User>, sqlx::Error> = sqlx::query_as(
"SELECT id, email, tenant_id FROM users WHERE id = $1"
)
.bind(user_id)
.fetch_optional(pool.as_ref())
.await;
match user_result {
Ok(Some(user)) => Ok(HttpResponse::Ok().json(user)),
Ok(None) => Ok(HttpResponse::NotFound().json(serde_json::json!({"error": "user not found"}))),
Err(e) => Ok(HttpResponse::InternalServerError().json(serde_json::json!({"error": e.to_string()}))),
}
}
Example: Upsert with verification instead of hallucination
Instead of assuming an upsert created a row, verify existence explicitly or rely on RETURNING to confirm inserted values.
async fn ensure_user(pool: web::Data<PgPoolOptions>, email: String, tenant_id: i32) -> Result<User, sqlx::Error> {
// Use RETURNING to get the actual stored row
let user = sqlx::query_as(
"INSERT INTO users (email, tenant_id) VALUES ($1, $2) ON CONFLICT (email) DO UPDATE SET tenant_id = EXCLUDED.tenant_id RETURNING id, email, tenant_id"
)
.bind(&email)
.bind(tenant_id)
.fetch_one(pool.as_ref())
.await?;
Ok(user)
}
Example: Foreign-key validation before response construction
When accepting a tenant_id, validate it exists in CockroachDB before using it to build a response.
async fn validate_tenant(pool: web::Data<PgPoolOptions>, tenant_id: i32) -> bool {
let count: (i64,) = sqlx::query_as("SELECT 1 FROM tenants WHERE id = $1")
.bind(tenant_id)
.fetch_one(pool.as_ref())
.await
.map(|row| row)
.is_ok();
count
}
By ensuring each Actix handler checks for None, uses RETURNING, and avoids constructing synthetic records, hallucination risks are mitigated. MiddleBrick scans can help identify missing null checks and improper error mapping in the API surface, providing findings tied to input validation and data exposure categories.
Related CWEs: llmSecurity
| CWE ID | Name | Severity |
|---|---|---|
| CWE-754 | Improper Check for Unusual or Exceptional Conditions | MEDIUM |