# Cookie Lab The Cookie Lab decodes and unsigns vulnerable stateless session cookies using a native Rust port of [CookieMonster](https://github.com/iangcarroll/cookiemonster). Crack a single cookie in your browser — the cookie and any wordlist you load never leave the page — or queue a batch across your runners. ## What it detects Cookie Lab decodes cookies from several frameworks and then tries to recover the signing key from a wordlist: - Django - Flask and itsdangerous - Rack - Express (`cookie-session`) - Laravel - CodeIgniter - WordPress authentication cookies - Yii2 signed cookies - Spring Security remember-me cookies - raw JSON Web Tokens (HS256/HS384/HS512) A recovered key means the target signs sessions with a guessable secret, so an attacker can forge a session and impersonate any user. Report the finding and ask the owner to rotate the signing secret. ## Cookie types Pick a **Cookie type** to force one framework, or leave it on **Auto-detect**. As you paste a cookie, Cookie Lab parses it locally and shows the formats that understand it, the signing algorithm it implies, and the decoded payload — no wordlist needed. If you force a type that does not match, the lab warns you and suggests switching back to Auto-detect. The selected type is recorded with each run (for example `decoder=flask,jwt`), so the backlog shows what a run was testing instead of an opaque "auto". ## Using the lab 1. Open [Cookie Lab](/tools/cookie-lab). 2. Paste the session cookie you are authorized to test. For Express `cookie-session`, use the `name=value^signature` form. Pasting a whole `Set-Cookie` header is fine — a **strip attributes** shortcut keeps just the cookie value. 3. Choose a wordlist. A wordlist is required — Cookie Lab bundles no default list. **Auto-detect** reads either a plain-text list (one key per line) or a base64 (Flask-Unsign) list; you can force the format instead. Uploading or pasting both work, and the lab shows the detected format, entry count, and a preview. For WordPress and Spring Security the entry format differs; see below. 4. Click **Decode & crack**. ### WordPress and Spring Security wordlist entries Most frameworks use the wordlist entry directly as the signing secret. Two frameworks derive the signature from material that is not stored in the cookie: - **WordPress** derives its HMAC key from the scheme salt (`AUTH_KEY` + `AUTH_SALT`, or the `LOGGED_IN_`/`SECURE_AUTH_` pair) and a four-character fragment of the user's password hash. Use `salt:pass_frag` as the entry, or the already derived `wp_hash()` key. The entry is split on the last colon because WordPress salts may contain colons. - **Spring Security** remember-me tokens sign `username:expiry:password:key`. Use the combined `password:key` suffix as the entry; the password is usually the stored hash Spring sees. If a key is recovered, the result shows the matching decoder(s), the algorithm, the decoded payload, and the key. The optional **Resign** field re-signs a decoded Django or Flask cookie with new content. A few example cookies are built in so you can try the lab before pointing it at a target. ## Local vs runner The lab has two backends: - **In your browser** cracks a **single** cookie instantly using the Cookie Lab WebAssembly build. The cookie never leaves the browser. Cracking is single-threaded, so large wordlists are capped at 10 MB. - **On your runners** is a **queue**. Paste one cookie per line and each becomes its own run; your connected runners pull them as they free up, so a batch of 50 runs spreads across 5 runners automatically. Each row is type-checked before it is queued, and the batch summary counts the detected frameworks. The backlog lists every run with its live state, detected type, and result (the recovered key), and you can open a run to stream its output or cancel it. You can also **fetch a URL** instead of pasting cookies: the runner grabs the `Set-Cookie` headers from that URL and cracks them. A wordlist is uploaded once to object storage and shared by the whole batch. Submitting and cancelling require a token with the **Tool Runs** write scope; reading requires the read scope. The runner decodes and unsigns cookies natively — no toolchain download and no network access beyond the cookie or URL you provide. Notifications for finished runs are not wired up yet. ## Reliability Queued runs are persisted in the platform database, not a transient cache, so they survive hub and runner restarts. A run claimed by a runner carries a lease that the runner renews on its heartbeat; if the runner dies mid-run the lease expires and the run is automatically re-queued for another runner. Redis only carries wake-up notifications — a Redis restart can delay a pickup by a few seconds but never loses a run. ## Limits Tool runs are limited per plan, per account (across all your runners):
Plan Concurrent Queued Starts / min Retention
Free 5 100 15 7 days
Pro 15 500 45 30 days
Elite 40 2000 120 90 days
Extra runs wait in the queue until a slot frees. Submitting past the queue cap is rejected. Finished runs are deleted after the retention window. ## Automating it For scheduled or dataset-driven use, the same tool is available as the platform module `bountyhub/cookielab` and the `cookie-session-audit` workflow template. The module accepts `decoder` (a comma-separated format list, or `auto`) and `wordlist_format` (`base64` or `plain`) alongside `cookie`, `url`, and `wordlist`. See [Modules](/workflows/modules). ## Authorization Only test sessions you are permitted to assess. This tool exists to validate your own deployments or authorized engagement targets.