Skip to content
beduldulPublic

About

Rust static analyzer for Solana/Anchor programs: AST-based checks with SARIF output

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

Repository files navigation

solguard

A static analyzer for Solana/Anchor programs, written in Rust. It parses real Rust source with syn (no regex pattern matching) and reports security findings with file/line/snippet evidence.

Status & honesty

solguard is syntactic. It walks the AST and reasons about collected items, context structs, fields, attributes and expressions. It has no dataflow analysis, cannot track values across function or instruction boundaries, cannot evaluate arbitrary Anchor constraints, and cannot prove anything. It finds suspicious patterns, not proven vulnerabilities. It does not replace a manual audit. Treat every finding as a lead to verify by hand.

Checks

ID Check Severity Reference
SG000 File could not be read/parsed (not analyzed) error no reference
SG001 Missing signer check: raw AccountInfo/UncheckedAccount used in a handler without Signer typing, is_signer, seeds, or #[account(signer)] error CWE-284
SG002 Missing owner check: raw account with no constraint/seeds/address attribute and no /// CHECK: doc error CWE-345
SG003 Unchecked arithmetic (+,-,*) in a handler (not a checked_/saturating_/wrapping_ variant) warning CWE-190
SG004 .unwrap()/.expect() in a handler — panic-as-DoS warning CWE-670 (approximation)
SG005 init_if_needed — reinitialization risk; requires justification error Anchor docs (reinit attack)
SG006 State with an authority/owner field used via Account<T> without has_one/constraint/seeds/close warning CWE-862
SG007 PDA bump re-derived at runtime instead of stored (bump = x.bump) info no reference
SG008 close with no visible zeroing of user data — account revival risk info Anchor close docs / account revival

Severity model:

  • error — pattern that is a direct enabler of a real attack class; fix or justify.
  • warning — likely exploitable but context-dependent (panics, overflow, missing has_one).
  • info — hygiene / defense-in-depth; often intentional.

Suppressions the tool deliberately honors

These are documented heuristics that reduce false positives; they can also hide a real bug, so read them as "the tool stays quiet", not "the code is safe":

  • /// CHECK: ... doc comment on the field (Anchor's manual-review convention).
  • seeds = [...] (PDA-derived address), #[account(signer)], constraint, address, close attributes.
  • Handler body mentions is_signer, .owner, or a require*/assert* macro.

Usage

solguard <PATH>                       # human output (default)
solguard <PATH> -f json               # machine-readable findings
solguard <PATH> -f sarif              # SARIF 2.1.0 (GitHub code scanning)
solguard <PATH> --fail-on error       # CI gate: exit 1 if any error finding

Exit codes: 0 = no findings at/above threshold, 1 = threshold exceeded (only with --fail-on), 2 = usage/IO error.

JSON schema

Top level is an array of findings:

{
  "check_id":   "SG001",             // stable check identifier
  "severity":   "error",             // "error" | "warning" | "info"
  "reference":  "CWE-284",           // verified reference or "no reference"
  "file":       "programs/x/src/lib.rs",
  "line":       17,                  // 1-based
  "column":     4,                   // 1-based
  "snippet":    "pub authority: UncheckedAccount<'info>,",
  "message":    "short summary",
  "explanation":"why this is a problem (attack class)"
}

SARIF output maps severity: error→error, warning→warning, info→note, validated against the official sarif-2.1.0 JSON schema.

CI

- name: solguard
  run: |
    cargo install --path . || true
    solguard programs/ --fail-on error

--fail-on accepts error, warning or info; only findings at or above the threshold cause exit 1.

What solguard does NOT do

  • No dataflow or taint analysis — a value crossing functions is invisible.
  • No semantic evaluation of arbitrary constraint = <expr> predicates.
  • No cross-instruction / cross-transaction reasoning (reentrancy-style state confusion, oracle manipulation across instructions, etc.).
  • No CPI-target analysis, no token-standard awareness (SPL/TOKEN-2022 rules).
  • Cannot verify whether a /// CHECK: justification is actually correct — it trusts the comment.
  • SG003 assumes Anchor defaults (overflow panics); non-Anchor builds without overflow-checks silently wrap, which is worse than reported.
  • It will miss anything requiring semantic understanding. It does not replace a manual audit.

Verification on real code

Run against coral-xyz/anchor's own example programs (real, public Anchor code):

  • tests/escrow — 2 findings (both SG008, info). True positives ~50%: Anchor's close on a PDA does leave user data intact; the fixture handlers do not zero it, but exploitability depends on PDA re-creation, which is impossible for these fixed-seed PDAs. Honest rating: plausible-but-not-exploitable.
  • tests/multisig — 5 findings, all SG006 (warning). Mixed: on Approve and ExecuteTransaction the multisig IS protected via has_one on other fields plus a derived-signer pattern the analyzer does not model; the CreateMultisig hit is on #[account(zero)] (init path), which the tool does not recognize. Mostly false positives — SG006 is the weakest check.
  • tests/misc — 77 findings. The SG005 hits (init_if_needed) are true positives by design — that test program exists to exercise init_if_needed. SG004 .unwrap() hits are true positives (real panics in handlers, deliberately in the test suite). SG007/SG008 are accurate pattern matches but low-severity hygiene.

Overall FP assessment: SG001/SG002/SG005/SG004 are high-precision on these repos; SG006 is noisy (~70% FP on real code) and SG007/SG008 are accurate but low-value. Use --fail-on error to gate on the reliable subset.

Development

cargo build
cargo test        # fixtures + CI-gate exit-code test

Fixtures live in tests/fixtures/{vulnerable,safe}/ — one vulnerable and one safe program asserting zero false positives.

License

MIT

About

Rust static analyzer for Solana/Anchor programs: AST-based checks with SARIF output

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages