Description
JAuth stores session state in a JWT cookie. Because the token accepts alg=none, you can rewrite the payload to grant yourself admin access and bypass authentication.
Setup
Visit http://saturn.picoctf.net:<PORT_FROM_INSTANCE>/ and log in with the provided test/Test123! credentials.
Open DevTools → Application → Cookies to copy the issued JWT. It contains three base64url segments separated by dots.
Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1Decode the token
ObservationThe session cookie is a long opaque string in three dot-separated segments, which is a JWT. Decode the header and payload and see which claims control authorization.Base64-decode the first two segments. The header uses HS256 and the payload contains role:"user". Leave the signature segment blank for now.Learn more
A JSON Web Token (JWT) is a compact, URL-safe token format used for authentication and authorization. It consists of three base64url-encoded segments separated by dots:
header.payload.signature. The header specifies the token type and signing algorithm. The payload contains claims - key-value pairs likesub(subject),exp(expiration), and application-specific fields likerole. The signature proves the header and payload have not been tampered with.Base64url is a variant of standard Base64 that replaces
+with-and/with_, and omits padding (=). This makes the encoded string safe to include in URLs and cookies without percent-encoding. Decoding the token's first two segments gives you the raw JSON objects, which you can then read and modify.Tools like jwt.io (a web-based decoder) and the
jwtcommand-line tool make decoding JWTs trivial. In a CTF, quickly decoding a JWT to inspect its payload is a standard first step whenever you see a suspiciously opaque cookie or authorization header - the structure is always the same three dot-separated segments.Step 2Forge an unsigned token
ObservationThe header names HS256 and the payload carries a role claim of user. If the server honors an algorithm of none, the role rewrites to admin with no valid signature at all.Change the header to {"typ":"JWT","alg":"none"} and the payload to set "role":"admin". Base64url-encode both segments without padding and concatenate them with a trailing dot to indicate an empty signature.bashprintf '{"typ":"JWT","alg":"none"}' | base64 | tr -d '=' | tr '+/' '-_'bashprintf '{"role":"admin", ...}' | base64 | tr -d '=' | tr '+/' '-_'Expected output
eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0
What didn't work first
Tried: Omitting the trailing dot and submitting header.payload as the forged token
The spec requires three dot-separated segments, so a two-segment token is rejected as malformed before the algorithm is ever read. The trailing dot is not decoration; it is the empty signature field, and the token needs it to parse.
Tried: Using standard Base64 padding (with = characters) instead of stripping it for base64url
Cookies and URLs treat the equals sign as special, so padded base64 in a cookie value gets corrupted or rejected. Base64url strips padding entirely, and the server's decoder infers the length from the segment.
Learn more
The alg:none vulnerability is a well-known JWT flaw. The JWT specification originally allowed
"alg": "none"to indicate an unsigned token (useful in trusted, internal contexts). Vulnerable servers that accept this value skip signature verification entirely - meaning any client can forge a valid-looking token simply by setting the algorithm to none and providing no signature. The trailing dot inheader.payload.represents the empty signature field.To forge the token: encode the modified header JSON with base64url (strip padding, swap
+and/), do the same for the modified payload, then concatenate them asencodedHeader.encodedPayload.(note the trailing dot). This produces a syntactically valid JWT that many vulnerable libraries will accept as genuine because they check the algorithm field instead of enforcing that signatures are always required.This vulnerability was disclosed in 2015 and has affected real-world implementations in multiple languages. Properly hardened JWT libraries either reject
alg:noneentirely or require callers to explicitly allowlist acceptable algorithms. When reviewing any system that uses JWTs, checking that the server enforces algorithm restrictions is a standard item on the security review checklist. Related attacks include the algorithm confusion attack (switching RS256 to HS256 and signing with the public key) and header injection (pointing thejkuorx5uheader at an attacker-controlled key set).Step 3Swap the cookie
ObservationThe admin page is gated on that cookie alone. Replace it with the forged token in DevTools, reload, and the server grants admin with no further credentials.Replace the existing JWT cookie with the forged one (header.payload.) and refresh the page. The admin view appears immediately and prints the flag.Learn more
Browser DevTools (F12) provides direct access to cookies via the Application tab. You can double-click any cookie value to edit it in place, then reload the page to send the new value to the server. This is the fastest way to test JWT forgeries without writing any exploit code - the browser handles the HTTP request with the modified cookie automatically.
The fact that changing a single field in the JWT payload (
role: "user"torole: "admin") immediately grants admin access illustrates a fundamental web security principle: never trust client-supplied data for authorization decisions. The server must verify both the token's signature and that the claims it contains are legitimate. Storing authorization state in an unverified client-side token is equivalent to having no authorization at all.In a real penetration test, JWT vulnerabilities are tested using tools like jwt_tool (a dedicated JWT attack suite), Burp Suite (intercept and modify tokens in the proxy), and custom scripts. Finding that a production application accepts
alg:nonetokens would be a critical severity finding - it completely bypasses authentication and allows full privilege escalation without knowing any credentials or secrets.
Interactive tools
- JWT DecoderDecode JSON Web Tokens and inspect the header, payload, and signature. Useful for web exploitation challenges.
Alternate Solution
Paste your JWT into the JWT Decoder tool on this site to instantly see the decoded header and payload. This makes it easy to confirm the algorithm and identify which claim to modify before forging the token.
Flag
Reveal flag
picoCTF{succ3ss_@u7h3nt1c@710...4eacf}
JWTs that declare alg:"none" trust client-side data blindly, so editing the payload is enough to escalate privileges.