Sorseal — the provenance layer for Soroban
Prove your smart contract wasn't swapped after deployment — and catch the bugs that drain contracts before you ship.
Every Soroban deployment is a trust assumption. Was the WASM on-chain built from the source you reviewed? Was it modified before deploy? Did someone sneak in a function that drains the treasury?
Sorseal answers these questions. It seals your build with cryptographic proof, scans your source for the patterns that let contracts get drained, and lets anyone verify the chain from source to deployment — all from the CLI.
# prebuilt binary (fastest)
curl -sSfL https://github.com/BreachDirect/sorseal/releases/latest/download/sorseal-linux-amd64 -o /usr/local/bin/sorseal && chmod +x /usr/local/bin/sorseal
# or via crates.io
cargo install sorseal --locked
# or from source
git clone https://github.com/BreachDirect/sorseal.git && cd sorseal && cargo build --releaseRequirements: Rust 1.85+ and wasm32-unknown-unknown target (rustup target add wasm32-unknown-unknown).
$ sorseal analyze
Critical SORSEAL-101 src/lib.rs:23 — function mutates state without require_auth (high confidence)
High SORSEAL-102 src/lib.rs:32 — reentrancy: state mutation + external call, no guard (medium confidence)
High SORSEAL-105 src/lib.rs:42 — transfer amount not derived from balance read (medium confidence)
3 findings — Critical: 1 · High: 2 · Medium: 0 · Low: 0
$ sorseal verify
PASSED my-contract :: wasm — sha256 matches sealed digest
PASSED my-contract :: source — sha256 matches sealed digest
PASSED my-contract :: command — build_command unchanged
3 checks: 3 passed, 0 failed, 0 errored
Try it now:
cd examples/vulnerable-contract && sorseal analyze
scripts/sim-demo.sh walks the full record → verify → simulate-onchain → onchain-audit chain against an in-memory synthetic ledger — no testnet account, no XLM, no stellar CLI. For a live testnet run (needs a funded account), see scripts/demo.sh.
Every pull request gets scanned automatically. Upload results to GitHub Code Scanning:
- uses: BreachDirect/sorseal@main
with:
sarif-file: sorseal.sarifOr gate on severity — fail the build if any Critical/High finding exists:
- uses: BreachDirect/sorseal@mainThen add a step:
- run: sorseal analyze --fail-on Highsorseal init # scaffold a sorseal.toml manifest
sorseal record # seal: build + hash + write provenance
sorseal verify # rebuild and compare digestssorseal analyze # scan all artifacts
sorseal analyze --wasm # also scan the compiled WASM bytecode
sorseal analyze --fail-on High # CI gate: exit non-zero on High/Critical
sorseal analyze --format json # machine-readable findings
sorseal analyze --sarif out.sarif # SARIF for code scanning
sorseal analyze --explain # list all rules
sorseal analyze --seal # seal finding digest into provenancesorseal watch --init # generate starter config
sorseal watch --once # single check (for cron)
sorseal watch # daemon mode with webhook alerts| Command | What it does |
|---|---|
sorseal init |
Scaffold a sorseal.toml manifest |
sorseal record |
Build artifacts, write sorseal.provenance.json |
sorseal verify |
Rebuild and verify artifacts match sealed provenance |
sorseal report |
Render provenance as console, JSON, or Markdown |
sorseal keygen |
Generate an Ed25519 keypair for signing |
sorseal sign |
Sign provenance as an in-toto/SLSA v1.0 attestation |
sorseal verify-attestation |
Verify a signed attestation |
sorseal onchain-verify |
Compare on-chain WASM hash against sealed provenance |
sorseal onchain-audit |
Audit a contract's full upgrade history |
sorseal simulate-onchain |
Fund-free offline on-chain verify + audit demo |
sorseal analyze |
Scan source for Soroban vulnerability patterns |
sorseal watch |
Monitor files for integrity drift, alert on changes |
sorseal hook |
Install/uninstall/status for a verify + analyze pre-commit hook |
sorseal analyze checks for the patterns that let Soroban contracts get drained, reentered, or crashed. Each rule has a stable id, a severity (how bad an exploit would be) and a confidence (how certain the scan is that the finding is real — exact bytecode/pattern matches are high, heuristic data-flow-adjacent rules are medium/low):
| Rule | Name | Severity | Confidence | What it catches |
|---|---|---|---|---|
SORSEAL-101 |
missing-authorization | Critical | high | State/value mutation without require_auth |
SORSEAL-102 |
reentrancy | High | medium | External call after state mutation, no guard |
SORSEAL-103 |
unchecked-arithmetic | Medium | medium | Raw +/-/* on amounts instead of checked_* |
SORSEAL-104 |
panic-on-user-input | Low | high | panic!/unwrap() on a caller-reachable path |
SORSEAL-105 |
unchecked-transfer | High | medium | .transfer amount not derived from balance read |
SORSEAL-106 |
missing-reentrancy-guard | Medium | medium | invoke_contract without non_reentrant |
SORSEAL-107 |
hardcoded-storage-key | Medium | medium | Hardcoded Symbol::new() as persistent storage key — collisions across upgrades |
SORSEAL-108 |
unsafe-raw-pointer | Critical | high | unsafe block or raw pointer deref in contract code |
SORSEAL-109 |
panic-on-storage-read | Low | high | unwrap() on env.storage() read — panics if key missing |
SORSEAL-110 |
admin-key-never-rotated | Medium | low | OWNER/ADMIN storage write without rotation pattern |
SORSEAL-111 |
missing-token-balance-check | High | medium | Token operation without verifying contract holds the asset |
SORSEAL-112 |
unchecked-env-caller | Medium | medium | Caller address used without require_auth — spoofable |
SORSEAL-113 |
oracle-price-feed | Medium | low | Price-feed read with no staleness/auth guard — single-oracle manipulation |
SORSEAL-114 |
flash-loan-approve | High | low | Allowance granted + external call in the same function |
SORSEAL-115 |
wasm-unreachable-export | High | high | Deployed WASM body traps with an unreachable opcode (source scanners miss it) |
SORSEAL-116 |
wasm-no-exports | Medium | high | WASM module exports nothing — wrong artifact being sealed |
Run sorseal analyze --explain SORSEAL-107 for detailed guidance on any rule.
Sorseal is the only tool in this table that ties source analysis to a sealed, verifiable provenance record for Soroban. It analyses your own contract source where Slither-analogues would, and dresses the results as signed in-toto/SLSA attestations you can verify on-chain.
| Need | Tool | Sorseal's take |
|---|---|---|
| Solidity smart-contract security | Slither | Sorseal covers the Soroban/WASM analogue; here for framing |
| Rust dependency CVEs | cargo-audit / cargo-deny | record gates builds the same way; analyze is about your own code, not deps |
| Lockfile policy (licenses, duplicates) | cargo-deny | Complementary — deny.toml rules apply unchanged to Soroban builds |
| Was your deployed contract swapped? | — | sorseal record → verify → onchain-verify (unique) |
| Are my build attestations signed? | — | sorseal sign (Ed25519 DSSE, SLSA v1.0) (unique) |
| Does my contract get reentered/drained? | Soroban security reviews (manual) | sorseal analyze catches 16 known patterns automatically |
Why these 16 checks and not others: the rule set is the minimum that, applied mechanically, misses materially fewer of the vulnerabilities that actually drain Soroban contracts (missing auth, unchecked arithmetic/transfers, reentrancy, oracle manipulation) than a manual review does, while staying deliberately lexical so it has zero build-time deps and zero false-negative cost from unparseable code. Rules are pure-pattern and explicitly low-confidence where data flow would be needed — see RULES.md for the reasoning per rule and the changelog. Anything beyond that (taint tracking, custom rules) is on the roadmap.
sorseal init ──→ sorseal.toml (manifest)
sorseal record ──→ build → hash (WASM + source + toolchain + git) → sorseal.provenance.json
sorseal verify ──→ rebuild → compare digests → PASSED/FAILED
sorseal analyze ──→ lexical scan → findings (JSON/console/SARIF/Markdown)
sorseal sign ──→ Ed25519 DSSE envelope (in-toto/SLSA v1.0)
sorseal onchain-* ──→ getLedgerEntries/getEvents XDR → verify against provenance
sorseal watch ──→ hash baseline → drift detection → Discord/Telegram/POST alert
This repository is part of a broader set of contributions to the Stellar / Soroban ecosystem. See WAVE_EVIDENCE_ToryMic.md for a curated list of related projects, demos, and tooling maintained by ToryMic, including testing, indexers, contract frameworks, and privacy/payment prototypes.
- Evidence file: WAVE_EVIDENCE_ToryMic.md
- Maintainers: MAINTAINERS.md
See CONTRIBUTING.md for setup, code style, and PR process.
This repository is a Stellar Drips Wave 9 project. The quickest ways to contribute right now:
- Pick up a
good-first-issue— issues labelledgood-first-issueare scoped and small enough to land in a weekend. - Run
sorseal analyzeon your own contract and file a bug/feature report with real output. - Add a detection rule — new Soroban issue classes (storage-key collisions, oracle manipulation, missing balance checks) make great intermediate issues.
- Document — rule-explanation pages, worked examples, and real testnet walkthroughs.
- Post captured evidence — run
scripts/sim-demo.shand attach output to PRs. Real output is stronger Wave evidence than code-only changes.
| Area | Status |
|---|---|
Build provenance (record/verify) |
shipped |
| Reporting (console/JSON/Markdown) | shipped |
| CI / SARIF + GitHub Action | shipped |
| Signed attestations (SLSA v1.0) | shipped |
| On-chain verification + upgrade audit | shipped |
Vulnerability scan (16 rules, --wasm, confidence scores, --seal) |
shipped |
CI severity gate (--fail-on) |
shipped |
| File integrity monitoring | shipped |
| Prebuilt binary releases (Linux/macOS/Windows) | shipped |
| Detection engine (data-flow awareness to cut heuristics → low-confidence) | in progress |
| Extensible rules (team-local custom patterns via config) | in progress |
npx sorseal wrapper + VS Code extension |
in progress |
| Hosted verify-any-contract page + provenance badge | in progress |
MIT