How it works.
Six mechanisms, and the limit that sits next to each one. If a claim on this page is not true of the build, the page is the thing that is wrong.
The proxy, and the certificate
J0 starts listening on 127.0.0.1:9090 as the window opens. Burp uses
8080; J0 uses 9090 so the two can run side by side while you are still deciding.
There is no start button to find and no port to choose.
Interception needs a certificate authority. J0 generates one on your machine the first time it runs and serves it from a landing page at the proxy’s own address, in both PEM and DER. It is never installed into a system trust store for you — trusting a CA is a decision, and software that makes it on your behalf has taken something it was not offered.
Upstream TLS verification stays on. An intercepting proxy that silently accepts a bad certificate on the far side is teaching you that the far side is fine.
What byte-faithful means here
Duplicate headers stay duplicated. Duplicate parameters stay duplicated, in order. Binary bodies stay binary, unusual encodings survive, and cookies are not re-serialised on their way through. Anything J0 normalises or reconstructs is kept apart from the original bytes, and the interface can show you both.
This is not fussiness. A tool that quietly canonicalises a request is reporting on a request it did not send, and the moment that matters is the moment a finding turns on an encoding.
Bodies are content-addressed in the project file, so the same response captured four hundred times is stored once — faithfully, not approximately.
Whose session was that
Browse normally, as each of your accounts. J0 groups requests by the credential set that carried them and gives each group a label, a role and an organisation. There is nothing to configure and no cookie name to type, including the common case where two accounts arrive with differently named cookies.
It records cookie and header names. It does not record values, anywhere, and no part of the interface will show you one.
Values that rotate per request or stay constant across every account — load balancer cookies, device identifiers — are dropped before grouping. Without that step a single login fragments into hundreds of accounts and the whole analysis becomes noise.
Sending as somebody else
A cross-account test replaces the whole credential set, not just a cookie: cookies, authorization headers, body tokens, and anti-forgery tokens in all three carriers they travel in. Swapping a session cookie while leaving a stale CSRF token behind produces a rejection that looks exactly like a control holding, which is the most expensive false negative in this class of work.
Every send in the application goes through one function in jo-proxy.
That includes the scanner, the Repeater, the Intruder and anything an agent asks
for. One chokepoint means one place where scope, method and destructive-action
guardrails are enforced, and no second path around them.
The verdicts, in the words the application uses
Five outcomes, and the two that are not findings matter as much as the one that is.
Every number carries its bar
“Similar in shape and length” is the sentence that gets a report sent back. J0 carries the measurement that settled a finding all the way into the write-up: the size gap, the threshold it was weighed against, where that threshold came from, and how many of the owner’s identifying values came back out of how many there were.
The threshold is learned per endpoint from its own repeated reads. An endpoint that swings 19 % between two identical requests is not judged by the same bar as one that is byte-stable. Resemblance is never decisive on its own.
Before anything is reported, three probes run: an identifier that belongs to nobody, the same request repeated, and the request with every credential stripped. Then one more question — could this account have obtained that identifier at all? J0 searches the replies the account genuinely received and reports how many contained it. A searched silence, not an assumed one.
Saying what was skipped
Coverage is an output, not a footnote. Each class of check reports tested, not measured, or refused, with the reason attached — and not measured is never rendered as a pass anywhere in the application.
The same rule governs an agentic run. Every feature it walks is accounted for as tested, skipped or never reached; a refusal to touch a destructive control is written down; and a feature that broke the crawl is recorded as one rather than quietly dropped.
Findings are bucketed by what to do about them — dig, candidate, not applicable, merged — and never scored. Severity is demonstrated impact, and only somebody who knows what the data is can judge that.
Where a model stops
The agentic layer is optional and off until you turn it on. A model chooses which feature to look at and writes up what came back. It does not compose request bytes, it does not choose a payload, and it is not handed a credential value — the tool API has no shape that could return one.
That boundary is a type in the Rust engine. The send function accepts only a value that the traffic check has already minted from real captured traffic, so a string a model invented cannot be passed to it: the program would not compile. It is not a rule in a prompt that a clever prompt can talk its way around.
Live sending needs an explicit toggle. The click policy refuses destructive controls. Page reads are redacted — tokens and JWTs scrubbed, object identifiers and UUIDs deliberately kept, because those are the thing under test. Every agentic request appears in the history marked as one, with the account it ran as.
Project files
A chooser opens on every launch, Burp-style, and projects can be switched while the
application is running. A project is a single .jo file: SQLite, with
content-addressed bodies. History survives a restart because it was never in memory
only.
Captured traffic lives in that file and nowhere else. The repository’s
.gitignore excludes .jo files and their sidecars, along
with keys, certificates and HAR exports, so a project cannot be committed by
accident.
Questions
Is this a Burp replacement?
Not yet, and it is honest to say so. Phases 1 to 5 of the specification are built: proxy, storage, the manual workbench, the detection engines and the agentic layer. Burp has twenty years of extensions and a scanner J0 does not try to duplicate — J0 deliberately stays off payload scanning and spends its effort on authorization, which is the class the scanners skip.
Does anything leave my machine?
Not unless you configure a hosted model and turn it on. There is no account, no telemetry and no update check. With a local model, nothing leaves at all.
Which model does it use?
Whichever you point it at: Claude Code, any OpenAI-compatible endpoint including a local one, or none — the deterministic engine runs the same scan without a model. Keys are entered in Settings and are never written into the repository or a log.
Can I use it on a client engagement?
It is Apache-2.0 and there is nothing stopping you, but read the features page first: this is a beta verified on one operating system, and the Linux and Windows jobs in the CI matrix have not been run.
Why is it called J0?
The repository is JZero and the specification calls the project
Project Jo. The application shows J0, which is what
fits in a title bar.