Sanctifier is a security and formal-verification suite for Stellar Soroban smart contracts. It statically analyses Rust/Soroban source code, checks for 12 classes of vulnerabilities, matches against a community-sourced vulnerability database, and optionally proves invariants with Z3.
- Installation
- Quick Start
- Finding Codes
- CLI Reference
- Example JSON Output
- JSON Schema
- GitHub Action
- Project Structure
- Configuration
- Add a Sanctifier Badge to Your Project
- Documentation
- Contributing
- License
cargo install sanctifier-cligit clone https://github.com/Jayy4rl/Sanctifier.git
cd Sanctifier/tooling/sanctifier-cli
cargo install --path .Prerequisites: Rust 1.78+,
libz3-devandclang/libclang-dev(needed by the Z3 formal-verification backend).# Debian / Ubuntu sudo apt-get install libz3-dev clang libclang-dev # macOS brew install z3 llvm
Common workflows are wrapped in a root-level Makefile:
make build # cargo build --workspace
make test # cargo test --workspace
make lint # cargo fmt --all --check && cargo clippy --workspace -- -D warnings
make fmt # cargo fmt --all
make audit # cargo audit && cargo deny check
make release # cargo build --workspace --release
make docs # cargo doc --workspace --no-deps --open
make clean # cargo cleanAnalyse a Soroban contract in a single command:
sanctifier analyze ./contracts/my-tokenExample terminal output
β οΈ Found potential Authentication Gaps!
-> [S001] Function: ./contracts/token-with-bugs/src/lib.rs:initialize
-> [S001] Function: ./contracts/token-with-bugs/src/lib.rs:transfer
-> [S001] Function: ./contracts/token-with-bugs/src/lib.rs:mint
β οΈ Found unchecked Arithmetic Operations!
-> [S003] Op: -
Location: ./contracts/token-with-bugs/src/lib.rs:transfer:30
-> [S003] Op: +
Location: ./contracts/token-with-bugs/src/lib.rs:transfer:33
β οΈ Found Unhandled Result issues!
-> [S009] Function: transfer
Call: Self :: balance (e . clone () , from . clone ())
Location: ./contracts/token-with-bugs/src/lib.rs:transfer:27
Message: Result returned from function call is not handled.
β οΈ Found SEP-41 Interface Deviations!
-> [S012] Function: allowance
Kind: MissingFunction
Message: Missing SEP-41 function 'allowance'.
π‘οΈ Found 2 known vulnerability pattern(s) (DB v1.0.0)!
β [SOL-2024-002] Missing Auth on Token Transfer (CRITICAL)
π΄ [SOL-2024-003] Unchecked Balance Underflow (HIGH)
β¨ Static analysis complete.
Every finding is tagged with a stable code so you can filter, suppress, or reference it in CI.
| Code | Category | Description |
|---|---|---|
S001 |
authentication | Missing require_auth in a state-changing function |
S002 |
panic_handling | panic! / unwrap / expect usage that may abort execution |
S003 |
arithmetic | Unchecked arithmetic with overflow/underflow risk |
S004 |
storage_limits | Ledger entry size exceeds or approaches the configured threshold |
S005 |
storage_keys | Potential storage-key collision across data paths |
S006 |
unsafe_patterns | Potentially unsafe language or runtime pattern detected |
S007 |
custom_rule | User-defined rule matched contract source |
S008 |
events | Inconsistent topic counts or sub-optimal gas patterns in events |
S009 |
logic | A Result return value is not consumed or handled |
S010 |
upgrades | Security risk in contract upgrade or admin mechanisms |
S011 |
formal_verification | Z3 proved a mathematical violation of an invariant |
S012 |
token_interface | SEP-41 token interface compatibility or authorization deviation |
In addition, the community vulnerability database emits SOL-2024-* codes
when a known vulnerability pattern is matched.
See docs/error-codes.md for full details.
Analyse a Soroban contract for vulnerabilities.
sanctifier analyze [OPTIONS] [PATH]| Flag | Short | Default | Description |
|---|---|---|---|
[PATH] |
β | . |
Contract directory or Cargo.toml |
--format <FORMAT> |
-f |
text |
Output format: text or json |
--limit <BYTES> |
-l |
64000 |
Ledger entry size limit in bytes |
--vuln-db <PATH> |
β | built-in | Custom vulnerability database JSON |
--webhook-url <URL> |
β | β | Webhook endpoint(s) for scan notifications (repeatable) |
# JSON output for CI
sanctifier analyze ./contracts/my-token --format json
# Custom ledger limit and webhook
sanctifier analyze . --limit 32000 \
--webhook-url https://hooks.slack.com/services/XXX/YYY/ZZZExit code: 1 when critical or high findings are detected (useful in CI
pipelines).
Use one or more --webhook-url flags to push a scan.completed notification
after sanctifier analyze finishes:
sanctifier analyze ./contracts/token-with-bugs \
--webhook-url https://discord.com/api/webhooks/XXX/YYY \
--webhook-url https://hooks.slack.com/services/AAA/BBB/CCCProvider-specific payloads:
| Provider | Payload shape |
|---|---|
| Discord | { "content": "Sanctifier scan completed ..." } |
| Slack | { "text": "Sanctifier scan completed ...", "attachments": [{ "color": "...", "fields": [...] }] } |
| Teams | { "text": "Sanctifier scan completed ..." } |
| Custom webhook | Raw JSON payload: event, project_path, timestamp_unix, summary |
The shared payload data includes:
| Field | Description |
|---|---|
event |
Always scan.completed |
project_path |
Analysed path passed to sanctifier analyze |
timestamp_unix |
Completion timestamp as UNIX seconds |
summary.total_findings |
Total number of findings emitted |
summary.has_critical |
Whether any critical findings were detected |
summary.has_high |
Whether any high-severity findings were detected |
Webhook delivery failures are non-fatal: Sanctifier logs a warning to stderr and still returns the analysis result.
Generate a .sanctify.toml configuration file in the current directory.
sanctifier init [OPTIONS]| Flag | Short | Default | Description |
|---|---|---|---|
--force |
-f |
false |
Overwrite an existing config file |
Create an SVG badge and optional Markdown snippet from a JSON scan report.
sanctifier badge [OPTIONS]| Flag | Short | Default | Description |
|---|---|---|---|
--report <PATH> |
-r |
sanctifier-report.json |
Path to a Sanctifier JSON report |
--svg-output <PATH> |
β | sanctifier-security.svg |
Output SVG file |
--markdown-output <PATH> |
β | β | Output Markdown snippet file |
--badge-url <URL> |
β | local SVG path | Public URL for the SVG |
sanctifier analyze . --format json > sanctifier-report.json
sanctifier badge --report sanctifier-report.json \
--svg-output badges/sanctifier-security.svg \
--markdown-output badges/sanctifier-security.mdGenerate a Graphviz DOT call graph of cross-contract calls
(env.invoke_contract).
sanctifier callgraph [OPTIONS] [PATH]| Flag | Short | Default | Description |
|---|---|---|---|
[PATH] |
β | . |
Contract directory, workspace, or .rs file |
--output <FILE> |
-o |
callgraph.dot |
Output DOT file |
sanctifier callgraph ./contracts/amm-pool -o amm-callgraph.dot
dot -Tpng amm-callgraph.dot -o amm-callgraph.png # requires GraphvizCheck for and download the latest Sanctifier binary from crates.io.
sanctifier updateGenerate a security report (writes to stdout or a file).
sanctifier report [OPTIONS]| Flag | Short | Default | Description |
|---|---|---|---|
--output <PATH> |
-o |
stdout | Output file path |
sanctifier analyze ./contracts/vulnerable-contract --format jsonNote: The example above is abbreviated. See the full field reference in the JSON Schema below.
The machine-readable contract for --format json output is published at
schemas/analysis-output.json (JSON Schema draft-07).
schemas/
βββ analysis-output.json # Draft-07 schema β validated in CI
Downstream tools (dashboards, IDE plugins, CI integrations) can use the schema to:
- Validate report files before processing them.
- Generate typed bindings in any language that supports JSON Schema.
- Detect breaking changes when the tool is upgraded.
The schema_version field in every report (e.g. "1.0.0") is bumped independently
of the Sanctifier tool version whenever the output shape changes, so consumers can
guard on it without coupling to the CLI release cycle.
Sanctifier ships a composite GitHub Action (action.yml) so CI consumers can
integrate with a few lines.
name: Sanctifier Scan
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
security-events: write
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Sanctifier
uses: HyperSafeD/Sanctifier@main
with:
path: .
format: sarif
min-severity: high
upload-sarif: "true"
sarif-output: sanctifier-results.sarifWhen format: sarif and upload-sarif: "true", the action uploads the SARIF
file via github/codeql-action/upload-sarif@v3 so findings appear in GitHub
code scanning.
Sanctifier/
βββ contracts/ # Soroban smart contracts (examples & test targets)
βββ frontend/ # Next.js web dashboard
βββ schemas/
β βββ analysis-output.json # JSON Schema (draft-07) for --format json output
βββ tooling/
β βββ sanctifier-cli/ # CLI binary (this is what you install)
β βββ sanctifier-core/ # Static-analysis engine & Z3 backend
βββ data/
β βββ vulnerability-db.json # Community-sourced vulnerability patterns
βββ scripts/ # Deployment & CI helper scripts
βββ docs/ # Architecture decisions, guides, case studies
Run sanctifier init to generate a .sanctify.toml:
ignore_paths = ["target", ".git"]
enabled_rules = ["auth_gaps", "panics", "arithmetic", "ledger_size"]
ledger_limit = 64000
approaching_threshold = 0.8
strict_mode = false
[[custom_rules]]
name = "no_unsafe_block"
pattern = 'unsafe\s*\{'
severity = "error"
[[custom_rules]]
name = "no_mem_forget"
pattern = "std::mem::forget"
severity = "warning"Display your contract's security status directly in your repository README.
# Produce a JSON report
sanctifier analyze . --format json > sanctifier-report.json
# Generate the SVG badge and a Markdown snippet
sanctifier badge \
--report sanctifier-report.json \
--svg-output .github/badges/sanctifier-security.svg \
--markdown-output .github/badges/sanctifier-security.md \
--badge-url "https://raw.githubusercontent.com/<owner>/<repo>/main/.github/badges/sanctifier-security.svg"git add .github/badges/sanctifier-security.svg
git commit -m "ci: add Sanctifier security badge"Copy the snippet from sanctifier-security.md, or paste directly:
[](https://github.com/HyperSafeD/Sanctifier)| Badge color | Status | Meaning |
|---|---|---|
| π’ Green | Secure | Zero findings |
| π Orange | Warning | At least one finding (high severity or any finding) |
| π΄ Red | Critical | At least one critical-severity finding |
The badge is regenerated automatically whenever you re-run sanctifier badge
with an updated report. Add it to your CI pipeline so the badge always
reflects the latest scan result.
| Document | Description |
|---|---|
| Getting Started | First-run walkthrough |
| Error Codes | Full finding-code reference |
| Runtime Guards Integration | Adding runtime guards to your contract |
| CI/CD Setup | GitHub Actions integration |
| Soroban Deployment | Deploy guard contracts to testnet |
| Contributing Analysis Rules | Writing custom analysis rules |
| Case Studies | Benchmark against official Soroban examples |
| Architecture Decisions | ADRs for design choices |
We welcome contributions from the Stellar community! Please see the Contributing Guide for details on setting up your development environment, running tests, and submitting pull requests.
MIT

{ "metadata": { "version": "0.1.0", "timestamp": "2026-03-24T12:00:00Z", "project_path": "./contracts/vulnerable-contract", "format": "sanctifier-ci-v1", }, "summary": { "critical": 0, "high": 0, "medium": 2, "low": 0, "info": 0, }, "findings": { "auth_gaps": [{ "code": "S001", "function": "src/lib.rs:set_admin" }], "panics": [ { "code": "S002", "type": "expect", "location": "src/lib.rs:set_admin_secure", }, ], "arithmetic_issues": [], "storage_collisions": [ { "code": "S005", "value": "admin", "type": "storage::set (instance)" }, ], "upgrade_admin_risks": [ { "code": "S010", "category": "Governance", "function": "set_admin" }, ], }, "error_codes": [ { "code": "S001", "category": "authentication", "description": "..." }, "...", ], "vuln_db_matches": [], "schema_version": "1.0.0", }