Lambda Tainted SQL String Construction

HIGH

Lambda event data is used in SQL string construction via f-strings or concatenation before being passed to a database execute call, enabling SQL injection.

Rule Information

Language
Python
Category
AWS Lambda
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonawslambdasql-injectionstring-constructionf-stringconcatenationtaint-analysisinter-proceduralCWE-89OWASP-A03
CWE References

Interactive Playground

Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.

pathfinder scan --ruleset python/PYTHON-LAMBDA-SEC-015 --project .
1
2
3
4
5
6
7
8
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

About This Rule

Understanding the vulnerability and how it is detected

This rule detects SQL injection vulnerabilities in AWS Lambda functions where untrusted event data is used to construct a SQL query string via f-string interpolation or string concatenation, and the resulting tainted string is subsequently passed to any database execute() function.

This rule differs from driver-specific rules (SEC-010 through SEC-014) by focusing on the intermediate SQL string construction step rather than the specific database driver. It catches the pattern where a tainted SQL string is built in one variable or function and then passed to execute() in another, which may span multiple helper functions or modules in the Lambda codebase.

Lambda functions receive attacker-controllable event data from API Gateway, SQS, SNS, S3, DynamoDB Streams, and other triggers (event.get("body"), event.get("queryStringParameters"), event["Records"]). When this data is used to build SQL strings, the string becomes tainted regardless of which database driver is used to execute it. Detecting the tainted string construction step, rather than only the execute() call, catches vulnerability patterns where the string is stored in a variable, passed through helper functions, or assembled from multiple event fields before reaching the sink.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Cross-Module Tainted SQL Propagation

SQL strings built from event data in one Lambda module (e.g., a query builder utility) and executed in another module are vulnerable even when the execute() call site appears to use safe patterns. This inter-module taint propagation is the primary pattern that driver-specific rules miss.

2

Multi-Driver Vulnerability Coverage

Lambda functions that connect to multiple databases via different drivers (e.g., PyMySQL for MySQL and psycopg2 for PostgreSQL) may construct SQL strings centrally and execute them through different drivers. A tainted SQL string passed to any driver's execute() is equally dangerous regardless of the driver.

3

Stored Query Template Injection

Some Lambda functions build SQL query templates by combining event data with stored query fragments, then execute the assembled template. The tainted template construction step exposes the injection vulnerability even before the execute() call.

4

Dynamic WHERE Clause Construction

Lambda handlers that build dynamic WHERE clauses by appending conditions based on event fields (e.g., adding AND column = 'value' for each filter parameter) via string concatenation are particularly vulnerable, as each filter field is an injection point and the vulnerability scales with the number of event fields processed.

How to Fix

Recommended remediation steps

  • 1Restructure SQL construction helpers to return a (query_template, params_list) tuple rather than a pre-built SQL string with embedded values.
  • 2Use placeholders (%s for MySQL/psycopg2, :name for SQLAlchemy text()) in the SQL template and collect event values in a separate list or dictionary.
  • 3For dynamic WHERE clause construction, append placeholders to the WHERE string and values to a separate list; never append event data to the SQL string directly.
  • 4Validate and type-convert event fields before adding them to the parameters list as a defense-in-depth measure.
  • 5Apply least-privilege database permissions to the Lambda's database user to limit the blast radius of any successful injection.

Detection Scope

How Code Pathfinder analyzes your code for this vulnerability

This rule performs inter-procedural taint analysis with global scope. Sources are Lambda event dictionary access calls: calls("event.get"), calls("event.__getitem__"), including event.get("body"), event.get("queryStringParameters"), event.get("pathParameters"), and event["Records"]. The rule tracks taint through f-string interpolation and string concatenation operations to identify SQL string variables that contain event data. The sink is any calls("*.execute") call where the tainted SQL string variable is passed as the first argument (tracked via .tracks(0)). Sanitizers include explicit int() or float() type conversion. The analysis follows taint through variable assignments, function return values, and module boundaries.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-89 ranked #3 in 2023 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection
PCI DSS v4.0
Requirement 6.2.4 - protect against injection attacks
NIST SP 800-53
SI-10: Information Input Validation
AWS Security Best Practices
Validate all inputs; apply least-privilege database permissions

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Lambda Tainted SQL String Construction

The driver-specific rules (SEC-010 to SEC-014) flag taint that flows directly from the Lambda event to a specific driver's execute() call. SEC-015 flags the intermediate step: when event data is used to construct a SQL string variable via f-strings or concatenation, and that tainted string variable is then passed to any execute() call. SEC-015 catches cases where the SQL string is assembled in a helper function or stored in a variable before being executed, which the driver-specific rules may miss.
If the column name comes from the event dictionary and is used in the SQL string (even via an allowlist check), the SQL string is still tainted by the rule's analysis. The recommended approach is to use a pre-built dictionary of safe SQL fragments keyed by allowed column names, and use the event value only to select a key from that dictionary, never to directly modify the SQL string. This keeps the SQL string as a static literal and avoids taint entirely.
No. Allowing event-controlled SQL templates is equivalent to allowing arbitrary SQL execution. SQL query templates must always be static literals defined in the Lambda code, never derived from event data. The only event data that should appear in execute() calls is in the parameters tuple, never in the SQL string argument.
Use an explicit allowlist dictionary: ALLOWED_SORT_COLUMNS = {'name': 'u.name', 'created': 'u.created_at'}. Validate the event's sort field against the dictionary and use the dictionary's value (a pre-built safe column reference) in the SQL string. For sort direction, validate the event value against {'asc', 'desc'}. Both the column reference and direction come from hardcoded constants, not from the event data itself.
SQLAlchemy's ORM and Core expression language (select(), where(), filter()) build parameterized queries programmatically and prevent SQL string injection by design. AWS's built-in RDS Data Service API and its boto3 execute_statement() use named parameters natively. For DynamoDB, the boto3 DynamoDB client's KeyConditionExpression uses Attr() and Key() objects rather than SQL strings. All of these alternatives eliminate tainted SQL string construction entirely.

New feature

Get these findings posted directly on your GitHub pull requests

The Lambda Tainted SQL String Construction rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works