Skip to main content

SAD: Statistic API Discovery

SAD is a Python library and CLI for evidence-backed static discovery of frontend API operations, including operations absent from captured traffic. Intended for authorized application analysis and security testing. Target JavaScript is never executed.

Status: early release, with a bounded abstract interpreter and explicit coverage limits; not a claim of complete JavaScript semantics or exhaustive discovery.

Install

Requires Python 3.11+. From this repository:

pip install .
# Contributors
pip install -e '.[dev]'

The PyPI distribution name is sad-py; the Python import and executable are sad. Once published, install it with pip install sad-py. No release has been published by this repository setup.

Python

from sad import Analyzer
from sad.ingest import BurpImporter

analyzer = Analyzer()
result = analyzer.analyze_url("https://example.com")
for endpoint in result.endpoints:
    print(endpoint.method, endpoint.url, endpoint.evidence)

result = analyzer.analyze_dataset(BurpImporter.from_xml("history.xml"))
result = analyzer.analyze_js('fetch(`/users/${id}`, {method: "DELETE"})')
result = analyzer.analyze_path("./assets")

CLI

sad crawl https://example.com --depth 2 --max-pages 30
sad analyze ./assets --format json
sad analyze-js app.js --base-url https://example.com
sad import-burp history.xml --format jsonl
sad import-burp requests.json --format csv
sad import-burp traffic.har
sad import-burp request.http --base-url https://example.com

The crawler follows canonical redirects of the starting URL between a host and its www variant, and from HTTP to HTTPS on standard ports. It adds the redirected origin to the collection scope so its pages and scripts can be collected. Other origins require explicit scope configuration through --allow-origin or CrawlConfig.allowed_origins; exclusions and redirect limits still apply. Discovering an API never causes it to be requested.

Analysis budgets and partial results

--depth and --max-pages control collection. They do not increase the JavaScript analysis budget. Every command accepts --max-steps (default: 200,000), corresponding to Analyzer(max_steps=...):

sad crawl https://www.google.com/ --depth 2 --max-pages 30 --max-steps 2000000 --format json --strict

The global step budget is divided among supplied JavaScript sources so one expensive script cannot prevent independent sources from being analyzed. When a source exhausts its share, completed discoveries and export bindings are retained, a located analysis-budget issue is emitted and other sources continue. Raising the budget allows more exploration, but does not guarantee completeness or remove other limits.

Argument combinations exceeded 16 reports widening of too many possible argument combinations. SAD keeps explored alternatives and a symbolic remainder and sets analysis_incomplete=true; it does not claim that every concrete combination was analyzed. Loops, recursion and missing inputs can also cause partial results. The CLI explicitly marks incomplete output, and --strict exits with status 1 when diagnostics occur.

high confidence applies to an individual detected operation, not to coverage of the whole application. An HTML form can produce an endpoint even if JavaScript analysis is incomplete; inspect its evidence in JSON to distinguish form declarations from JavaScript sinks.

Burp history: observed and previously unseen APIs

SAD imports the captured requests and analyzes captured response bodies. HTML responses contribute inline scripts and forms; JavaScript responses feed the same static analysis engine used for source files. This can discover operations that were never invoked during the captured session. Assets absent from the capture are not downloaded by an offline import.

For example, a captured app.js response might contain:

fetch("/api/users", {method: "POST"});
fetch(`/api/users/${id}`, {method: "DELETE"});
fetch("/api/admin/export");

If the history contains POST /api/users, SAD correlates that request with the first static discovery. If it also contains DELETE /api/users/123, SAD can correlate it with the symbolic /api/users/{id}. The export operation remains a static discovery even if no export request appears in the history. Original observations and contributing evidence are retained.

Endpoint origin states

The origin field describes where the evidence came from:

State Meaning Example
static-analysis Discovered by reading source code or an HTML declaration, including code inside captured responses. No matching request was supplied. A captured script calls fetch("/api/admin/export"), but that URL is absent from the history.
observed A request exists in the supplied traffic, with no matching static discovery. SAD did not make that request. Burp recorded GET /api/profile, but the supplied code does not expose a corresponding call.
observed+static An observed request was correlated with a static discovery. The logical endpoint retains both evidence sources. Code declares DELETE /api/users/{id} and Burp recorded DELETE /api/users/123.
inferred Reserved for future discoveries based on indirect heuristics that cannot yet be traced to a resolved network sink or an observed request. The current engine does not assign this state automatically. A future adapter might suggest a route from incomplete framework metadata.

origin and confidence answer different questions: origin identifies the evidence source; confidence expresses certainty in the mapping. An unresolved URL such as /api/users/{id} remains static-analysis with symbolic values and appropriate confidence. Resolving a wrapper to fetch is also static analysis; the word “inference” does not automatically imply origin="inferred".

These states never cause SAD to invoke an endpoint. SAD never executes target JavaScript. Live crawling only collects source resources; importing files or captured traffic is offline.

See measured reliability and limitations, architecture and coverage, integration contract, and release checklist. JSON, JSONL, CSV and table outputs share the same library models. Diagnostics indicate malformed inputs and exhausted budgets; incomplete results are retained.

Metadata

Release files for sad-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sad-py 0.1.0
File Size Uploaded Provenance Actions
sad_py-0.1.0.tar.gz 115.9 kB With provenance Details for sad_py-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sad-py 0.1.0
File Interpreter ABI Platform Actions
sad_py-0.1.0-py3-none-any.whl Python 3 none any Details for sad_py-0.1.0-py3-none-any.whl

Total release size: 155.7 kB

Release files / sad_py-0.1.0.tar.gz

Download URL sad_py-0.1.0.tar.gz
Size 115.9 kB
Tags Source
SHA-256 checksum
How to use checksums
afdf98b25a1f82e4181d12bb17a659553d4c16f8fc723fd48f7dc36e3f432fad
BLAKE2b-256 checksum
How to use checksums
79f988d8f1602889ff4495f378436787c5555947cc0b07b1bccd9905c403b05d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / sad_py-0.1.0-py3-none-any.whl

Download URL sad_py-0.1.0-py3-none-any.whl
Size 39.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d28261d765da79eebf6abf73428b114ebaec559e87c76f32ae624abb3cd92272
BLAKE2b-256 checksum
How to use checksums
057bd8ea4ff74a8b9e6420b7b01c6eecba6660b5292214e4c1355847c3e33c51
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Security for sad-py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sad_py-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page