MEDIUM clickjackingfastapipython

Clickjacking in Fastapi (Python)

Clickjacking in Fastapi with Python — how this specific combination creates or exposes the vulnerability

Clickjacking is a client-side injection vulnerability that manipulates a user into interacting with a hidden UI element inside an iframe. In a Fastapi application built with Python, the risk arises when the app serves HTML responses that do not prevent framing by browsers. If Fastapi endpoints render pages that can be loaded inside an <iframe> without explicit anti-clickjacking controls, an attacker can embed the app’s UI on a malicious site and overlay invisible controls, leading to unauthorized actions or credential theft.

Python web frameworks like Fastapi do not set default frame-protection headers; this is a language/framework-agnostic omission, not a bug in Python itself. When developers build UI endpoints (e.g., using templates or returning HTML directly) and neglect Content-Security-Policy frame-ancestors or X-Frame-Options, the unauthenticated attack surface includes clickjacking. middleBrick’s 12 security checks run in parallel and include an Authentication check and related UI/behavior tests that can surface missing frame-protection headers as part of the unauthenticated scan. The scanner does not execute JavaScript or simulate browsers, so it identifies whether headers and CSP directives are present that a browser would use to block framing, rather than testing exploitability via a live browser.

Because Fastapi often serves both API and HTML (for example, using templates or static files), developers must explicitly opt in to frame protection. Without a strict Content-Security-Policy with frame-ancestors or an X-Frame-Options header, a page served by Fastapi can be framed by any origin. This exposes users to tricks such as invisible like buttons, fake profile updates, or hidden form submissions when the victim is authenticated to the Fastapi app. The vulnerability is not in Python syntax but in the missing security headers and relaxed CSP policies that Python developers must configure intentionally.

Python-Specific Remediation in Fastapi — concrete code fixes

To remediate clickjacking in Fastapi with Python, set HTTP headers that instruct browsers not to allow framing. The most robust approach is a strict Content-Security-Policy frame-ancestors directive, optionally complemented by X-Frame-Options for legacy browser compatibility. Below are concrete, working examples using Fastapi dependencies and response middleware.

Middleware approach (applies to all responses)

from fastapi import Fastapi, Request
from fastapi.responses import HTMLResponse
from fastapi.middleware import Middleware
from fastapi.middleware.base import BaseHTTPMiddleware

class FrameProtectionMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        response = await call_next(request)
        # Content-Security-Policy frame-ancestors 'none' prevents all framing
        response.headers["Content-Security-Policy"] = "frame-ancestors 'none'"
        # Legacy header for older browsers
        response.headers["X-Frame-Options"] = "DENY"
        return response

app = Fastapi(middleware=[Middleware(FrameProtectionMiddleware)])

@app.get("/")
async def read_root():
    return {"message": "protected"}

Per-route with custom response (selective protection)

from fastapi import Fastapi
from fastapi.responses import HTMLResponse

app = Fastapi()

@app.get("/public-page", response_class=HTMLResponse)
async def public_page():
    html = """
    
    
      
        
        Protected
      
      
        

No framing allowed

""" response = HTMLResponse(content=html) response.headers["X-Frame-Options"] = "DENY" return response

Dynamic policy based on route or role

from fastapi import Fastapi, Depends
from fastapi.responses import HTMLResponse

app = Fastapi()

def get_frame_policy(strict: bool = True) -> str:
    return "frame-ancestors 'none'" if strict else "frame-ancestors 'self'"

@app.get("/settings", response_class=HTMLResponse)
async def settings_page():
    policy = get_frame_policy(strict=True)
    html = f''
    response = HTMLResponse(content=html)
    response.headers["X-Frame-Options"] = "DENY"
    return response

These examples ensure that browsers will refuse to render the Fastapi app inside an iframe unless explicitly allowed. For SPAs or hybrid apps, adjust frame-ancestors to trusted origins (e.g., frame-ancestors 'self' https://trusted.example.com) rather than using 'unsafe-inline' or overly permissive rules. middleBrick’s OpenAPI/Swagger analysis can validate that these headers are present in unauthenticated scans, and the Pro plan’s continuous monitoring can alert you if a future change removes frame protection.

Frequently Asked Questions

Does Clickjacking require authentication to exploit in a Fastapi app?
No, clickjacking is typically unauthenticated. It relies on the victim being logged in separately; the attack embeds the Fastapi UI in a malicious page to trick users into interacting with hidden elements. Missing frame-protection headers enable the framing regardless of authentication state.
Can CSP frame-ancestors alone replace X-Frame-Options in Fastapi?
CSP frame-ancestors is the modern mechanism and can be sufficient, but it’s best to include both CSP frame-ancestors and X-Frame-Options for broader browser coverage. middleBrick’s scans check for both headers and report when essential protections are missing.