A Burp Suite extension for validating HTTP requests against various strategies with deduplication and persistent result tracking.
Originally scaffolded from the PortSwigger Extension Template Project; the code below is specific to this pipeline's validation/live-testing needs.
- Quick Start
- Testing with GUI
- Validation System
- Key Development Commands
- Extension Loading in Burp
- Live testing
- Required external dependency: bulkScan
- Building the JAR file
- Loading the JAR file into Burp
# Build the extension
./gradlew jar
# Run automated tests (headless, exits after completion)
./gradlew livetesting
# Run tests with GUI (for manual validation, stays open)
./gradlew livetestingGuiBoth livetesting tasks load the freshly-built build/libs/validator.jar
automatically, via a generated Burp user-config
(build/livetesting-user-config.json, written by writeLiveTestingUserConfig).
You do not need to register the extension in Burp by hand for tests, and the
run is unaffected by whatever is registered in your personal ~/.BurpSuite
config. (The Burp jar is auto-downloaded to libs/ on first run.)
livetesting runs on Burp Suite Community (free) or Professional. downloadBurp
fetches Professional by default; pass -Dburp.product=community to fetch the free
Community jar instead (delete libs/burp.jar first if switching editions). On
Community, the handful of Pro-only tests (Collaborator, persistent project files,
scanner issue reporting) report SKIPPED (requires Burp Suite Professional) and the
suite still passes; on Professional they run in full.
livetesting validates an model_outputs_v5 corpus. It resolves which database
to use in this order:
-Dvalidator.db=<path>if set;../flamer/production.db— a real corpus, if you have run flamer and it actually containsmodel_outputs_v5rows;- otherwise a small committed seed, built from
../flamer/seed/production-seed.sql.
So ./gradlew livetesting works from a fresh clone with no flamer run: the
buildSeedDb task materializes the seed into build/seed.db via sqlite-jdbc (no
sqlite3 CLI needed) and the suite runs against it. The seed is a diverse,
target-agnostic subset (placeholder hosts only) plus the specific technique ids a
few tests look up by id. To extend it, add rows to
flamer/seed/production-seed.sql (statements are separated by lines reading
exactly --STMT--).
Note: an empty flamer/production.db (e.g. from a no-op flamer run) is treated
as absent — resolution skips it and falls back to the seed, so data-dependent
tests still pass. The task logs which database it chose (livetesting DB: ...).
(livetesting also needs a Burp jar — Community or Professional; see
Burp edition.)
When running ./gradlew livetestingGui, Burp Suite will:
- Launch with the GUI visible
- Automatically run all tests when started
- Display results in the "Validator" tab
- Stay open after tests complete for manual inspection
- You can re-run tests by clicking the "Run Tests" button in the Validator tab
This is useful for:
- Manual validation of test results
- Inspecting the database state after tests
- Debugging test failures
- Exploring the Burp Suite interface with the extension loaded
This extension validates HTTP requests from a SQLite database against configurable validation strategies:
- Read requests from
model_outputs.db - Normalize requests (remove body, set path to
/, set host toexample.com) - Detect duplicates via byte-level comparison
- Validate using pluggable strategies
- Persist results with strategy name/version tracking
- DummyValidationStrategy: Simple test strategy (POST=true, GET=false)
- HackxorValidationStrategy: Sends to https://hackxor.net/, validates on HTTP 200
The livetesting suite runs inside Burp (see Live testing) and, with the seed corpus above, passes from a fresh clone.
./gradlew clean # Clean build artifacts
./gradlew build # Build and test the extension
./gradlew jar # Create the extension JAR file
./gradlew livetesting # Run automated tests (headless, exits after completion)
./gradlew livetestingGui # Run tests with GUI for manual validation (stays open)The built JAR file will be in build/libs/validator.jar and can be loaded directly into Burp Suite.
Note: compiling this extension requires bulkScan-all.jar in the project root — see Required external dependency: bulkScan below. Full livetesting also needs a Burp Suite jar (Community or Professional — see Burp edition) and is out of scope for CI; ./gradlew jar (i.e. compilation) is the runnable proof here.
Montoya API reference: https://portswigger.github.io/burp-extensions-montoya-api/javadoc/
The extension's entry point is LiveTestingExtension.java, which implements Montoya's BurpExtension interface and wires up validation, live-testing, and the passive response watcher on load.
- Build the JAR using
./gradlew jar - In Burp: Extensions > Installed > Add > Select the JAR file
- For quick reloading during development: Ctrl/⌘ + click the Loaded checkbox
To enable the debug mode, start Burp Suite jar from libs folder with the Java VM option -Dlivetesting.debug and headless mode -Djava.awt.headless=true.
Test results will be print out to the console.
To run only a specific test class, use the -Dlivetesting.class=ClassName option. This only works in headless mode with debug enabled.
Example: java -Djava.awt.headless=true -Dlivetesting.debug -Dlivetesting.class=SimpleTest -jar your Burp Suite Pro jar
Burp's Montoya API consist of only interfaces. Concrete implementation to those interfaces are only available during runtime.
This makes unit testing hard. That is why this package livetesting exists. It enables the developer to write tests and execute them
in the "Validator" tab when in debug mode. This is useful when hunting and reproducing bugs.
In order to write new tests, create a new class that ends with "Test", like "MyTest.java". For each test case write a public method with no parameters that returns a "TestResult". The LiveTestingTab will automatically search for such methods, invoke, check and present the results in console on headless mode.
Run tests with:
- Automated (headless, exits after tests):
./gradlew livetesting - Manual validation (GUI, stays open):
./gradlew livetestingGui - Specific test class:
./gradlew livetesting -Dlivetesting.class=MyTest
To debug normalization issues, use the NormalizationInspectorTest:
./gradlew livetesting -Dlivetesting.class=NormalizationInspectorTest -Dinspect.id=123
./gradlew livetesting -Dlivetesting.class=NormalizationInspectorTest -Dinspect.ids=123,456,789When you run livetesting, if the extension is loaded by Burp it will display "Extension loaded successfully". If you do not see this message within ten seconds, treat this as a test failure and ask for a human to fix it.
This extension compiles against bulkScan-all.jar, a fat jar bundling bulkScan (a Burp bulk-scanning framework, itself dependent on the legacy Burp Extender API) together with its albinowaxUtils helper library. src/main/java/burp/BulkScanInitializer.java and src/main/java/burp/LiveTestingExtension.java reference its classes (BulkScan, BulkScanLauncher, Utilities, ConfigurableSettings, BulkUtilities, IBurpExtender, IBurpExtenderCallbacks, etc.) directly at compile time, and build.gradle.kts declares implementation(files("bulkScan-all.jar")).
The jar is not vendored in this repository (it isn't redistributable here). To build this extension:
- Build
bulkScan-all.jaryourself (a shadow/fat jar containing bulkScan plus its dependencies), the same way you would supply your own Burp Suite Pro jar forlivetesting. - Place it at the project root (
validator/bulkScan-all.jar) before running./gradlew jar.
Without it, ./gradlew jar (and even ./gradlew compileJava) fails at compilation with "cannot find symbol" errors for the classes above — this is expected until the jar is supplied.
To build the JAR file, run the following command in the root directory of this project:
- For UNIX-based systems:
./gradlew jar - For Windows systems:
gradlew jar
If successful, the JAR file is saved to <project_root_directory>/build/libs/<project_name>.jar. If the build fails, errors are shown in the console. The project name is validator. You can change this in the settings.gradle.kts file.
Note: this requires bulkScan-all.jar to be present first — see Required external dependency: bulkScan above.
To load the JAR file into Burp:
- In Burp, go to Extensions > Installed.
- Click Add.
- Under Extension details, click Select file.
- Select the JAR file you just built, then click Open.
- [Optional] Under Standard output and Standard error, choose where to save output and error messages.
- Click Next. The extension is loaded into Burp.
- Review any messages displayed in the Output and Errors tabs.
- Click Close.
Your extension is loaded and listed in the Burp extensions table. You can test its behavior and make changes to the code as necessary.
If you make changes to the code, you must rebuild the JAR file and reload your extension in Burp for the changes to take effect.
To rebuild the JAR file, follow the steps for building the JAR file.
To quickly reload your extension in Burp:
- In Burp, go to Extensions > Installed.
- Hold
Ctrlor⌘, and select the Loaded checkbox next to your extension.