Path Traversal in Axum with Cockroachdb
Path Traversal in Axum with Cockroachdb — how this specific combination creates or exposes the vulnerability
Path Traversal occurs when an API accepts user-controlled input used to construct file paths or database identifiers without adequate validation, allowing an attacker to access files or data outside the intended directory or scope. In an Axum application using Cockroachdb, this typically manifests through endpoints that accept identifiers (e.g., user_id, document_id) and use them in SQL queries without proper authorization checks or input sanitization.
Consider an endpoint that retrieves a user document by ID:
// WARNING: This pattern is vulnerable to IDOR and path traversal via crafted IDs
async fn get_document(
Path(doc_id): Path<String>,
pool: &PgPool,
) -> Result<Json<Document>, (StatusCode, String)> {
let row = sqlx::query!("SELECT id, content FROM documents WHERE id = $1", doc_id)
.fetch_optional(pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
match row {
Some(r) => Ok(Json(Document { id: r.id, content: r.content })),
None => Err((StatusCode::NOT_FOUND, "Not found".to_string())),
}
}
If doc_id is not constrained to the authenticated user’s scope (e.g., missing tenant or ownership checks), an attacker can traverse paths in the logical data space by iterating through IDs. Although Cockroachdb does not expose a traditional filesystem path, the database identifier space becomes the traversal target. Combined with BOLA (Broken Level Access) weaknesses, this allows unauthorized access across what appears to be isolated records.
middleBrick detects this pattern during its unauthenticated scan by observing whether endpoints that accept user-supplied identifiers enforce authorization relative to a subject (e.g., via JWT subject claims or session context). The scanner cross-references OpenAPI/Swagger definitions with runtime behavior to identify missing authorization constraints on parameters used in SQL statements. Findings often map to the OWASP API Top 10 Broken Object Level Authorization and can intersect with Data Exposure checks when sensitive Cockroachdb rows are accessible without proper scoping.
Additional risk arises when endpoints expose filesystem-like operations (e.g., serving uploaded files) and use user input to build paths without canonicalization. Even when Cockroachdb stores metadata only, Axum handlers that concatenate user input into file paths on the server before passing to Cockroachdb for lookup can enable directory traversal via ../../ sequences, leading to Data Exposure or server-side request forgery when combined with SSRF probes.
Cockroachdb-Specific Remediation in Axum — concrete code fixes
Remediation focuses on strict input validation, parameterized queries, and enforcing ownership or tenant context at the application layer. Avoid string concatenation for SQL; use strongly typed queries with explicit bind variables. Ensure every query that references a row ID also validates that the row belongs to the requesting subject.
1. Enforce ownership checks using the authenticated subject:
async fn get_document_secure(
Path(doc_id): Path<String>,
Extension(pool): Extension<PgPool>,
// Assume extract_subject returns a validated subject claim
subject: Subject,
) -> Result<Json<Document>, (StatusCode, String)> {
let row = sqlx::query!((
"SELECT id, content, owner_id FROM documents WHERE id = $1 AND owner_id = $2"
), doc_id, subject.id)
.fetch_optional(&pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
match row {
Some(r) => Ok(Json(Document { id: r.id, content: r.content })),
None => Err((StatusCode::FORBIDDEN, "Access denied".to_string())),
}
}
This ensures that even if an attacker guesses or iterates IDs, they cannot access records where owner_id does not match the authenticated subject. The query uses Cockroachdb’s parameterized SQL to prevent injection and relies on the database to enforce row-level filtering.
2. Validate and restrict identifier formats before using them in queries:
use validator::Validate;
#[derive(Validate)]
struct DocumentPath {
#[validate(length(min = 1), regex("^[a-zA-Z0-9_-]+$"))]
doc_id: String,
}
async fn get_document_validated(
Path(path): Path<DocumentPath>,
pool: &PgPool,
subject: Subject,
) -> Result<Json<Document>, (StatusCode, String)> {
let row = sqlx::query!((
"SELECT id, content FROM documents WHERE id = $1 AND owner_id = $2"
), path.doc_id, subject.id)
.fetch_optional(pool)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
match row {
Some(r) => Ok(Json(Document { id: r.id, content: r.content })),
None => Err((StatusCode::FORBIDDEN, "Access denied".to_string())),
}
}
By constraining doc_id with a regex that allows only safe characters, you reduce the risk of injection or misuse. Combined with parameterized queries, this approach aligns with secure coding practices for database interactions in Rust-based Axum services.
3. For file-serving endpoints, sanitize paths and avoid user-controlled directory traversal:
use std::path::{Path, PathBuf};
fn sanitize_path(base: &Path, user_path: &str) -> Option<PathBuf> {
let normalized = PathBuf::from(user_path).strip_prefix(".").ok()?;
let full = base.join(normalized).canonicalize().ok()?;
if full.starts_with(base) {
Some(full)
} else {
None
}
}
async fn serve_file(
Path(filename): Path<String>,
pool: &PgPool,
) -> Result<NamedFile, (StatusCode, String)> {
let base = Path::new("/safe/uploads");
let safe_path = sanitize_path(base, &filename)
.ok_or_else(|| (StatusCode::BAD_REQUEST, "Invalid path".to_string()))?;
// Use safe_path to verify file exists in allowed directory before serving
NamedFile::open(safe_path).map_err(|_| (StatusCode::NOT_FOUND, "File not found".to_string()))
}
This pattern ensures that user input cannot escape the intended base directory, mitigating traversal attempts before any database interaction is required.
middleBrick’s CLI can validate that such patterns are present in your codebase and that endpoints are scanned for insecure parameter usage. Use the GitHub Action to fail builds if insecure path-building patterns are detected, and leverage the MCP Server to get inline guidance while editing Axum handlers in your IDE.
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 |