HIGH xss cross site scriptingfastapidynamodb

Xss Cross Site Scripting in Fastapi with Dynamodb

Xss Cross Site Scripting in Fastapi with Dynamodb — how this specific combination creates or exposes the vulnerability

Cross-site scripting (XSS) in a FastAPI application that uses DynamoDB typically arises when untrusted data is rendered in HTML, JavaScript, or URL contexts without proper encoding or validation. Even though DynamoDB is a NoSQL database and does not execute code, it can store user-controlled content that later becomes injected into responses. In FastAPI, routes often serialize DynamoDB item attributes directly into JSON or templates; if those values contain strings like <script> or event handlers, and the frontend inserts them into the DOM without escaping, stored XSS can occur.

Consider a profile endpoint that retrieves user bio text from DynamoDB and returns it as JSON. If the bio includes <img src=x onerror=alert(1)>, and the frontend places that string into innerHTML, the payload executes in the victim’s browser. Because DynamoDB does not enforce a schema, fields intended to be plain text may inadvertently contain HTML or script-like content, especially when third-party sources supply the data. The risk is compounded when the same data is used in multiple contexts—HTML, attribute, and JavaScript—without context-aware encoding.

Another common pattern involves query parameters that are stored in DynamoDB and later reflected in rendered pages. For example, a search term saved to DynamoDB might be echoed back in a results page. If the reflection does not apply context-specific escaping (HTML, JS URL, CSS), an attacker can supply a payload such as <svg onload=alert(document.cookie)> and achieve reflected XSS. MiddleBrick’s checks for Input Validation and Data Exposure highlight cases where untrusted data reaches the client without sufficient sanitization or encoding.

Additional exposure can occur through administrative or debug endpoints that fetch items from DynamoDB and render them in HTML for troubleshooting. Without strict output encoding and a clear separation between data and markup, these paths become inadvertent injection channels. Because FastAPI’s default response models often mirror DynamoDB attribute names directly, developers may overlook the need for serialization layers that enforce safe escaping for each output context.

Dynamodb-Specific Remediation in Fastapi — concrete code fixes

Remediation centers on ensuring that any data retrieved from DynamoDB is treated as untrusted and is appropriately encoded for the context where it is used. Below are concrete code examples for a FastAPI endpoint that reads and writes to DynamoDB while mitigating XSS.

Safe retrieval and JSON response

Use a Pydantic model to control serialization and avoid exposing raw attribute names that may contain unexpected HTML. Apply HTML escaping only when rendering in templates; for JSON, ensure the frontend does not set innerHTML with user-controlled strings.

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
import boto3
from html import escape

app = FastAPI()
dynamodb = boto3.resource("dynamodb", region_name="us-east-1")
table = dynamodb.Table("UserProfiles")

class UserProfile(BaseModel):
    user_id: str
    username: str
    bio: str  # treat as plain text, encode on output when necessary

@app.get("/profiles/{user_id}", response_model=UserProfile)
def get_profile(user_id: str):
    resp = table.get_item(Key={"user_id": user_id})
    item = resp.get("Item")
    if not item:
        raise HTTPException(status_code=404, detail="Not found")
    # Escape only when you control the rendering context; for JSON, ensure client does not use innerHTML
    safe_bio = escape(item.get("bio", ""))
    return UserProfile(user_id=item["user_id"], username=item["username"], bio=safe_bio)

Safe storage with input normalization

Normalize and validate input before writing to DynamoDB. Strip or encode potentially dangerous sequences for your use case, and prefer allowlists for known-safe patterns.

import re
from fastapi import HTTPException

def normalize_bio(raw_bio: str) -> str:
    # Remove script-like patterns and allow basic formatting only
    cleaned = re.sub(r"<script[^>]*>.*?</script>", "", raw_bio, flags=re.IGNORECASE | re.DOTALL)
    cleaned = re.sub(r"on\w+\s*=", "", cleaned, flags=re.IGNORECASE)
    cleaned = escape(cleaned)  # HTML-escape on input for text fields
    return cleaned.strip()

@app.post("/profiles")
def create_profile(profile: UserProfile):
    safe_bio = normalize_bio(profile.bio)
    table.put_item(Item={"user_id": profile.user_id, "username": profile.username, "bio": safe_bio})
    return {"status": "ok"}

Template rendering with autoescape

If you render DynamoDB data in HTML templates, use an autoescaping engine and pass data as structured objects, not raw strings concatenated into HTML.

from fastapi import FastAPI, Request
from fastapi.templating import jinja2
import boto3

app = FastAPI()
app.add_template_engine(jinja2.Jinja2Templates(directory="templates"))

table = boto3.resource("dynamodb", region_name="us-east-1").Table("UserProfiles")

@app.get("/profiles/{user_id}/page")
def profile_page(request: Request, user_id: str):
    resp = table.get_item(Key={"user_id": user_id})
    item = resp.get("Item")
    # Templates should autoescape; do not mark safe unless you trust the content
    return templates.TemplateResponse("profile.html", {"request": request, "profile": item})

Context-aware encoding for reflected values

When reflecting query parameters or stored values in different contexts, apply encoding specific to that context. Below is a simplified example for HTML body context and a JavaScript URL context.

from html import escape
import urllib.parse

# HTML body context
safe_for_html = escape(user_controlled_string, quote=True)

# JavaScript URL context: encodeURIComponent
safe_for_js_url = urllib.parse.quote(user_controlled_string, safe="")

These patterns ensure that even when DynamoDB holds data used in multiple contexts, FastAPI responses do not introduce executable script through injection points.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Does DynamoDB sanitization alone prevent XSS in FastAPI?
No. Sanitization at the database layer reduces risk, but XSS is ultimately a client-side issue. You must apply context-aware escaping in FastAPI responses and ensure frontend rendering does not treat untrusted data as HTML.
Should I store pre-escaped HTML in DynamoDB for FastAPI?
Generally no. Store raw text and apply escaping at the rendering layer based on context. Storing pre-escaped HTML makes it harder to change output formats and can double-escape content, leading to usability issues.