Pii Leakage in Axum with Cockroachdb
Pii Leakage in Axum with Cockroachdb — how this specific combination creates or exposes the vulnerability
When building a web service with the Axum framework in Rust and storing data in CockroachDB, PII leakage commonly arises from mismatches between application-layer data handling and database storage practices. Axum encourages strongly typed request extraction and handler composition, which is effective for modeling business logic, but does not automatically enforce privacy controls at the persistence boundary. Developers may inadvertently store or return sensitive fields such as email addresses, phone numbers, government IDs, or location coordinates without encryption, masking, or access restrictions.
In a CockroachDB-backed Axum service, leakage can occur through several specific patterns. If a developer maps request DTOs directly to database columns that contain PII, and then serializes query results back to API consumers, sensitive data can flow unguarded through HTTP responses. For example, a User table with columns like email, phone, or ssn_hash might be queried by an endpoint such as GET /users/{id}; without explicit field filtering, the handler may return the full row, exposing PII to clients or logs. Similarly, CockroachDB’s secondary indexes and JSONB columns can inadvertently expose PII if they store raw personal data and are queried without restriction.
Another common vector is logging and observability. Axum middleware that logs requests or responses may capture PII present in payloads or database rows, especially when developers use generic debug logging on handler results. CockroachDB audit logs or application-level traces that include full structs or serialized rows can retain sensitive information. Additionally, serialization formats like JSON or MessagePack used in APIs may embed PII in nested objects or arrays, and Axum’s extractor patterns may not validate or redact these fields before persistence or transmission.
Compliance-aware developers must also consider scope and retention. Even when PII is stored securely in CockroachDB using encrypted columns, Axum endpoints that aggregate or export data—such as admin dashboards or export endpoints—can create unintended exposure if they do not enforce least-privilege access controls and field-level masking. Without runtime checks, an authenticated route might return more data than necessary, violating principles like data minimization and increasing the impact of a potential breach.
Cockroachdb-Specific Remediation in Axum — concrete code fixes
To prevent PII leakage in an Axum application using CockroachDB, implement explicit data handling, storage-layer controls, and response filtering. Use selective queries and DTOs that exclude sensitive fields unless explicitly required, and apply encryption or hashing at rest where applicable. Below are concrete, realistic code examples tailored for this stack.
1. Define segregated models and DTOs
Separate your database model from API contracts. Store PII in the database but never return it directly from endpoints unless necessary and consented. Use a distinct response DTO that omits sensitive fields.
// Domain model (maps to CockroachDB table)
#[derive(Debug, Queryable, Identifiable)]
pub struct User {
pub id: i32,
pub email: String,
pub phone: String,
pub ssn_hash: String,
pub created_at: chrono::NaiveDateTime,
}
// API request DTO
#[derive(Debug, Deserialize)]
pub struct CreateUser {
pub email: String,
pub phone: String,
pub ssn_hash: String,
}
// API response DTO — excludes PII
#[derive(Debug, Serialize)]
pub struct UserPublic {
pub id: i32,
pub created_at: chrono::NaiveDateTime,
}
2. Use selective queries and field projection
When fetching data for endpoints that do not require PII, explicitly select only the columns you need using SQLx or Diesel. This reduces accidental exposure and makes intent explicit.
// Using SQLx with CockroachDB — fetch only non-PII fields for public endpoints
async fn get_user_public(
pool: &PgPool,
user_id: i32,
) -> Result<UserPublic, sqlx::Error> {
sqlx::query_as("
SELECT id, created_at FROM users WHERE id = $1
")
.bind(user_id)
.fetch_one(pool)
.await
}
3. Encrypt or hash sensitive fields at rest
For fields such as email or phone, prefer storing encrypted or hashed values when feasible. Use CockroachDB’s built-in cryptographic functions or application-layer encryption with strong keys managed outside the database.
// Example: storing an email as encrypted using application-layer keys
let encrypted_email = encrypt(&email, &app_key); // implement using AES-GCM or similar
sqlx::query("INSERT INTO users (email, email_encrypted) VALUES ($1, $2)")
.bind(&email)
.bind(encrypted_email)
.execute(pool)
.await?;
4. Apply middleware filters and guards
In Axum, use extractors and guards to ensure handlers only access data they are authorized to see. Combine this with runtime checks before returning any database row.
// Axum extractor example with scope check
async fn user_handler(
user_id: Path<i32>,
Extension(state): Extension<AppState>,
) -> Result<Json<UserPublic>, (StatusCode, String)> {
let user = get_user_public(&state.pool, *user_id)
.await
.map_err(|e| (StatusCode::NOT_FOUND, e.to_string()))?;
Ok(Json(user))
}
5. Redact logs and traces
Ensure logging frameworks do not capture full structs containing PII. Customize log formats in Axum middleware to exclude sensitive fields.
// Axum middleware to redact PII from logs
impl Layer<S> for RedactionLayer {
type Service = RedactedService<S>;
fn layer(&self, inner: S) -> Self::Service {
RedactedService { inner }
}
}
struct RedactedService<S> {
inner: S,
}
impl<S, ReqBody, Body> Service<Request<ReqBody>> for RedactedService<S>
where
S: Service<Request<ReqBody>, Response = Response<Body> + 'static>
{
type Response = S::Response;
type Error = S::Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>
where
ReqBody: 'static,
{
fn call(&self, req: Request<ReqBody>) -> Self::Future {
// redact known PII keys from request/response logs
let redacted = redact_request(&req);
let fut = self.inner.call(redacted);
Box::pin(async move {
let res = fut.await?;
Ok(redact_response(res))
})
}
}
}
6. Enforce least privilege at the database level
Configure CockroachDB roles and row-level security so that Axum services connect with minimal privileges. Avoid using a highly privileged service account for routine queries.
-- Example CockroachDB role for read-only public user access
CREATE ROLE public_reader;
GRANT SELECT ON TABLE users TO public_reader;
REVOKE ALL ON DATABASE mydb FROM public_reader;
-- Application connects as public_reader for public endpoints
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |