HIGH ldap injectionfastapicockroachdb

Ldap Injection in Fastapi with Cockroachdb

Ldap Injection in Fastapi with Cockroachdb — how this specific combination creates or exposes the vulnerability

LDAP Injection occurs when an attacker can manipulate LDAP query construction, typically through unsanitized user input. In a Fastapi application that uses an LDAP server for authentication or group membership checks, if input is concatenated directly into LDAP filter strings, attackers can bypass authentication or extract sensitive data. When this Fastapi service stores or references account data in Cockroachdb, the LDAP interaction often maps user identities to relational records (e.g., mapping authenticated LDAP DN to tenant or user rows in Cockroachdb). This introduces a multi-layer risk: an LDAP injection can lead to unauthorized directory access and can be chained to manipulate or infer Cockroachdb data through application logic that trusts LDAP-derived identifiers.

Consider a Fastapi endpoint that takes a username and builds an LDAP filter without escaping:

from fastapi import Fastapi, Depends, HTTPException
import ldap

app = Fastapi()

def get_ldap_conn():
    conn = ldap.initialize("ldap://ldap.example.com")
    conn.protocol_version = ldap.VERSION3
    return conn

@app.post("/login")
async def login(username: str, password: str):
    conn = get_ldap_conn()
    # Unsafe: direct string interpolation into LDAP filter
    filt = f"(uid={username})"
    try:
        conn.simple_bind_s(filt, password)
    except ldap.INVALID_CREDENTIALS:
        raise HTTPException(status_code=400, detail="Invalid credentials")
    # If bind succeeds, map to Cockroachdb identity
    cur = conn.cursor()  # placeholder for application DB session
    # Example: query Cockroachdb for user metadata using LDAP-supplied identity
    cur.execute("SELECT id, role FROM users WHERE ldap_uid = $1", (username,))
    row = cur.fetchone()
    return {"ok": True, "role": row[1] if row else None}

The (uid={username}) filter is vulnerable to LDAP Injection. An attacker can supply uid*)(uid=admin)) or other control characters to change the filter semantics, potentially authenticating as another user or enumerating directory entries. Because the application later uses the same username to query Cockroachdb, the LDAP injection can influence which Cockroachdb rows are accessed, leading to horizontal privilege escalation (BOLA/IDOR) or unauthorized data exposure. The combination is particularly risky if Cockroachdb holds sensitive PII or if LDAP group membership is used to derive row-level permissions in the database.

Moreover, Fastapi’s dependency injection and async patterns can inadvertently propagate the tainted input. For example, passing the username from authentication to multiple service functions increases the attack surface across components that interact with Cockroachdb. Without input validation and strict separation between identity store queries and database queries, the LDAP channel becomes a pivot point for attacks against the relational store.

Cockroachdb-Specific Remediation in Fastapi — concrete code fixes

Remediation centers on preventing LDAP injection by treating LDAP filter construction as a parameterized, escaped operation, and ensuring Cockroachdb queries remain independent and parameterized. Do not concatenate user input into LDAP filters. Instead, use an LDAP escape routine and bind with a constructed distinguished name (DN) or use parameterized filters where the LDAP library supports it. For Cockroachdb, always use parameterized SQL; never interpolate values into queries, even when values originate from LDAP.

Below is a secure Fastapi pattern that separates concerns, escapes LDAP input, and uses strongly typed parameters for Cockroachdb:

from fastapi import Fastapi, Depends, HTTPException
import ldap
import psycopg2
from psycopg2 import sql

app = Fastapi()

def get_ldap_conn():
    conn = ldap.initialize("ldap://ldap.example.com")
    conn.protocol_version = ldap.VERSION3
    return conn

def escape_ldap_value(value: str) -> str:
    """Escape RFC4515 special characters for safe LDAP filter use."""
    # From RFC4515: * -> \2a, ( -> \28, ) -> \29, \\ -> \5c, null -> \00
    replacements = {('*', r'\2a'), ('(', r'\28'), (')', r'\29'), ('\\', r'\5c'), ('\x00', r'\00')}
    result = value
    for char, esc in replacements:
        result = result.replace(char, esc)
    return result

@app.post("/login")
async def login(username: str, password: str):
    # Validate and normalize input before using in LDAP
    safe_username = escape_ldap_value(username.strip())
    # Use a parameterized approach by constructing a full DN when possible
    # Example: avoid filter injection by binding directly with a known DN pattern
    user_dn = f"uid={safe_username},ou=people,dc=example,dc=com"
    conn = get_ldap_conn()
    try:
        conn.simple_bind_s(user_dn, password)
    except ldap.INVALID_CREDENTIALS:
        raise HTTPException(status_code=400, detail="Invalid credentials")

    # Now independently query Cockroachdb using parameterized SQL only
    conn_pg = psycopg2.connect(
        host="cockroachdb.example.com",
        port26257,
        user="app_user",
        password="secure_password",
        database="app_db"
    )
    try:
        with conn_pg.cursor() as cur:
            # Safe: parameterized query, no string interpolation
            cur.execute(
                sql.SQL("SELECT id, role FROM users WHERE ldap_uid = %s"),
                (safe_username,)
            )
            row = cur.fetchone()
            return {"ok": True, "role": row[1] if row else None}
    finally:
        conn_pg.close()

Key points specific to Cockroachdb:

  • Always use cursor.execute(sql, params) with parameter placeholders; Cockroachdb’s PostgreSQL wire protocol supports this via psycopg2 or compatible drivers.
  • Do not construct SQL with string concatenation or interpolation, even if the input was escaped for LDAP, because threat contexts differ.
  • Validate and sanitize input once at the edge (e.g., allow only alphanumeric and limited special characters for usernames) to reduce complexity downstream.
  • If using an ORM or higher-level DB access layer, ensure it uses parameterized statements under the hood; avoid raw string queries.

Additionally, apply defense-in-depth by implementing schema-level constraints in Cockroachdb (e.g., NOT NULL, CHECK constraints) and using least-privilege database roles for the application user. This ensures that even if a higher-layer bug introduces tainted input, the database restricts what can be done with it.

Frequently Asked Questions

Can LDAP Injection directly modify data in Cockroachdb?
By itself, LDAP Injection affects the directory service. However, if the application uses LDAP-derived input to build SQL queries without parameterization, it can lead to SQL Injection against Cockroachdb. Proper escaping for LDAP and strict parameterized queries for the database prevent chained exploitation.
Does middleBrick detect LDAP Injection in Fastapi applications using Cockroachdb?
middleBrick scans unauthenticated attack surfaces and includes checks for injection and authorization flaws across multiple layers. It can identify indicators of LDAP Injection and related authentication bypass patterns; findings include remediation guidance mapped to frameworks such as OWASP API Top 10.