Shazzer User Guide
What is Shazzer?
Shazzer is a shared online fuzzing platform for browser behavior testing. It enables security researchers to create, share, and run fuzz tests across different browsers to discover parsing quirks, JavaScript syntax variations, and potential security issues.
Whether you're researching XSS bypasses, exploring HTML parsing differences between browsers, or testing JavaScript edge cases, Shazzer provides the tools and infrastructure to systematically test thousands of character combinations across multiple browsers simultaneously.
Key Features
Distributed Fuzzing Network
Shazzer's distributed fuzzing network allows you to run your fuzz tests across real browsers connected from around the world. Instead of testing only in your local browser, your vectors can be executed on Chrome, Firefox, Safari, and Microsoft Edge simultaneously.
- Real-time browser connections - Connected browsers receive and execute fuzzing tasks automatically
- Multi-browser results - Compare how different browsers handle the same fuzzing template
- Network dashboard - View connected browsers, their versions, and current activity in real-time
- Automatic task distribution - Vectors needing results are automatically dispatched to available browsers
Visit the Network page to see connected browsers and monitor fuzzing activity. You can also contribute your own browser to the network to help run tests.
Personal Fuzzing Network
The public network runs everyone's vectors on whichever browsers happen to be idle, so a result for your vector arrives when the network gets to it. A personal fuzzing network is just your own browsers. Log in to Shazzer on Chrome, Firefox, Safari and Edge, join your network from each one, and one press of Fuzz or Test fuzz in any of them runs the vector in all of them at once, with every browser's results side by side.
Setting it up takes three steps:
- Create it once for your account, from the Personal network section of the fuzzing widget in the bottom-right corner or from Settings. The browser you create it from joins automatically.
- Join from each other browser you want to include. Log in there, open the same widget and press Join personal fuzzing network. Joining is per browser, so a browser you have not joined from stays out until you do.
- Fuzz as normal. Press Fuzz, Run, Test fuzz or Test Run on any vector page or in the editor. The browser you pressed it in runs the vector as it always did, and your other connected browsers run it at the same time.
How it behaves:
- Results land in the same toast. Your own browser's results appear first, and each other browser's results appear under Your other browsers as they finish. Timings, errors and "no results" are reported per browser.
- Fuzz and Run save; Test fuzz and Test Run do not. Fuzz saves every browser's result to the vector in one go, exactly as if you had pressed Fuzz in each browser yourself. Test fuzz shows you the results and saves nothing, which also makes it work on an unsaved vector in the editor.
- One run per browser and operating system. The network hands each fuzz to one peer per distinct browser, operating system and platform. A second tab, or a second window, of the same browser on the same machine is not another peer, and the browser you pressed the button in is never sent its own fuzz.
- Who is connected. The widget lists every browser in your network and whether it is idle, fuzzing, in the background or a launcher window. Within each browser a visible idle tab is chosen first, and a background tab only when nothing else is available. A background tab cannot render fuzzing frames, so a browser whose only tab is hidden may report fewer matches for render-dependent vectors. Keep each browser visible, or open its fuzz launcher.
- Private. Each account gets its own room, entered only with a short-lived signed token from your login, and it never touches the public network: nothing you fuzz this way is handed to anyone else's browser, and results are saved by your own browsers with your own session.
- Switching it off. Leave in the widget removes one browser. The toggle in Settings disables the network for your whole account; browsers already connected stay until they next reconnect, then are refused.
Fuzzing Basket
The basket runs many vectors across your personal network in one go. It needs a connected personal network, so set that up first.
- Fill it. Every vector list has a checkbox per row and a select-all in its header, and the feed, search, profile and collection cards and the vector page have an Add to basket button. The basket is kept in your browser, per account, so it survives navigation and a reload. It holds up to 50 vectors.
- Fuzz all. A bar at the bottom of the screen shows how many vectors are in the basket. Press Fuzz all to send it. If the button is greyed out, hover it to see why: usually the personal network is not created, not joined or not yet connected.
- Watch the progress drawer. It opens on the right with one row per vector and one column per browser, each cell showing queued, running, saved, no results, error, timed out or disconnected. Hide it and reopen it from the bar's Progress button, or press Cancel to drop everything still queued.
How it behaves:
- Every browser gets every vector, including the one you pressed Fuzz all in. Each browser works through its own queue one vector at a time and only while it is idle, so a basket never interrupts a fuzz already running in that browser. Pressing Fuzz on a single vector while a basket is running takes priority: the interrupted basket item goes back to the front of the queue.
- Results are saved like a normal Fuzz. Each browser saves its own result to each vector as it finishes, so the vector pages fill in while the basket runs. The fuzz amount setting you have chosen applies to every item.
- Some vectors are skipped. Vectors that are quarantined, no longer visible to you, over the fuzzing limits, or whose data sets have been deleted are listed under Not fuzzed in the drawer instead of stopping the rest. Vectors that report over the network are not handed to a browser whose tab is hidden, because a hidden tab cannot observe them; they wait for that browser to become visible.
- Giving up. A vector that times out is marked as such and not retried. A browser that disconnects for two minutes gives up its remaining queue as disconnected; the other browsers carry on.
Teams
Teams allow you to collaborate with other researchers on shared fuzzing projects. Each team gets its own private fuzzing network and shared vector collection.
- Team networks - Each team has a dedicated fuzzing network isolated from the public network
- Shared vectors - Assign your vectors to teams so all members can view and run them
- Member management - Invite collaborators and manage team membership
- Private collaboration - Work on sensitive research without exposing vectors publicly
Community Features
Shazzer includes social features to help you discover and share research:
- Follow researchers - Follow other users to stay updated on their vectors
- Like vectors - Save interesting vectors to your liked collection
- Notifications - Get notified about activity related to your vectors and follows
- Categories - Browse vectors organized by topic (HTML Parsing, JavaScript Syntax, XSS Execution, etc.)
MCP API Integration
Shazzer provides API access for programmatic fuzzing through MCP (Model Context Protocol) via the shazzer-mcp server. This lets AI assistants such as Claude Desktop and Claude Code work with Shazzer. The server exposes four tools:
- create_template - Create a new fuzz template. Public templates are automatically picked up and run by the distributed fuzzing network.
- find_templates - Search public templates by keyword, type, or category.
- get_results - Retrieve fuzz results for a template, by id or search query.
- view_network - See which browsers are connected and whether your own templates have been picked up by the network.
API keys carry two scopes: read (find templates, get results, view network) and author (create templates). Grant a key only the scopes it needs.
For safety, the MCP server is read-and-author only โ it cannot run arbitrary code or ad-hoc fuzz on the network. Public templates you create run exactly like any template submitted through the website.
Create an API key and find the Claude Desktop / Claude Code setup instructions on your Settings page.
Creating Vectors
Shazzer offers six vector types. Three are character-fuzzing types โ HTML, JS, and XSS โ which create a vector and test it using the test button on the new vector screen. They operate by executing a comprehensive loop with the template and replacing any placeholders.
The other three run the template once per browser rather than looping over a range of characters. Performance vectors record how long code takes to run and Feature vectors record whether a capability is supported; both are collated across browsers on the Stats page. Single execution vectors run arbitrary code once and log whatever it finds โ the mode for enumerating things rather than sweeping characters.
HTML Vectors
To create an HTML vector, select HTML from the dropdown menu. The testing options will be tailored to the HTML vector type. A special tag, "<found>", triggers Shazzer to log the result when detected. If you wish to test if characters within a style attribute were successful, you can utilize the style attribute and set the color property to "red". Shazzer will log the result upon detecting the color red.
Example using <found>:
<!----$[chr]><found>Example using style:
<div style="/**$[chr]color:red;">test</div>JS Vectors
JS vectors also incorporate a loop, where you should employ the log($[i]) placeholder to log the result. For instance, if you aim to identify which characters are permissible before parentheses in a function call:log$[chr]($[i])
XSS Vectors
XSS vectors resemble JS vectors but additionally permit HTML usage. You should utilize the same placeholders as you would for JS, but apply XSS vectors to determine if characters are logged. Here's an example XSS vector:<img src $[chr]onerror=log($[i])>
The onerror attribute will trigger when the characters preceding it are ignored.
URL Fuzzing
URL fuzzing uses CSP (Content Security Policy) violation events to determine if a fuzz was successful. When a resource URL is allowed by the browser, a CSP violation is triggered against a restrictive policy, which Shazzer uses to detect and log successful results.
For example, to find which characters are allowed before the src attribute:
<img $[chr]src=https://fuzz.shazzer.co.uk/$[rand]?$[i]>The URL fuzzing button on the vector add/edit page allows you to configure different fuzzing URLs. Each URL uses a different placeholder to identify which iteration or data value triggered the result:
https://fuzz.shazzer.co.uk/$[rand]?$[i]- Logs the iteration numberhttps://fuzz.shazzer.co.uk/$[rand]?$[j]- Logs the second loop iteration numberhttps://fuzz.shazzer.co.uk/$[rand]?$[data1]- Logs the value from the first data arrayhttps://fuzz.shazzer.co.uk/$[rand]?$[data2]- Logs the value from the second data array
Performance Vectors
Performance vectors benchmark JavaScript across browsers so you can see how fast a piece of code runs in Chrome, Firefox, Safari, and Microsoft Edge. Select Performance from the type dropdown. Unlike the fuzzing types, there are no $[chr]/$[i] placeholders โ the snippet is run once per browser and timed.
- Snippet A (the vector field) is the code to benchmark, e.g.
s.startsWith("hello"). - Snippet B (optional) lets you compare two approaches. Provide it to run an A/B comparison โ e.g.
startsWithvs a regular expression โ or leave it empty to simply time a single function. - Shared setup (initCode, under Advanced Options) declares variables both snippets can use, e.g.
var s = "hello world";. You can also setvar iterations = 2000000;here to control how many times each snippet runs per trial.
Each browser warms the code up, then runs several timed trials and reports the median time (in milliseconds, so lower is faster). When both snippets are present, the faster one is highlighted per browser. Because a browser can always pick whichever snippet is faster, the cross-browser ranking uses each browser's best time โ so a browser can rank first via Snippet B even if it's slower at Snippet A. Results are aggregated on the Stats โ Performance page, which shows which browser is fastest for each operation, an overall win tally, and a normalized performance index.
Feature Vectors
Feature vectors detect whether a browser supports a given capability. Select Feature from the type dropdown and provide a detection snippet that evaluates to a truthy value when the feature is supported. Like performance vectors, the snippet runs once per browser (no placeholder loop).
Example detection snippets:
CSS.supports("selector(:has(a))")โ the CSS:has()selectortypeof [].at === "function"โArray.prototype.at()typeof structuredClone === "function"โ the globalstructuredClone()
Each browser records a simple supported / not-supported result (a thrown error counts as not supported). Results are aggregated on the Stats โ Features page, which shows a support matrix, which browser supports the most features, features supported by only one browser, and features no browser supports.
Single Execution Vectors
Single execution vectors run your code exactly once per browser instead of sweeping code points. Select Single execution from the type dropdown. This is the mode for a vector that enumerates rather than sweeps โ every on* property on window, every property that leaks the parent URL โ where the answer does not depend on a character and there is nothing to iterate.
Record each result with log(). A single execution vector can log many results from one run; each is stored against the browser that produced it, so the vector page shows which browsers exposed which values.
Example:
Object.getOwnPropertyNames(window).filter(p => p.startsWith("on")).forEach(p => log(p))- The vector field is the code to execute. It is wrapped in a
try/catch, so a throw simply ends the run with whatever was logged before it. - Code to execute before the run (under Advanced Options) is optional setup. Declarations made here are in scope for the template and the teardown.
- Code to execute after the run is optional teardown, run last.
Placeholders such as $[chr] and $[i] don't apply โ there is no iteration for them to refer to. Use this type rather than a JS vector with a constant template: a JS vector repeats its setup code in every chunk of the sweep, so an enumerating vector would log its whole set many times over and be rejected for producing too many results.
Placeholders
Placeholders allow users to substitute text in their template with generated characters in a loop. Currently, Shazzer supports many placeholders:
log($[i])This placeholder logs the number of the current iteration of the loop and is commonly used in JS and XSS vector types.
$[i]This placeholder also logs the number of the current iteration of the loop.
$[chr]This placeholder generates a character based on the current iteration number.
<found>When this special tag is detected, Shazzer will log the result.
List of all placeholders
- $[i] - This placeholder produces the current iteration number
- $[j] - This placeholder produces the current iteration number from the second loop
- $[chr] - This placeholder produces the current character
- $[rand] - This placeholder inserts a random string
- $[hex2] - This placeholder inserts a hex string with a length of 2
- $[hex4] - This placeholder inserts a hex string with a length of 4
- $[data1] - This placeholder produces the data specified in the first dropdown
- $[data2] - This placeholder produces the data specified in the second dropdown
- <found> - This placeholder causes a log when the tag is found
- <notfound> - This placeholder causes a log when the tag is not found
- log($[i]) - This placeholder causes the log function to execute with the current iteration number
- log('$[data1]') - This placeholder causes the log function to execute with data in the first dropdown
- log('$[data2]') - This placeholder causes the log function to execute with data in the second dropdown
- urlenc($[chr]) - This placeholder produces the character from the current iteration and url encodes it
- html($[chr]) - This placeholder produces the character from the current iteration and HTML encodes it
- json($[chr]) - This placeholder produces the character from the current iteration and unicode escapes it
- urlenc($[data1]) - This placeholder produces data in the first dropdown and url encodes it
- html($[data1]) - This placeholder produces data in the first dropdown and HTML encodes it
- json($[data1]) - This placeholder produces data in the first dropdown and unicode escapes it
- urlenc($[data2]) - This placeholder produces data in the second dropdown and url encodes it
- html($[data2]) - This placeholder produces data in the second dropdown and HTML encodes it
- json($[data2]) - This placeholder produces data in the second dropdown and unicode escapes it
- $[bytes:deadbeef] - This placeholder allows you to insert bytes
- $[unicode:U+10FFFF] - This placeholder allows you to insert a unicode character
Custom Data Arrays
In addition to character-based fuzzing, you can create custom data arrays to test specific values like HTML tags, event handlers, or attribute names. Create data arrays data section and reference them in vectors using:
$[data1]- First data array$[data2]- Second data array
This is useful for testing which HTML elements support certain attributes, or which event handlers are valid in specific contexts.
Comparing Browser Differences
The Differences page shows vectors where browsers behave differently. This is invaluable for finding browser-specific parsing quirks that could lead to security bypasses. For example, a character that's ignored in Chrome but significant in Firefox could be used to craft browser-specific payloads.
Tools
Shazzer provides additional tools to aid your research:
- Unicode Table - Browse and search Unicode characters, useful for identifying characters to test
- Cheat Sheet - Quick reference for XSS payloads and techniques
Tips for Effective Fuzzing
- Start with a small code point range to test your vector logic before running full fuzzes
- Use descriptive names and descriptions for your vectors so others can understand and benefit from your research
- Check the Differences page to see which of your vectors reveal interesting browser variations
- Contribute your browser to the network to help the community and earn fuzzing results on your own vectors
- Use private vectors for sensitive research, then make them public once published
- Log in on every browser you have and create a personal fuzzing network, so one Fuzz gives you every browser's answer at once instead of waiting for the public network