A comprehensive security scanning platform for Soroban smart contracts on the Stellar network. The platform combines a Rust-powered static analysis engine, a Next.js frontend, and on-chain Soroban contracts (bounty marketplace, escrow, role-based access control, multi-signature governance) to help teams build and verify safe smart contracts.
soroban-security-scanner/
βββ contracts/ # Soroban smart contracts (Rust, soroban-sdk 28)
β βββ scanner/ # SecurityScanner contract (bounties, escrow, RBAC, multi-sig)
β β βββ src/lib.rs # Contract implementation
β β βββ src/test.rs # Unit tests
β β βββ tests/ # Integration tests (e.g. ed25519 release signatures)
β βββ scripts/ # Testnet deployment scripts
βββ frontend/ # Next.js 14 web application
βββ component-library/ # Shared React component library (@soroban-scanner/ui-components)
βββ src/ # Rust backend: static analysis engine, auth, API (axum)
βββ tests/ # Backend & e2e test suites
βββ scripts/ # Ops/dev scripts
βββ .github/workflows/ # CI/CD (main.yml, deploy-frontend.yml, ci.yml)
βββ docs/ # Deep-dive documentation
ββββββββββββββββββββββββββββββββ
β Next.js Frontend β
β Scanner UI Β· Dashboard Β· β
β MultiSig Wizard Β· Escrows β
ββββββββββββββββ¬ββββββββββββββββ
β REST / HTTP
ββββββββββββββββΌββββββββββββββββ
β Rust Backend (axum) β
β Static analysis Β· AST/Syn β
β Auth/JWT Β· Rate limiting Β· β
β Batch ops Β· Audit trail β
ββββββββββββββββ¬ββββββββββββββββ
β Soroban RPC
ββββββββββββββββΌββββββββββββββββ
β Soroban Smart Contracts β
β Bounty pool Β· Escrow Β· RBAC β
β Multi-sig Β· Emergency alertsβ
ββββββββββββββββββββββββββββββββ
- Bounty marketplace β report vulnerabilities, verify them, and pay bounties from a funded pool.
- Escrow engine β time-locked escrows with optional ed25519 release signers; releases are replay-safe via per-escrow nonces and canonical signed messages.
- Role-based access control β
SuperAdmin,Verifier,EscrowManager,TreasuryManagerwith granular permissions. - Multi-signature governance β high bounties, emergency verifications and role grants require multi-sig proposals with approval thresholds and time-locks.
- Structured 200-code error system β every failure state maps to a stable numerical code via
ContractError::code()(domains: auth1-19, validation20-39, lookup40-59, funds60-79, escrow80-99, proposals100-119, roles120-139, emergency140-159, arithmetic160-179), with reverse lookup viaContractError::from_code(). - Gas optimizations β enum-like values (status/purpose/severity) are stored as
Symbols instead ofStrings; storage maps are loaded once per operation instead of repeatedly; multi-sig execution skips redundant nestedrequire_authcalls; checked arithmetic throughout.
- Node.js 18+ and npm
- Rust (stable) with the
wasm32v1-nonetarget:rustup target add wasm32v1-none - Stellar CLI (formerly soroban-cli) for contract deployment: https://github.com/stellar/stellar-cli
- Docker & Docker Compose (optional, for local backend services)
git clone https://github.com/connect-boiz/soroban-security-scanner.git
cd soroban-security-scannercd contracts
cargo build -p security_scanner # host build (tests, clippy)
stellar contract build # WASM build (soroban-sdk 28+; requires stellar-cli v25.2.0+)The frontend depends on the local component library, so build it first:
cd component-library
npm ci && npm run build
cd ../frontend
npm ci
npm run dev # http://localhost:3000npm ci # root workspace (scripts, node backend, tests)
npm run build # see package.json for the full buildcd contracts
cargo test -p security_scanner # 48 unit + 5 integration testsCoverage report with cargo-llvm-cov (line coverage is 96%):
cargo install cargo-llvm-cov
cargo llvm-cov -p security_scanner # terminal summary
cargo llvm-cov -p security_scanner --open # HTML report
cargo llvm-cov -p security_scanner --fail-under-lines 80 # CI gateCI enforces a minimum 80% line-coverage gate on the contract in .github/workflows/main.yml.
cd frontend
npm test # run tests
npm run test:coverage # coverage report (coverage/)Coverage is ~89% statements / 82% branches / 87% functions / 90% lines (413 tests across 47 suites). CI enforces a minimum 80% gate on all four metrics (coverageThreshold in frontend/jest.config.js) β npx jest --coverage fails the build if any metric drops below 80%.
npm test # root workspace jest suite (62 tests)
npx jest --coverage # coverage reportnpm run test:e2e # Playwright
npm run test:a11y # axe-core accessibility checks-
Install the Stellar CLI and generate a testnet-funded keypair:
stellar keys generate alice --network testnet --fund
-
Deploy and initialize the contract:
cd contracts ./scripts/deploy_testnet.shThe script builds the WASM, deploys it, and calls
initializewith the admin address and a payment token (native XLM asset contract by default). Configure via env vars:Variable Default Purpose KEY_ALIASaliceSource-account keypair alias NETWORKtestnetStellar CLI network alias ADMIN_ADDRESSkeypair's address G...address that owns the contractTOKEN_ADDRESSnative asset ctr. C...payment token contract idCONTRACT_ALIASsecurity_scannerAlias under which the id is stored Manual equivalent:
stellar contract deploy \ --wasm target/wasm32v1-none/release/security_scanner.wasm \ --source-account alice --network testnet --alias security_scanner stellar contract invoke --id security_scanner --source-account alice --network testnet -- \ initialize --admin GCP3H546OU3IHGIFLT764EBRTA4GH2TNOBNF67CDLTLHCNFW7TTGP4CM \ --token CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC(The
initializevalues above are the verified live ones;deploy_testnet.shalso prints the new contract id in hex, which is the form to pass as--contract_idin later calls β see the CLI quirk note below.) -
Live testnet deployment (2026-09-08):
Item Value Contract CCFQFAVBDLBR2XH74LYG7DPTRHE4IIUDCYFTSOSM2T6HSHP5KSM7HYLH(soroban-sdk 28)Admin GCP3H546OU3IHGIFLT764EBRTA4GH2TNOBNF67CDLTLHCNFW7TTGP4CM(testnet keypairalice)Token CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC(native XLM asset)Explorer https://stellar.expert/explorer/testnet/contract/CCFQFAVBDLBR2XH74LYG7DPTRHE4IIUDCYFTSOSM2T6HSHP5KSM7HYLH Note: the earlier sdk-26 deployment (
CAR7KRNH32CNU3YEYFZYYSFPMXUQHH4EIJPD47333ZN2LGW5P7SVNZIW) is superseded; the contract was upgraded to soroban-sdk 28 to match testnet's protocol 28 and redeployed.CLI quirk β pass
BytesNargs as raw hex. stellar-cli v28 encodes aC...strkey argument for aBytesN<32>parameter in a way the host rejects (Error(WasmVm, InvalidAction)/UnreachableCodeReachedduring contract decode), while the same value as 64-char hex works. Always pass--contract_id <64-hex>(and--release_signer <64-hex>for escrows with a release signer) instead of the strkey.Sanity check:
stellar contract invoke --id security_scanner --source-account alice --network testnet -- get_bounty_pool # "49100000" (funded + partially paid out during E2E verification) stellar contract invoke --id security_scanner --source-account alice --network testnet -- \ get_user_roles --user GCP3H546OU3IHGIFLT764EBRTA4GH2TNOBNF67CDLTLHCNFW7TTGP4CM # ["SuperAdmin"]
Live E2E verification (2026-09-09): the deployed contract was exercised with real testnet transactions β funded the bounty pool (+50M XLM via the native asset contract), reported + verified a vulnerability (bounty paid, reputation updated), ran the full escrow lifecycle (create β conditions-met β release, beneficiary balance +2M XLM on-chain), created/approved multi-sig proposals (high-bounty + emergency) and verified the gates (
#24 ProposalNotReady,#15 MultiSigRequired), and confirmed the structured error codes live (#10 InsufficientPermissions,#16 AlreadyApproved,#26 EscrowAlreadyReleased,#11 ProposalNotFound,#30 ZeroAmount). Multi-sig execution needs β₯2 distinct approvers with a permission; bootstrapping the second approver requires a role grant that itself needs 2 approvals (unit tests grant roles directly), so live execution stops at the approval-count gate.
The repo ships frontend/vercel.json, which builds the local component-library dependency during install:
{
"framework": "nextjs",
"installCommand": "npm ci --prefix ../component-library --no-audit --no-fund && npm run build --prefix ../component-library && npm ci --no-audit --no-fund",
"buildCommand": "npm run build"
}Dashboard setup (easiest): import the repository into Vercel, set Root Directory to frontend β the config is picked up automatically.
CLI setup: link the project and deploy:
npx vercel link # once β creates .vercel/project.json
npx vercel deploy --prodAutomated deploys: .github/workflows/deploy-frontend.yml deploys a preview on every pull request and production on pushes to main/develop. It needs three repository secrets:
| Secret | Where to get it |
|---|---|
VERCEL_TOKEN |
Vercel β Account β Settings β Tokens |
VERCEL_ORG_ID |
npx vercel teams ls / project settings |
VERCEL_PROJECT_ID |
npx vercel project ls / project settings |
How the secrets gate works: GitHub Actions does not allow secrets in job-level if: conditions, so the workflow uses a small check-config job: it writes configured=true/false to $GITHUB_OUTPUT depending on whether all three secrets are non-empty, and the preview/production jobs gate on that output (if: needs.check-config.outputs.configured == 'true').
- Secrets not set (default): the
Check Vercel configurationjob runs in ~2s and both deploy jobs skip β the run stays green instead of failing on every push. - Secrets set: deploys start automatically on the next push/PR to
main/developβ no workflow changes needed.
To enable real deploys, add the three secrets under Settings β Secrets and variables β Actions and push (or re-run the workflow).
Live URL: https://soroban-security-scanner.vercel.app (production, deployed 2026-09-09).
To move deploys to CI, add the three secrets under Settings β Secrets and variables β Actions and push β the production job deploys automatically from then on (the values are VERCEL_TOKEN = a Vercel account token from the link above, VERCEL_ORG_ID = your team id, VERCEL_PROJECT_ID = the project id from frontend-linked project).
.github/workflows/main.ymlβ runs on every push/PR: contract tests (fmt, clippy, unit + integration), the 80% coverage gate (cargo llvm-cov --fail-under-lines 80), frontend tests + coverage (80% gate on statements/branches/functions/lines), node tests + coverage, and uploads all coverage artifacts..github/workflows/deploy-frontend.ymlβ Vercel preview (PR) and production (push) deploys. Acheck-configjob verifies theVERCEL_TOKEN/VERCEL_ORG_ID/VERCEL_PROJECT_IDsecrets are set, and the deploy jobs skip until they are (see Vercel deployment)..github/workflows/ci.ymlβ full matrix: contracts, Rust backend, node backend, frontend, component library..github/workflows/security-idor-tests.ymlβ IDOR prevention tests and static security analysis.
- Fork the repo and create a feature branch.
- Run the full test matrix locally (
cargo test,npm test) and keep contract line coverage β₯ 80%. - Open a PR β CI runs tests and the coverage gate automatically.
MIT β see LICENSE.
Built with β€οΈ for the Stellar community.