Documentation · v1.0.0

burp2model

burp2model turns Burp traffic into an evidence-backed model of a web app. It is a model builder, not a scanner.

  • Pure Python, no runtime dependencies. It never replays your capture.
  • Every node and edge cites the requests it came from (ev_N).
  • Secret values are masked before anything is written.
  • It names what the capture could not tell you, and never calls anything a vulnerability.

Install #

Python 3.9 or newer.

shell
pip install burp2model
burp2model --version

From source: pip install -e ".[dev]", then pytest -q (288 tests).

Quickstart #

In Burp, open Proxy → HTTP history, select all, right-click, Save items. Keep base64 encoding on. Burp Community works. Only capture traffic you are authorized to record.

shell
# build: writes burp2model-out/shop/
burp2model history.xml --webapp shop

# ask: no AI, every line cited
burp2model query shop "code vs runtime"
burp2model query shop help

# two accounts: one build per role, then compare
burp2model user.xml  -w shop --role user
burp2model admin.xml -w shop --role admin
burp2model cross-role shop --low user --high admin

No Burp? burp2model crawl URL --yes -w shop crawls a running app and builds the same model. It sends live requests, so use it only on apps you are authorized to test. --read-only blocks anything but GET, HEAD and OPTIONS.

Output of query shop "code vs runtime" on the bundled sample:

APIs: 10 endpoints
  BOTH         6
  STATIC_ONLY  1
  RUNTIME_ONLY 3
    static-only  * /api/admin/audit  ev_3

STATIC_ONLY means the code names the path but the capture never requested it. The * means the code gave no HTTP method, so none is guessed.

Outputs #

Every build writes burp2model-out/WEBAPP/. The default --webapp name is app.

FileWhat it is
report.htmlOffline dashboard with a map, a query console and an evidence drawer. Demo
model.jsonThe full graph, unknowns and the evidence table. Example
context.jsonA compact package of the model. Example
graph.dbOne SQLite file with the graph and redacted exchanges. burp2model q WEBAPP queries it.
graph.json · graph.graphmlThe graph for D3, Cytoscape, Gephi and yEd.
build.svgThe build animation.
inputs/<role>.jsonlRedacted per-role records. Role builds merge from these.

By default a build also runs light recon on the primary public host and saves osint.json. It fails soft. Use --no-osint or BURP2MODEL_OFFLINE=1 to stay offline.

The six layers #

6unknownsNamed blind spots, each with a next step.
5trustthird_party, role, auth, cookie
4apisendpoint, parameter, operation (GraphQL)
3codescript, plus the workers it spawns and the source map it names.
2routesroute: pages, redirects and other GET resources
1edgehost: schemes, ports, server headers
  • Every edge is OBSERVED (seen in traffic) or INFERRED (read from code). Recon edges are EXTERNAL.
  • Layer 3: a script that starts a worker gets a SPAWNS edge (inferred). A script that names a source map gets a sourcemap attribute. If the map is not in the capture, the model raises the unknown SOURCE_MAP_NOT_CAPTURED.
  • Reconciliation compares endpoints named in code with endpoints seen at runtime: BOTH, STATIC_ONLY or RUNTIME_ONLY.
  • Scope: the busiest host sets the first-party domain (by Public Suffix List). Everything else is a third party. Override with --scope.
  • Unknowns include AUTHENTICATED_STATE_NOT_OBSERVED, ROLE_NOT_TAGGED, API_PURPOSE_UNKNOWN, AUTHORIZATION_UNKNOWN and CAPTURE_ITEMS_SKIPPED.
i

An absence in the model is an absence in the capture, not a statement about the target.

Query intents #

burp2model query WEBAPP "INTENT" answers from the model with no language model. Every line is cited and ends with Model call: none.

IntentAnswers
list-apisEvery endpoint with state, statuses and evidence.
reconcileCode vs runtime counts. code vs runtime also works.
list-routesEvery route.
route-apis /xThe APIs a route calls, directly or through its scripts.
provenance /api/ordersWhere an endpoint was seen: evidence, statuses, roles, callers.
third-partiesOff-scope hosts.
auth-surfaceCredentials, roles and cookie flags.
unknownsWhat the capture could not answer.
entity-evidence NAMEThe evidence ids behind any node, by label.

Also available: parameters, secrets (masked), privileged, errors and shape. Any question that matches no intent is refused, not guessed.

For filters over graph.db, use burp2model q WEBAPP 'req.method:POST AND resp.code.gte:400'. q WEBAPP help lists the language.

Redaction #

Before an exchange leaves the parser, every value is masked and every name and shape is kept. password=hunter2 becomes password=[REDACTED].

  • Headers such as Authorization, Cookie and Set-Cookie.
  • Sensitive parameter names, plus JWTs, API keys, private keys, card numbers and emails wherever they appear.
  • Value-like URL segments: /reset/alice@corp.com/Zx9kQ2pLm7Rt becomes /reset/{email}/{token}.

Bodies are never written to disk. A masked value is kept only as a keyed HMAC fingerprint (kind, length, entropy, count). The key lives at ~/.config/burp2model/fingerprint.key. Tests check that no planted secret reaches any output file. The HTML report escapes every string from the target and blocks network requests with a strict CSP.

Limits #

  • Endpoint extraction from code is pattern-based, not a JavaScript parser. URLs built at runtime can be missed.
  • Path-token masking uses shape and entropy. A short token can survive, and an odd slug can be masked.
  • Default scope uses the busiest host. A capture dominated by a CDN can pick the wrong site. Use --scope.
  • "Privileged-looking" in cross-role is a path-name heuristic.
  • Page-to-API edges depend on the Referer header. Strict policies give fewer CALLS edges.
  • The model covers only what was captured. Nothing it reports is a finding.

FAQ #

Is this a scanner?

No. It reads a capture you already made. It never sends requests to build a model from a Burp export. Only crawl, osint and the default build recon touch the network.

Is it safe to share the outputs?

They hold no secret values or bodies. They do hold hostnames, paths and parameter names, so treat them as engagement material. Never share the fingerprint key.

My API subdomain shows as a third party.

It is under a different registrable domain. Pass --scope with both domains.

cross-role says a role is missing.

Build each capture with --role into the same --out and --webapp. A build without --role starts over.

Can I open graph.db directly?

Yes. It is plain SQLite. burp2model q WEBAPP schema lists the tables.