~/wiki

SQL Injection in LLM Systems

Confiance : high
sql-injectionsecurityllm-systemsdatabase-securitymetadata-filteringparameterizationinput-validationproduction-vulnerabilitiesassistant-rhcritical-security-issuesstring-interpolationquery-constructiondatabase-attacks

Critical security vulnerability in LLM applications where user-controlled metadata filters or search parameters are directly interpolated into SQL queries without proper parameterization, enabling attackers to execute arbitrary database operations.

Vulnerability Patterns in RAG Systems

Direct String Interpolation

# VULNERABLE: Direct value interpolation
def _build_filter_clause(self, filters):
    clause = f"metadata = '{filters['value']}'"  # SQL injection risk
    return clause

Unparameterized IN Clauses

# VULNERABLE: List values directly embedded
def build_filter(self, values):
    value_str = "', '".join(values)
    return f"column IN ('{value_str}')"  # Injection through crafted list items

JSON Metadata Filtering

# VULNERABLE: User-controlled JSON metadata
def filter_by_metadata(self, key, value):
    query = f"SELECT * FROM docs WHERE metadata->>{key} = '{value}'"
    # Attacker controls both key and value

Attack Vectors

Quote Escape Attacks

# Attacker input: "'; DROP TABLE documents; --"
# Resulting query: SELECT * FROM docs WHERE field = ''; DROP TABLE documents; --'

Boolean Logic Manipulation

# Attacker input: "' OR 1=1 --"  
# Resulting query: SELECT * FROM docs WHERE field = '' OR 1=1 --'
# Returns all documents regardless of intended filtering

Nested JSON Exploitation

# Attacker input for JSON key: "'; DELETE FROM embeddings; SELECT 'x"
# Malicious query execution through JSON operator injection

LLM System Specific Risks

Metadata-Driven Retrieval

RAG systems often use metadata filtering to scope retrieval results. User queries may indirectly control metadata values, creating injection opportunities:

# User asks: "Show me documents from ministry '; DROP TABLE docs; --"
# System generates metadata filter with user input
ministry_filter = user_input  # Dangerous!

Multi-Source Federation

Systems querying multiple databases with different schemas increase attack surface:

# Different databases, same vulnerability pattern
postgres_query = f"WHERE ministry = '{user_ministry}'"
sqlite_query = f"WHERE dept = '{user_ministry}'"  # Same injection risk

Dynamic Query Construction

LLM systems often build queries dynamically based on user intent:

# AI agent constructs query based on user request
if user_wants_recent:
    date_filter = f"date > '{user_date}'"  # User controls date format

Case Study: Assistant-RH Vulnerabilities

The assistant-rh system exhibited multiple SQL injection vulnerabilities:

Metadata Filter Injection

# retriever.py:69 - Direct string interpolation
def _build_filter_clause(self, metadata_filters):
    for key, value in metadata_filters.items():
        clauses.append(f"metadata->>'{key}' = '{value}'")  # VULNERABLE

List Value Injection

# IN clause construction with user-controlled values
values = "', '".join(filter_values)  # No escaping
query = f"field IN ('{values}')"  # Injection through list items

Compound Attack Surface

The system's multi-source architecture multiplied the attack surface, with similar vulnerabilities across PostgreSQL and SQLite implementations.

Mitigation Strategies

Parameterized Queries

# SECURE: Use parameterized queries
def build_filter_secure(self, key, value):
    query = "SELECT * FROM docs WHERE metadata->>%s = %s"
    return self.execute(query, (key, value))

Input Validation

# SECURE: Validate metadata keys against whitelist
ALLOWED_METADATA_KEYS = {'ministry', 'department', 'date', 'category'}

def validate_metadata_key(self, key):
    if key not in ALLOWED_METADATA_KEYS:
        raise ValueError(f"Invalid metadata key: {key}")

JSON-Specific Protections

# SECURE: Proper JSON parameter binding
def filter_json_metadata(self, key, value):
    # Validate key is safe for JSON operator
    if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', key):
        raise ValueError("Invalid JSON key format")
    
    # Use proper parameterization
    query = "SELECT * FROM docs WHERE metadata->>%s = %s"
    return self.execute(query, (key, value))

Query Builder Abstractions

# SECURE: Use ORM or query builder
from sqlalchemy import and_, or_

def build_secure_filter(self, filters):
    conditions = []
    for key, value in filters.items():
        # ORM handles parameterization automatically
        conditions.append(self.model.metadata[key] == value)
    return and_(*conditions)

Detection and Prevention

Code Review Patterns

Look for these patterns in code reviews:

  • String formatting in SQL queries (f"...", .format(), % formatting)
  • Direct concatenation of user input into queries
  • Raw SQL construction without parameterization

Static Analysis

# Custom linter rules
def check_sql_injection(node):
    if isinstance(node, ast.JoinedStr):  # f-string
        if any('SELECT' in part or 'WHERE' in part for part in extract_strings(node)):
            return "Potential SQL injection in f-string"

Testing Strategies

def test_sql_injection_protection():
    malicious_inputs = [
        "'; DROP TABLE docs; --",
        "' OR 1=1 --",
        "' UNION SELECT password FROM users --"
    ]
    
    for malicious_input in malicious_inputs:
        # Should not modify database or return unexpected results
        result = search_with_filter('ministry', malicious_input)
        assert_no_injection_occurred(result)

Production Hardening

Database Permissions

  • Use dedicated database users with minimal required permissions
  • Avoid connections with DDL (DROP, CREATE) privileges for application queries
  • Implement row-level security where applicable

Query Monitoring

# Log and monitor for injection patterns
def log_suspicious_queries(query, params):
    suspicious_patterns = ['DROP', 'DELETE', 'UPDATE', 'UNION', '--', ';']
    if any(pattern in query.upper() for pattern in suspicious_patterns):
        logger.warning(f"Suspicious query detected: {query[:100]}")

Defense in Depth

  • Input validation at multiple layers
  • Database-level query restrictions
  • Application-level parameterization
  • Regular security audits

See also

  • assistant-rh - Case study system with SQL injection vulnerabilities
  • undefined-references - Related production code quality issues
  • module-loading-failures - Other critical system failures
  • database-security - Broader database security practices
  • input-validation - General input validation strategies