Lambda XSS via Tainted HTML Response Body

HIGH

Lambda event data is embedded directly in an HTML response body returned to API Gateway, enabling Cross-Site Scripting attacks against end users.

Rule Information

Language
Python
Category
AWS Lambda
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonawslambdaxsshtml-responseapi-gatewaytaint-analysisinter-proceduralCWE-79OWASP-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-020 --project .
1
2
3
4
5
6
7
8
9
10
11
12
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 Cross-Site Scripting (XSS) vulnerabilities in AWS Lambda functions where untrusted event data is embedded directly in the HTML response body returned to API Gateway without HTML-escaping.

Lambda functions acting as API Gateway backends frequently generate HTML responses dynamically. When the response body (the 'body' key in the Lambda return value) is set to Content-Type: text/html and contains unescaped event data, the browser renders any injected HTML or JavaScript. Event sources include event.get("queryStringParameters"), event.get("body"), event["pathParameters"], and event["headers"], all of which are attacker-controllable through API Gateway requests.

Unlike web frameworks that escape template variables by default, Lambda handlers that construct HTML strings manually have no automatic escaping layer. The developer must explicitly call html.escape() on every piece of event data embedded in an HTML response. Failure to do so enables reflected XSS, where an attacker crafts a URL or form that causes the Lambda to reflect malicious script back to the victim's browser.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Reflected XSS via API Gateway

An attacker who controls any query parameter, path parameter, or request body field can inject <script> tags or event handler attributes (onerror, onload) into the HTML response. The victim's browser executes the injected JavaScript when they visit the attacker-crafted URL, enabling session hijacking, credential theft, and malicious redirects.

2

Session Token Theft

JavaScript injected via Lambda XSS can read document.cookie, localStorage, and sessionStorage to steal session tokens and authentication credentials. These tokens can be exfiltrated to attacker-controlled infrastructure in a single request, giving the attacker persistent access to the victim's account.

3

Phishing and Content Injection

XSS allows attackers to modify the DOM to display fake login forms, error messages, or instructions that trick users into submitting credentials or installing malware. The attack occurs on the legitimate domain served by the Lambda-backed API, making it harder for users to recognize.

4

SameSite Cookie Bypass

Lambda-backed APIs that rely on SameSite=Lax cookie protections against CSRF are still vulnerable to XSS, because XSS executes in the same origin context and can make authenticated requests directly without triggering CSRF protections.

How to Fix

Recommended remediation steps

  • 1Call html.escape() on every piece of Lambda event data before embedding it in an HTML response body.
  • 2Add a Content-Security-Policy header to API Gateway responses to limit the impact of any XSS that bypasses output escaping.
  • 3Set X-Content-Type-Options: nosniff to prevent MIME type sniffing that could enable XSS via non-HTML responses.
  • 4Return JSON responses instead of HTML wherever possible; if the client needs HTML, render it client-side with a trusted JavaScript framework that escapes content automatically.
  • 5Validate and restrict the format of event fields that appear in HTML responses to further reduce the injection surface.

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["headers"]. The sink is the HTML response body string that flows into the Lambda return value's 'body' key when the Content-Type is text/html (tracked via .tracks(0)). Sanitizers include html.escape() applied to individual values before embedding. The analysis follows taint through f-string interpolation, string concatenation, variable assignments, and function boundaries.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

CWE Top 25
CWE-79 ranked #2 in 2023 Most Dangerous Software Weaknesses
OWASP Top 10
A03:2021 - Injection
PCI DSS v4.0
Requirement 6.2.4 - protect against injection attacks including XSS
NIST SP 800-53
SI-10: Information Input Validation
AWS Security Best Practices
Validate and sanitize all event data before including in responses

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Lambda XSS via Tainted HTML Response Body

Lambda returns response bodies as strings without any processing. Unlike template engines (Jinja2, Django templates) that escape variables by default, Lambda handlers that construct HTML manually have no automatic escaping layer. The developer must explicitly call html.escape() on every piece of event data. Lambda's design as a generic compute service means it does not impose any output encoding conventions.
Yes. The XSS vulnerability exists in the browser, not the server. When the Lambda returns an HTML response that the browser renders, injected scripts execute in the context of the application's origin. Session cookies, localStorage data, and API tokens accessible to that origin are all at risk. The Lambda execution model on the server side is irrelevant to the browser-side XSS impact.
CSP is a valuable defense-in-depth measure, but it is not a substitute for output encoding. CSP can be bypassed in various scenarios (JSONP endpoints, allowed CDN domains, policy misconfigurations). The correct primary defense is html.escape() applied to all event data before embedding in HTML. Add CSP headers as an additional layer of protection.
Jinja2's autoescaping feature, when enabled (Environment(autoescape=True) or using the select_autoescape helper), HTML-escapes variables automatically. If autoescaping is enabled and you are not using the |safe filter on untrusted data, Jinja2 prevents XSS. If autoescaping is disabled or you use |safe on event data, the vulnerability remains.
If the response uses Content-Type: application/json, browsers typically do not render it as HTML and XSS is unlikely. However, if the JSON response is later rendered by a client-side JavaScript framework that uses innerHTML or similar DOM manipulation without escaping, XSS can still occur on the client side. Set Content-Type correctly and avoid application/json responses with Content-Type: text/html to prevent browser misinterpretation.

New feature

Get these findings posted directly on your GitHub pull requests

The Lambda XSS via Tainted HTML Response Body rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works