Lambda SQL Injection via pymssql cursor.execute()

CRITICAL

Lambda event data flows to pymssql cursor.execute() without parameterization, enabling SQL injection against RDS SQL Server backends.

Rule Information

Language
Python
Category
AWS Lambda
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonawslambdasql-injectionpymssqlsql-serverrdstaint-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-012 --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
38
39
40
41
42

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 flows into pymssql cursor.execute() calls without proper parameterization, enabling SQL injection against RDS for SQL Server backends.

Lambda functions connecting to RDS for SQL Server (Microsoft SQL Server) via pymssql receive event data from API Gateway, SQS, SNS, S3, and other triggers. Fields like event.get("body"), event.get("queryStringParameters"), and event["Records"] are attacker-controllable in public-facing deployments. pymssql uses %s (or %d, %f for typed parameters) as placeholders; when these placeholders are bypassed by embedding event data directly in the SQL string via concatenation or f-strings, injection becomes possible.

SQL Server injection is particularly dangerous due to xp_cmdshell, a stored procedure that executes OS commands. While RDS restricts xp_cmdshell, unrestricted SQL Server instances allow full OS command execution through SQL injection. Even on RDS, data exfiltration, authentication bypass, and data manipulation remain fully exploitable. Lambda functions lack the ORM safety layer that web frameworks provide, making raw pymssql calls a common injection vector in serverless SQL Server integrations.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Full Database Exfiltration

An attacker who controls any SQL fragment can use UNION SELECT or error-based extraction techniques to read from any table accessible to the Lambda's SQL Server database user, including user credentials, financial records, session tokens, and other sensitive data.

2

xp_cmdshell OS Command Execution (Unrestricted SQL Server)

On unrestricted SQL Server instances (not RDS), an attacker with sufficient database permissions gained through injection can enable and execute xp_cmdshell to run arbitrary OS commands on the database server. RDS for SQL Server disables xp_cmdshell, but this risk applies to self-managed SQL Server instances accessible from Lambda.

3

Linked Server Pivoting

SQL Server supports linked servers that allow cross-database queries. SQL injection through a Lambda can exploit linked server configurations to pivot to other database servers accessible from the SQL Server instance, potentially accessing systems outside the intended Lambda attack surface.

4

Authentication Bypass

Lambda functions that verify credentials or check authorization via SQL queries are vulnerable to ' OR '1'='1'-- style bypasses. This can grant attackers administrative access by causing the query to return rows regardless of the actual credential values.

How to Fix

Recommended remediation steps

  • 1Always pass Lambda event data as the second argument to cursor.execute() as a tuple, never by concatenating it into the SQL string.
  • 2Use pymssql's typed placeholders (%s for strings, %d for integers, %f for floats) appropriately to benefit from driver-level type enforcement.
  • 3Grant the Lambda's SQL Server database login the minimum necessary permissions (SELECT on specific tables) and avoid sysadmin or db_owner role membership.
  • 4Store SQL Server credentials in AWS Secrets Manager with automatic rotation rather than in Lambda environment variables.
  • 5Enable RDS SQL Server audit logging to detect unusual query patterns that may indicate active exploitation.

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 sink is calls("*.execute") matching pymssql cursor objects with the tainted SQL string tracked via .tracks(0) (the query string argument). Sanitizers include explicit int() or float() type conversion. The analysis follows taint through string concatenation, f-string interpolation, variable assignments, and function 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 SQL Injection via pymssql cursor.execute()

pymssql supports typed placeholders: %s for strings/general values, %d for integers, %f for floats, and %b for binary data. Like other DB-API drivers, these placeholders must be used by passing values as the second tuple argument to cursor.execute(), not by using Python's built-in string formatting. Passing values via Python % string formatting ("%s" % value) performs string substitution at the Python level before pymssql sees the query, bypassing the driver's parameterization entirely.
Amazon RDS for SQL Server disables xp_cmdshell and prevents it from being enabled. However, the other impacts of SQL injection (data exfiltration, authentication bypass, data modification) remain fully applicable on RDS. If your Lambda connects to a self-managed SQL Server instance (e.g., on EC2), xp_cmdshell exploitation is possible if the database user has sufficient permissions.
Both pymssql and pyodbc (with Microsoft ODBC Driver for SQL Server) are commonly used. Both support parameterized queries via DB-API 2.0. The security principle is identical for both: pass event data as parameters, never in the SQL string. Consider SQLAlchemy as an abstraction layer over either driver, which encourages ORM usage and provides a uniform parameterization interface.
Static SQL clauses like TOP n, WITH (NOLOCK), or OFFSET n ROWS FETCH NEXT m ROWS ONLY are fine in the SQL string when n and m are validated integers from event data passed as parameters (for the actual values). For clauses where only the value varies, use a %d placeholder. For clauses where the structure varies based on event input (e.g., dynamic ORDER BY), use an allowlist of permitted values and select from a pre-built dictionary of safe SQL fragments.
Yes. The rule performs inter-procedural analysis and follows taint from the Lambda event dictionary through utility functions, query builders, and return values across file and module boundaries. If event data flows through a build_filter_clause() helper in a separate module to cursor.execute(), the finding is still reported.

New feature

Get these findings posted directly on your GitHub pull requests

The Lambda SQL Injection via pymssql cursor.execute() rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works