Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
20f0531
feat(cli): add 'sanctifier watch' to re-analyze on file change
Mercy017 Jun 22, 2026
74894c3
feat: detect unsafe integer casts
YfengJ Jun 23, 2026
18184ca
docs: add custom detector cookbook and update contributing guide
0xVida Jun 23, 2026
faa1727
fix: satisfy clippy option zip lint
YfengJ Jun 23, 2026
10f505c
feat(detector): add fee_rounding rule (S017) to catch integer divisio…
Gbangbolaoluwagbemiga Jun 23, 2026
3233065
fix(ci): add fee_rounding → S017 to differential-corpus.json rule_to_…
Gbangbolaoluwagbemiga Jun 23, 2026
d4041bd
Merge pull request #571 from joelpeace48-cell/feat/fee-rounding-detec…
Gbangbolaoluwagbemiga Jun 23, 2026
3f2b882
Merge pull request #569 from YfengJ/codex/unsafe-cast-detector-321
Gbangbolaoluwagbemiga Jun 23, 2026
d2a3421
feat: implement shareable report permalink feature
meshackyaro Jun 23, 2026
befcca4
Merge pull request #572 from meshackyaro/feature/shareable-report-per…
Gbangbolaoluwagbemiga Jun 23, 2026
21d98c5
docs: Update AMM pool README to document completed hardening (closes …
Jun 24, 2026
7bc85ff
feat: detect missing storage TTL bumps
YfengJ Jun 24, 2026
53a705f
Merge pull request #577 from codemagician1949/feat/close-issue-389-am…
Gbangbolaoluwagbemiga Jun 24, 2026
2eb6a0c
Merge pull request #576 from YfengJ/codex/ttl-missing-315
Gbangbolaoluwagbemiga Jun 24, 2026
d45454a
Add non-blocking Kani formal-verification CI job (#348)
anuoluwaponiorimi Jun 24, 2026
ee8d3ae
Merge pull request #578 from anuoluwaponiorimi/feat/kani-ci-proofs
Gbangbolaoluwagbemiga Jun 24, 2026
32372fa
Merge pull request #579 from Mercy017/feat/cli-watch-mode-361
Gbangbolaoluwagbemiga Jun 24, 2026
751b51d
feat(zk): add Groth16/BLS12-381 audit-proof circuit (issue #352)
presidojay1 Jun 24, 2026
2b47636
style: run cargo fmt on sanctifier-zk
presidojay1 Jun 24, 2026
70ff150
Merge pull request #580 from Temi-suwa18/feat/issue-352-zk-audit-circuit
Gbangbolaoluwagbemiga Jun 24, 2026
ab4ccc4
Add argument DoS detector
YfengJ Jun 24, 2026
7609b7e
Merge pull request #581 from YfengJ/codex/arg-dos-detector-327
Gbangbolaoluwagbemiga Jun 24, 2026
4a7bdf6
Merge branch 'main' into 299-detector-cookbook
Gbangbolaoluwagbemiga Jun 24, 2026
52360f9
Merge pull request #570 from 0xVida/299-detector-cookbook
Gbangbolaoluwagbemiga Jun 24, 2026
05ad73e
feat: add public Soroban/Stellar CVE vulnerability database (#151)
boys-cyberhub Jun 25, 2026
5a2a243
feat: add SEP-41 formal spec templates for token compliance
charlesbarleyman Jun 25, 2026
9fbe74a
Merge pull request #583 from charlesbarleyman/feat/sep41-formal-spec-…
Gbangbolaoluwagbemiga Jun 25, 2026
33572e8
docs: regenerate docs/cli.md to include cve command
boys-cyberhub Jun 26, 2026
184481b
Merge pull request #582 from boys-cyberhub/feat/issue-151-vulndb
Gbangbolaoluwagbemiga Jun 26, 2026
b8ee630
Add decimals scale token math detector
gloskull Jul 26, 2026
440e360
Merge pull request #2 from gloskull/add-detection-for-mixed-token-math
gloskull Jul 26, 2026
db2f1d0
Merge branch 'main' into DETECTOR]-Token-math
gloskull Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ members = [
"contracts/kani-poc",
"contracts/token-invariants",
"contracts/sep41-token-invariants",
"contracts/zk-verifier",
]
resolver = "2"

Expand Down
8 changes: 0 additions & 8 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,6 @@ New to Sanctifier and adding it to an existing project? Read in this order:
- **[Getting Started (detailed)](getting-started.md)** — example output and
finding-by-finding explanations.
- **[Detector Cookbook](detector-cookbook.md)** — three worked examples of custom detectors (trivial, medium, and data-flow).
- **[soroban-sdk Compatibility](soroban-sdk-compatibility.md)** — the supported
soroban-sdk versions, the CI compatibility matrix, and version-specific
handling (including the toolchain pin).
- **[Source-Optional WASM Analysis](wasm-analysis.md)** — analyze a compiled
`.wasm` module directly with `sanctifier wasm`, and its documented limitations
vs. source mode.
- **[Talks & Workshops](talks/README.md)** — ready-to-present slide deck and
live-demo script for demonstrating Sanctifier at conferences and workshops.
- **[Awesome Soroban Security](awesome-soroban-security.md)** — curated external
tools, audits, incidents, and learning resources.
- **[Differential Testing vs Slither/Aderyn](differential-testing.md)** — how
Expand Down
21 changes: 0 additions & 21 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ This document contains the help content for the `sanctifier` command-line progra
* [`sanctifier cve show`↴](#sanctifier-cve-show)
* [`sanctifier cve export`↴](#sanctifier-cve-export)
* [`sanctifier cve serve`↴](#sanctifier-cve-serve)
* [`sanctifier wasm`↴](#sanctifier-wasm)

## `sanctifier`

Expand All @@ -50,7 +49,6 @@ Stellar Soroban Security & Formal Verification Suite
* `verify` — Verify #[sanctify::invariant] declarations across a contract or workspace
* `prove` — Run SMT-based formal verification on Soroban token contract invariants
* `cve` — Search, list, show, and export the public Soroban/Stellar CVE database
* `wasm` — Analyze a compiled .wasm module directly when source is unavailable (source-optional mode)



Expand Down Expand Up @@ -398,25 +396,6 @@ Start a local HTTP server exposing GET /api/vulndb



## `sanctifier wasm`

Analyze a compiled .wasm module directly when source is unavailable (source-optional mode)

**Usage:** `sanctifier wasm [OPTIONS] <PATH>`

###### **Arguments:**

* `<PATH>` — Path to a compiled `.wasm` module

###### **Options:**

* `-f`, `--format <FORMAT>` — Output format (text, json)

Default value: `text`
* `--show-limitations` — Print the source-vs-WASM limitations note (also shown at the end of text output)



<hr/>

<small><i>
Expand Down
5 changes: 0 additions & 5 deletions frontend/app/api/report/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import { NextRequest, NextResponse } from "next/server";
import { getReport } from "../../../lib/report-storage";
import { rateLimit } from "../../../lib/rate-limit";

export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const ip = request.headers.get("x-forwarded-for") || "127.0.0.1";
if (!rateLimit(ip, 30, 60000)) { // 30 reqs per minute
return NextResponse.json({ error: "Too many requests" }, { status: 429 });
}
const { id } = await params;

const report = await getReport(id);
Expand Down
1 change: 0 additions & 1 deletion tooling/sanctifier-cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ pub mod init;
pub mod prove;
pub mod update;
pub mod verify;
pub mod wasm;
pub mod watch;
pub mod webhook;
8 changes: 0 additions & 8 deletions tooling/sanctifier-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ pub enum Commands {
Prove(commands::prove::ProveArgs),
/// Search, list, show, and export the public Soroban/Stellar CVE database
Cve(commands::cve::CveArgs),
/// Analyze a compiled .wasm module directly when source is unavailable (source-optional mode)
Wasm(commands::wasm::WasmArgs),
/// (internal) Regenerate the Markdown CLI reference from the clap definitions.
///
/// Prints the reference to stdout. Hidden from `--help`; used by the docs
Expand Down Expand Up @@ -171,12 +169,6 @@ fn main() -> anyhow::Result<()> {
Commands::Cve(args) => {
commands::cve::exec(args)?;
}
Commands::Wasm(args) => {
if args.format != "json" {
branding::print_logo();
}
commands::wasm::exec(args)?;
}
Commands::GenerateDocs => {
// Render the full command tree to Markdown straight from the clap
// definitions so the committed `docs/cli.md` can never describe a
Expand Down
114 changes: 4 additions & 110 deletions tooling/sanctifier-core/src/finding_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,8 @@ pub const DEPRECATED_SDK: &str = "S014";
pub const DEAD_CODE: &str = "S015";
pub const ERROR_CODE_COLLISION: &str = "S016";
pub const FEE_ROUNDING: &str = "S017";
pub const UNSIGNED_UNDERFLOW: &str = "S019";
pub const LEDGER_SECONDS: &str = "S021";
pub const EXCESSIVE_CLONE: &str = "S020";
pub const ARG_DOS: &str = "SANCT_ARG_DOS";
pub const BALANCE_EQUALITY: &str = "SANCT_BALANCE_EQ";
pub const SANCT_UNWRAP: &str = "SANCT_UNWRAP";
pub const INIT_HARDCODED_ADMIN: &str = "SANCT_INIT_HARDCODED_ADMIN";
pub const SANCT_VISIBILITY: &str = "SANCT_VISIBILITY";
pub const UNBOUNDED_STORAGE: &str = "SANCT_UNBOUNDED_STORAGE";
pub const SANCT_VIEW_PANIC: &str = "SANCT_VIEW_PANIC";
pub const ALLOWANCE_RACE: &str = "SANCT_ALLOWANCE_RACE";
pub const STATE_WRITE_IN_VIEW: &str = "SANCT_STATE_WRITE_IN_VIEW";
pub const DIVISION_BY_ZERO: &str = "S018";

// ── Source-optional (compiled WASM) checks ────────────────────────────────────
// Emitted only by `sanctifier wasm`, which analyzes a deployed module directly.
pub const WASM_NOT_SOROBAN: &str = "W001";
pub const WASM_NO_EXPORTS: &str = "W002";
pub const WASM_MISSING_ENV_META: &str = "W003";
pub const WASM_FLOAT_TYPES: &str = "W004";
pub const DECIMALS_SCALE: &str = "SANCT_DECIMALS";

#[derive(Debug, Clone, Serialize)]
pub struct FindingCode {
Expand Down Expand Up @@ -140,99 +122,17 @@ pub fn all_finding_codes() -> Vec<FindingCode> {
description:
"Fee/interest calculation using integer division rounds to zero for micro-amounts, enabling fee-evasion attacks",
},
FindingCode {
code: UNSIGNED_UNDERFLOW,
category: "arithmetic",
description:
"Unchecked subtraction on an unsigned integer can wrap past zero (underflow)",
},
FindingCode {
code: LEDGER_SECONDS,
category: "time_logic",
description:
"Ledger sequence number (block counter) mixed with a seconds-magnitude literal; use timestamp() for real-time windows",
},
FindingCode {
code: EXCESSIVE_CLONE,
category: "gas_efficiency",
description:
"Gas-wasting clone of the Soroban Env handle where a reference (&env) would suffice",
},
FindingCode {
code: ARG_DOS,
category: "denial_of_service",
description:
"Contract entrypoint iterates over a Vec or Map argument without a visible length cap",
},
FindingCode {
code: SANCT_UNWRAP,
category: "panic_handling",
description:
"Contract entrypoint uses unwrap, expect, or a risky unwrap_or_default fallback",
},
FindingCode {
code: INIT_HARDCODED_ADMIN,
category: "authentication",
description:
"Initialization function uses hardcoded admin address literal or default value instead of formal argument",
},
FindingCode {
code: SANCT_VISIBILITY,
category: "authentication",
description: "Helper-shaped state mutator is publicly exposed without authorization",
},
FindingCode {
code: UNBOUNDED_STORAGE,
category: "denial_of_service",
description:
"Persistent/instance storage collection grows via append/insert with no removal or length cap",
},
FindingCode {
code: SANCT_VIEW_PANIC,
category: "panic_handling",
description:
"View/getter entrypoint contains a reachable panic, aborting callers that assume reads are safe",
},
FindingCode {
code: ALLOWANCE_RACE,
category: "authorization",
description:
"Allowance is overwritten unconditionally (set-allowance) without increase/decrease or compare-and-set semantics, enabling the approve front-running race",
},
FindingCode {
code: STATE_WRITE_IN_VIEW,
category: "code_hygiene",
description:
"Getter/view-style function performs a storage write; callers expect it to be read-only",
},
FindingCode {
code: DIVISION_BY_ZERO,
code: DECIMALS_SCALE,
category: "arithmetic",
description:
"Division or modulo by a non-constant value not proven non-zero, which panics on-chain if zero at runtime",
},
FindingCode {
code: WASM_NOT_SOROBAN,
category: "wasm",
description:
"Compiled module has no Soroban contract spec section; may not be a Soroban contract",
},
FindingCode {
code: WASM_NO_EXPORTS,
category: "wasm",
description: "Compiled module exports no callable functions",
},
FindingCode {
code: WASM_MISSING_ENV_META,
category: "wasm",
description:
"Compiled module is missing Soroban environment metadata (interface version)",
},
FindingCode {
code: WASM_FLOAT_TYPES,
category: "wasm",
description:
"Compiled module uses floating-point value types, which the Soroban host rejects",
"Token amount arithmetic mixes raw/scaled values without decimals or scale validation",
},
]
}
Expand All @@ -259,12 +159,6 @@ mod tests {
assert!(codes.iter().any(|c| c.code == STORAGE_COLLISION));
assert!(codes.iter().any(|c| c.code == UNSAFE_PATTERN));
assert!(codes.iter().any(|c| c.code == CUSTOM_RULE_MATCH));
assert!(codes.iter().any(|c| c.code == SANCT_UNWRAP));
assert!(codes.iter().any(|c| c.code == SANCT_VISIBILITY));
assert!(codes.iter().any(|c| c.code == INIT_HARDCODED_ADMIN));
assert!(codes.iter().any(|c| c.code == UNBOUNDED_STORAGE));
assert!(codes.iter().any(|c| c.code == SANCT_VIEW_PANIC));
assert!(codes.iter().any(|c| c.code == ALLOWANCE_RACE));
assert!(codes.iter().any(|c| c.code == DIVISION_BY_ZERO));
assert!(codes.iter().any(|c| c.code == DECIMALS_SCALE));
}
}
1 change: 0 additions & 1 deletion tooling/sanctifier-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ pub mod rules;
#[cfg(feature = "smt")]
pub mod smt;
mod storage_collision;
pub mod wasm;
use std::collections::{HashMap, HashSet};
use syn::spanned::Spanned;
use syn::visit::{self, Visit};
Expand Down
Loading
Loading