A PwnFox-style web security testing extension β for Chrome.
Colored containers Β· isolated cookie & storage jars Β· one-click Burp proxy Β· JS injection toolbox
PwnChrome is a Chrome alternative to PwnFox (the Firefox extension by YesWeHack). It brings the same workflow to Chromium browsers: spin up color-coded containers, log in as several users on the same site at the same time, and pipe everything through Burp with one click β each container's traffic automatically tagged for the PwnFox Burp extension.
Note
Why this is harder on Chrome. PwnFox relies on Firefox's native containers
(contextualIdentities), which give each container its own cookie jar for free. Chrome has no such
thing β there's no container API, and Manifest V3 removed blocking webRequest. So PwnChrome has to
re-engineer containers from scratch on top of declarativeNetRequest + webRequest: it controls
what each colored tab sends, captures what it receives, and emulates per-color isolation by hand.
See How it works.
Note
A container is a color. All tabs sharing a color share one cookie/storage jar. Different colors are isolated from each other. Uncolored tabs use Chrome's normal store.
- Screenshots
- Install
- Container colors
- Usage with Burp
- How it works
- Isolation: what's reliable, what's approximate
- Permissions
- Project structure
- Development & testing
- Limitations vs Firefox PwnFox
- Credits & license
Burp HTTP history, colored per container β the PwnFox Burp extension reads X-PwnFox-Color:
Popup![]() |
Options β proxy + JS toolbox![]() |
Chrome no longer loads unpacked extensions from the command line, so use the UI.
- Download
pwnchrome.zipfrom the Releases page and unzip it. - Open
chrome://extensionsand enable Developer mode (top-right). - Click Load unpacked and select the unzipped
PwnChrome/folder.
git clone https://github.com/Vozec/PwnChrome.gitThen chrome://extensions β Developer mode β Load unpacked β select the PwnChrome/ folder.
The toolbar icon is red when disabled, green when enabled. The master switch and Burp proxy are on by default, so you can start tagging tabs right away.
The color β header mapping is identical to PwnFox, so the existing Burp extension works with zero changes.
| Tab color | X-PwnFox-Color value |
|---|---|
| blue | blue |
| turquoise | cyan |
| green | green |
| yellow | yellow |
| orange | orange |
| red | red |
| pink | pink |
| purple | magenta |
βββββββββββββββ X-PwnFox-Color: red ββββββββββββββββ colored history βββββββββββ
β red tab β ββββββββββββββββββββββββΊ β β βββββββββββββββββββΊ β β
β (user 1) β isolated cookies β Burp @ :8080 β β PwnFox β
βββββββββββββββ€ β (proxy) β β (Burp β
β blue tab β ββββββββββββββββββββββββΊ β β βββββββββββββββββββΊ β ext) β
β (user 2) β X-PwnFox-Color: blue ββββββββββββββββ βββββββββββ
βββββββββββββββ isolated cookies
- Start Burp with a proxy listener on
127.0.0.1:8080(default). - Install Burp's CA certificate in Chrome (visit
http://burpβ CA Certificate) so HTTPS works. - Install the PwnFox extension in Burp (BApp Store or the repo's
burp/jar). - The master switch and Burp proxy are ON by default β just click a color to open a tagged tab.
- Open a second tab, give it a different color, log in as another user β both sessions stay separate, and Burp colors each container's requests automatically.
Chrome's MV3 constraints shape the whole design:
- No
contextualIdentities(Firefox containers) β emulate with per-color state. - No blocking
webRequestfor normal extensions β usedeclarativeNetRequest(DNR) to modify headers. - DNR modifies headers before
webRequestcan read them β so DNR can't both strip and let us readSet-Cookie. The fix is a clean split of duties:
flowchart LR
subgraph out [Outgoing request]
A[Colored tab] -->|DNR sets Cookie to jar| B[Burp / server]
A -->|DNR sets X-PwnFox-Color| B
end
subgraph in [Incoming response]
B -->|Set-Cookie| C[webRequest read-only]
C -->|store| D[(Per-color jar)]
C -->|HttpOnly: remove from shared store| E[chrome.cookies]
end
D -.->|rebuilds| F[DNR Cookie rules]
F -.-> A
Sending is fully controlled by DNR (synchronous, race-free): a catch-all remove Cookie rule gives the
tab an empty session, plus one set Cookie rule per registrable domain injecting the container's jar.
Receiving is observed by a read-only webRequest listener that captures Set-Cookie into the jar and
removes HttpOnly cookies from the shared store so they can't leak to other containers.
Storage is handled by a MAIN-world shim injected on each navigation: it namespaces
localStorage/sessionStorage by color and overrides document.cookie; an isolated-world relay.js
forwards cookie writes back to the service worker.
Important
For 100% native isolation (cookies + storage + IndexedDB + cache), use a separate Chrome profile per identity. PwnChrome emulates isolation inside a single profile β excellent for cookies, best-effort for storage.
Reliable
- Colored tabs send only their container's cookies, even with many colors active at once (DNR is synchronous).
- HttpOnly auth cookies are captured per color and kept out of the shared store.
- Same color shares a jar; different colors are isolated.
- Survives a browser restart: jars persist, and the tabβcolor map is rebuilt from the restored
π¦ <color>tab groups on startup. - HTTP cache disabled for colored tabs (
Cache-Control: no-store), so a cached resource can't leak between containers.
Approximations (by design)
| Area | Behavior |
|---|---|
| Jar keying | Keyed by registrable domain (eTLD+1 via a small built-in suffix list). A site and its subdomains share cookies; host-only cookies may be over-sent to sibling subdomains. |
Secure flag |
Not enforced on injected cookies (sent regardless of scheme) β fine for HTTPS targets. |
| Storage shim timing | Injected as early as possible per navigation, but not guaranteed before the first page script; an early localStorage/document.cookie read may briefly see the shared store. |
| HTTP cache | Not partitioned per container (the cache key ignores headers) β so it's disabled for colored tabs instead. |
| Not isolated | IndexedDB and the Cache API (service-worker caches). |
| Permission | Why |
|---|---|
declarativeNetRequest |
Inject X-PwnFox-Color and rewrite the Cookie header per container. |
webRequest |
Read-only capture of Set-Cookie from responses. |
cookies |
Remove HttpOnly container cookies from the shared store. |
proxy |
One-click Burp proxy configuration. |
scripting + webNavigation |
Inject the MAIN-world storage/cookie shim on navigation. |
tabs + tabGroups |
Map tabs to colors and show containers as colored tab groups. |
storage |
Persist config and cookie jars. |
<all_urls> |
Containers and proxy apply to any site under test. |
PwnChrome/
βββ manifest.json # MV3 manifest
βββ icons/ # generated PNGs (gen_icons.py) + green/red status variants
βββ src/
βββ config.js # shared config + color definitions
βββ cookies.js # cookie engine: parse/serialize, jar, registrable domain
βββ background.js # service worker: DNR rules, cookie capture, proxy, shim, icon
βββ inject.js # content script: toolbox injection
βββ relay.js # content script: relays document.cookie writes to the SW
βββ popup/ # toolbar popup (containers, isolation toggles, proxy)
βββ options/ # proxy host/port + toolbox editor
The cookie engine and the service-worker logic are pure enough to test in Node with a stubbed chrome API
(no browser needed):
src/cookies.jsβSet-Cookieparsing, eTLD+1, jar merge/expiry, HttpOnly exclusion fromdocument.cookie.src/background.jsβ DNR rule construction,Set-Cookiecapture β jar β rule rebuild, HttpOnly removal, multi-tab sharing per color, simultaneous distinct sessions across colors, restart reconcile,clearJar.
Regenerate the icons after editing gen_icons.py:
python3 icons/gen_icons.pyWarning
Live end-to-end testing via --load-extension is blocked on recent Chrome builds (the switch is ignored).
Load the extension through chrome://extensions and verify behavior manually, or use the stubbed-chrome
Node harness for logic.
| Firefox PwnFox | PwnChrome | |
|---|---|---|
| Containers | Native contextualIdentities |
Emulated per color |
| Cookie isolation | Native, perfect | DNR + webRequest (robust, eTLD+1-keyed) |
| Storage isolation | Native | MAIN-world shim (best-effort) |
| HTTP cache | Isolated | Disabled for containers (can't be partitioned) |
| IndexedDB / Cache API | Isolated | Not isolated (use separate profiles) |
| Proxy scope | Per-request (per container possible) | Global only β Chrome has no per-tab proxy API |
X-PwnFox-Color |
yes | yes β identical mapping |
| Remove security headers | yes | not included |
| postMessage logger | yes | not included |
Proxy is global in Chrome:
chrome.proxy.onRequestis Firefox-only and PAC scripts can't see tab IDs. When the proxy is on, all traffic goes through Burp β the color header still separates containers Burp-side.
- Inspired by and interoperable with PwnFox by YesWeHack β the
X-PwnFox-Colorheader and Burp extension are theirs. - Built for the Chromium/MV3 platform.
Use only against systems you are authorized to test.


