Static application security testing · v3.2

code, understood.

Security analysis that's reproducible by design. Every finding witnessed, every result attested.

scanipy · acme/payments-api · main@7f3a2c9
High · CWE-22Deterministic-coreAttested

Path traversal in archive extraction

src/api/uploads.py · L48 → src/util/archive.py · L112
42def upload_archive(req):
43    name = req.form["name"] # ← source
48    archive.extract(name, dest=UPLOAD_DIR)
↓ taint propagates · 2 hops ↓
110def extract(member, dest):
112    path = os.path.join(dest, member) # ← sink
113    open(path, "wb").write(data)
fingerprint
7f3a · 2c9d · 4e81 · strong
S_version
specs@2026.05.14-r2
env_digest
sha256:c1b…a89
cpg_order_hash
canonical · 3d8…b22
99.5%
Front-end parse fidelity gate for benchmarked languages.
Median incremental speedup vs full re-analysis.
< 30m
p95 end-to-end scan for a 100k LOC repository.
0
Tolerated byte-diffs on the deterministic-core partition.
How it works · scroll
01 / Reproducibility

Same code in.
Same findings out.

Every deterministic-core result is a function of source, a version-pinned spec set, and a pinned environment. Re-run the scan and get the same SARIF, byte for byte. The Attestor fails the build if it doesn't.

02 / Incrementality

Only analyse
what changed.

Scanipy reuses the CPG of the parent commit and replays the analysis on the affected slice. Closed-world commits rebuild in time proportional to the semantic delta, not the size of the repository.

03 / Provenance

Every finding
shows its work.

Every result ships with a signed chain: source commit → snapshot digest → spec version → env digest → taint witness → rule id. Auditors verify findings without re-running the analysis.

Run · 14:02 UTCSARIF · sha256:c1b…a89
Run · 14:39 UTCSARIF · sha256:c1b…a89
Run · audit replaySARIF · sha256:c1b…a89

Three runs, three weeks apart. Same hash.

Repository · 14,328 filesparent: 7f3a2c9
changed (3)affected (5)untouched (14,320)

Eight files of work for a fourteen-thousand-file repo.

sourceacme/payments-api@7f3a2c9
snapshotcpg · sha256:9d2…11c
S_versionspecs@2026.05.14-r2
env_digestimage · sha256:c1b…a89
cpg_ordercanonical · 3d8…b22
witnessuploads.py:48 → archive.py:112
spec_idpath-traversal/zipslip-py
signatureed25519 · 0x8f…42a
scroll
Built for the messy real world

A SAST platform with the receipts.

Engineering teams stop trusting tools that change their minds. Scanipy is built so you don't have to.

Multi-SCM, one connector

GitHub, GitLab, Bitbucket, Azure DevOps: same conformance suite, same fingerprint across providers.

Refactor-stable findings

Rename a variable, extract a method, move a file. The slice fingerprint survives. No false-new on cosmetic changes.

Anytime-valid spec gate

New detection rules clear a precision floor with mathematically defensible guarantees, even under unbounded re-evaluation.

Incremental by default

Scanipy reuses the parent commit's analysis graph and replays only the affected slice. PRs scan in seconds, not minutes.

Two partitions, honest labels

Every finding declares its origin. Deterministic-core results carry a reproducibility theorem; oracle-passthrough results carry a measured rate. Never both, never blurred.

LLM-assisted, not LLM-decided

Language models triage and propose new specs. They never delete a finding, never sit on the detection path. Determinism is non-negotiable.

Drop in code · get back evidence

Findings you can defend.

Every result links back to the exact path through your code that produced it. Hand the witness to anyone (auditor, engineer, ticket bot) and they can verify without re-running the scan.

Input · python

# app/views/uploads.py
from flask import request, send_file
import os

UPLOAD_DIR = "/var/uploads"

def download(req):
    name = req.args["file"]
    path = os.path.join(UPLOAD_DIR, name)
    return send_file(path)
Open interactive demo →No signup required.

Output · 1 finding

High · CWE-22Deterministic-core
Path traversal · unsanitised user input reaches file read
app/views/uploads.py · L7 (source) → L9 (sink)

req.args["file"] flows into os.path.join without a normalisation check.

fingerprint
a82d · 4e1f · 7c93 · strong
spec
path-traversal/flask-py
S_version
specs@2026.05.14-r2
env_digest
sha256:c1b…a89
Why teams ship Scanipy

“It's the first SAST result our auditors stopped arguing with. The finding either reproduces or it doesn't. Done.”

Run your first scan in a minute.

Free for open-source. Free for the first repo. The auditor's edition is paid. Never the result.