The Solana Security StandardSOL-0XX rules distilled from $514M of real exploits, firing as you code in every AI tool (Claude Code, Codex, Cursor, Windsurf…), your editor, and CI. By the auditors who find them.

SOL-001 firing on a vulnerable Solana program — Bounty 6 H2 case study

-orange)

The same SOL-0XX rules flag Solana-specific bugs while you code — caller-controlled clock values, cross-market state asymmetry, wrapper handlers that drift from engine logic, missing Anchor constraints, and 37 bug classes in all, drawn from real audits.

Works in: Claude Code · Codex · Copilot · Cursor · Windsurf · Cline · Aider · any MCP client · the VS Code extension (Open VSX) · the CLI · Semgrep · GitHub Actions. Pick your surface below.

Use it in Claude Code (30 seconds)

mkdir -p .claude && \
  curl -sL https://raw.githubusercontent.com/Copenhagen0x/solana-security-standard/main/plugin-guidance.md \
       -o .claude/claude-security-guidance.md && \
  curl -sL https://raw.githubusercontent.com/Copenhagen0x/solana-security-standard/main/security-patterns.yaml \
       -o .claude/security-patterns.yaml

plugin-guidance.md is the compact ≤8 KB plugin digest (every rule as a one-line cue, generated from the full claude-security-guidance.md); it lands as the plugin's .claude/claude-security-guidance.md. Full per-rule detail is one MCP call (list_solana_security_rules) or one click (the master on GitHub) away.

Then make sure you have Anthropic's security-guidance plugin installed:

/plugin install security-guidance@claude-plugins-official
/reload-plugins

Done. Open a Solana program file in Claude Code and the plugin will catch issues as you write.

(This pulls from main with no integrity check. For supply-chain-sensitive use, see Verified install below.)

Or install the whole standard as a Claude Code plugin (the MCP scan tool + a /scan command, auto-wired):

/plugin marketplace add Copenhagen0x/solana-security-standard
/plugin install solana-security-standard@solana-security-standard

Verified install (pin + checksum)

For CI or supply-chain-sensitive setups, pin to a release tag and verify the download against the published CHECKSUMS.txt instead of pulling main:

Note: the plugin-guidance.md digest ships from v1.11.0 onward. Until that release is tagged, use the Quick install above (which pulls the digest from main); the pinned-tag flow below works once v1.11.0 exists.

TAG=v1.11.0   # the digest ships from v1.11.0 on; older tags use claude-security-guidance.md directly
BASE="https://raw.githubusercontent.com/Copenhagen0x/solana-security-standard/$TAG"
tmp=$(mktemp -d) && cd "$tmp" && mkdir -p semgrep
curl -fsSL "$BASE/CHECKSUMS.txt"                          -o CHECKSUMS.txt
curl -fsSL "$BASE/plugin-guidance.md"                     -o plugin-guidance.md
curl -fsSL "$BASE/security-patterns.yaml"                 -o security-patterns.yaml
curl -fsSL "$BASE/semgrep/solana-security-standard.yaml"  -o semgrep/solana-security-standard.yaml
sha256sum -c CHECKSUMS.txt          # Linux — all three must print "OK"; aborts on any mismatch
# macOS (no sha256sum): shasum -a 256 -c CHECKSUMS.txt
mkdir -p "$OLDPWD/.claude"
cp security-patterns.yaml "$OLDPWD/.claude/"
cp plugin-guidance.md "$OLDPWD/.claude/claude-security-guidance.md"   # rename to the plugin's expected filename
# the verified semgrep ruleset stays in $tmp/semgrep/ — point `semgrep --config` at it or copy where you need it

Pinning to a tag freezes you to a known release (a tampered main can't reach you); the checksum confirms nothing was altered in transit. (Hashes are over the LF bytes GitHub serves — verify the downloaded files, not a CRLF local checkout.) Tags from v1.9.1 on are SSH-signed — verify origin with git verify-tag v1.11.0 (key + steps in SECURITY.md). (Checksums and the in-repo allowed-signers can't defend against a full account compromise that rewrites both — the signed tag, verified out of band, is the origin check for that.)

Run it in CI — GitHub Action

Gate every pull request on the standard. The same SOL-0XX patterns run as a check, with inline annotations on the diff:

# .github/workflows/solana-security.yml
name: Solana Security Standard
on: [pull_request]
permissions:
  contents: read
  security-events: write   # optional — enables inline PR annotations
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Copenhagen0x/solana-security-standard@v1
        with:
          paths: ./programs        # what to scan (default: .)
          # fail-on-findings: true # red X on findings (default)
          # upload-sarif: true     # GitHub code scanning (default)
          # min-tier: high         # noise floor: drop LOW-tier hygiene findings
          # baseline: .sss-baseline.json  # gate only on NEW findings (see cli/README)

Then show the world you adopt it — drop this badge in your README:


Run it from the CLI

npx @jelleo/solana-security-standard scan ./programs

Human, JSON, or SARIF output; exits non-zero on findings (so it gates any CI). Zero dependencies. Details in cli/.

Every machine rule is scored against its canonical vulnerable/fixed example pair on every change — see BENCHMARK.md (generated, CI-enforced: a rule that stops detecting its bug, or starts flagging its fix, cannot merge).

Run it in your editor — VS Code / Cursor / Windsurf

The VS Code extension shows SOL-0XX findings as inline warning squiggles as you type, in Rust and TypeScript/JS files. Same engine as the CLI, 100% local (no telemetry). Install it from Open VSX — works in Cursor, Windsurf, and VSCodium; on stock VS Code, sideload the .vsix from extensions/vscode/ (the Microsoft Marketplace listing is pending publisher verification). Details in extensions/vscode/.

Run it with Semgrep

Already have a Semgrep pipeline? Point it at the ported ruleset:

semgrep --config https://raw.githubusercontent.com/Copenhagen0x/solana-security-standard/main/semgrep/solana-security-standard.yaml ./programs

The same SOL-0XX rules as pattern-regex rules. Details in semgrep/.

Use it in your AI coding agent — Codex · Copilot · Cursor · Windsurf · Cline · Aider

Most AI coding tools read a rules/instructions file. integrations/ ships the SOL-0XX standard in each tool's native format — all generated from the one source — so your assistant writes and reviews Solana/Anchor code against the rules. Copy the file for your tool (full matrix in integrations/README.md):

Tool Copy into your repo
Codex / any AGENTS.md agent integrations/codex/AGENTS.md
GitHub Copilot integrations/copilot/.github/copilot-instructions.md
Cursor integrations/cursor/.cursor/
Windsurf integrations/windsurf/.windsurf/
Cline integrations/cline/.clinerules
Aider integrations/aider/ (with an optional scanner lint command)

Use it via MCP — any MCP client

Prefer the Model Context Protocol? The MCP server gives any MCP client (Cline, Copilot, Cursor, Claude, Windsurf) a scan_solana_code tool plus the full rule set — no file to copy:

{ "mcpServers": { "solana-security-standard": { "command": "npx", "args": ["-y", "@jelleo/solana-security-mcp"] } } }

100% local, same scanner as the CLI. Details in mcp/.

Learn from real exploits — the Solana Hacks Database

hacks/ maps real, disclosed Solana exploits to the SOL-0XX rule class each one falls under — Wormhole, Mango Markets, Cashio, Crema, Nirvana, Cypher, Loopscale, and more ($514M+ in documented losses). Every entry is cited, and incidents no code rule can prevent (stolen keys, off-chain wallets) are flagged as such rather than misattributed — the same honesty the rest of this repo holds itself to. Browse the database →.

Every rule, explained — content/

content/ is a standalone explainer for all 37 rules: what each catches, the fix, whether it is machine-checkable or review-only, the real exploits in that class (cross-linked to the Hacks Database), and a code example where one exists. One page per rule — all generated from the standard + patterns + hacks + examples, so nothing drifts.

Grow it — the disclosures/ feed

The standard is a living one. disclosures/ ingests a new Solana disclosure — a GitHub Security Advisory, an Immunefi report, or a security-fix PR — and proposes a candidate Hacks-Database entry with suggested SOL-0XX mappings for a human to verify. It never auto-writes (a cited DB only takes reviewed entries). As an internal sanity check, the keyword classifier surfaces a labeled rule among its ranked suggestions for every exploit already catalogued — self-consistency on our own root-cause text, not a blind-accuracy or top-1 claim.

What you get

37 rules: 34 on-chain Solana program bug classes, plus 3 integrator / client-side rules (SOL-029–031) for the TypeScript/web3.js that builds and sends transactions (bots, keepers, integrators). SOL-001 covers two confirmed-exploitable bounty wins (the same caller-controlled now_slot class fixed in both the ACTIVATE and RETIRE branches of percolator). Most of the rest are drawn from documented Solana audit patterns — some from our published disclosures (with maintainer triage classifications noted in the Source column), some from public bug-class taxonomy; the integrator trio came from a live buyback-worker report.

Rule Catches Source
SOL-001 Unauthenticated now_slot / clock spoofing Bounty wins (2): percolator-prog#107 ACTIVATE + percolator-cli#78 F33 RETIRE
SOL-002 Cross-market state asymmetry → counter inflation Documented public class (percolator-prog#104) — not our bounty
SOL-003 Wrapper handler re-implements engine logic Pattern from our #78 F1 — maintainer fixed in-flight, not bountied
SOL-004 Health/penalty terms omitted from calc Pattern from our #78 F2 — engine-side, separate disclosure pending
SOL-005 Anchor realloc() without guards Latent pattern from our #78 F12 — reachable when 14-asset cap lifted
SOL-006 Missing signer check on privileged handler Generic Solana
SOL-007 Missing account.owner == program_id Generic Solana
SOL-008 Unverified PDA derivation Generic Solana
SOL-009 CPI without authority check Generic Solana
SOL-010 Reinit attack via init_if_needed Generic Solana
SOL-011 Lamport drain via account closure Generic Solana
SOL-012 Rent exemption check missing Generic Solana
SOL-013 Token Program ID confusion (Token vs Token-2022) Generic Solana
SOL-014 Unchecked integer arithmetic Generic Solana
SOL-015 Anchor has_one/constraint= missing Generic Anchor
SOL-016 Bump seed not validated against canonical bump Generic Solana
SOL-017 Raw AccountInfo without typed deserialize Generic Solana
SOL-018 Hardcoded System Program ID literal Generic Solana
SOL-019 Missing discriminator check on deserialize Generic Solana
SOL-020 SetAuthority without prior verification Generic Solana
SOL-021 Terminal/close op gated on a live-only condition → funds lock Jelleo v16 audit F1 — maintainer fixed as "Finding C"
SOL-022 Write-only "impaired" counter never decremented → funds encumbered Jelleo v16 audit F2percolator#74, code-confirmed
SOL-023 Fee/penalty rounds toward the user → evasion + leakage Jelleo v16 audit F3 (Low)
SOL-024 Stale / unchecked Pyth/Switchboard oracle price Generic Solana DeFi
SOL-025 Sysvar read by raw deserialize (not Clock::get()) Generic Solana
SOL-026 Duplicate mutable account unchecked (native + Anchor AccountLoader/remaining_accounts) Generic Solana
SOL-027 Unvalidated remaining_accounts Generic Solana
SOL-028 Missing slippage / min-out bound Generic Solana DeFi
SOL-029 Preflight simulation disabled (skipPreflight: true) on a mainnet send Integrator — live buyback-worker report (TS/web3.js)
SOL-030 Hardcoded priority fee — no congestion awareness Integrator — live buyback-worker report (TS/web3.js)
SOL-031 Jupiter quote consumed without contextSlot freshness Integrator — live buyback-worker report (TS/web3.js)
SOL-032 Decimals assumed (hardcoded scale) instead of read from the mint Jelleo audit pattern — the decimals/accounting loss-of-funds class (review-only: a scale literal isn't machine-distinguishable)
SOL-033 Account field read after a CPI without reload() — stale-state decisions Generic Anchor (documented reload footgun)
SOL-034 Manual lamport mutation desyncs the program's internal ledger Generic Solana
SOL-035 Instructions sysvar read unpinned — forged introspection spoofs a precompile/CPI-origin check Generic Solana (known precompile-bypass class)
SOL-036 Token account trusted as an ATA without canonical (owner, mint) derivation Generic Solana SPL (review-only)
SOL-037 CPI callee program id unpinned — call redirected to an attacker program Generic Solana (review-only; the callee-side gap SOL-009 doesn't cover)

Why these rules — honest provenance

We disclose exactly where each rule came from. Some are confirmed-exploitable bounty wins; some are documented patterns we surfaced but the maintainer classified differently in triage. We list both kinds because all of them are real Solana attack surfaces worth flagging — but we don't claim bounty credit we didn't earn.

  • SOL-001 — TWO confirmed-exploitable bounty wins (same class, two code paths). ACTIVATE branch: percolator-prog#107, fixed in 6512fa1. RETIRE branch: percolator-cli#78 F33, fixed in 3fd9b1d. Both maintainer-acknowledged via Lean theorem-prover models. Our suggested authenticated_slot_or_fallback patch shipped verbatim.

  • SOL-002 — public class, not our bounty. The cross-market pnl_pos_bound_tot inflation class was publicly disclosed at percolator-prog#104 by another researcher. Included because the pattern is reproducible across perp-DEX programs.

  • SOL-003, SOL-004, SOL-005 — patterns from our bounty 5 disclosure. All three were in our #78 submission (36 findings total). Maintainer triage outcomes: F1 already fixed in 0925ed4 before triage; F2 engine-side (separate disclosure pending at aeyakovenko/percolator); F12 latent (reachable when the 14-asset cap is lifted). Real Solana patterns worth flagging in future code, none paid as new bounties.

  • SOL-021, SOL-022, SOL-023 — patterns from our percolator v16 engine audit. F1 (terminal-close deadlock) was fixed by the maintainer as "Finding C". F2 (write-only impaired insurance counter) is disclosed at percolator#74 — code-confirmed, not yet reproduced on-chain. F3 (fee rounding) is Low. Code-analysis patterns, not claimed as paid bounties.

The remaining rules (SOL-006 through SOL-020, plus SOL-024 through SOL-028) cover documented Solana / DeFi audit patterns — signer/owner/PDA verification, Anchor constraints, CPI authority, lamport drains, Token Program ID confusion, integer overflow, oracle staleness, slippage bounds, etc. Standard auditor checklist territory.

All published cycle reports: jelleo.com/cycles

How it works

The standard is two source files — a YAML of deterministic patterns and a Markdown threat-model + rule catalog — plus a self-contained scanner. Every surface runs the same rules: the CLI, GitHub Action, editor extension, MCP server, and Semgrep apply them directly. In Claude Code specifically, Anthropic's security-guidance plugin reads the two files and reviews edits at three layers:

  1. On each file edit — fast pattern match (no model call). Reads .claude/security-patterns.yaml for regex/substring rules. Our file provides 23 deterministic patterns.
  2. At the end of each turn — background model review of the full diff. Reads .claude/claude-security-guidance.md for semantic guidance. Our file provides the Solana threat model + 37-rule catalog + review checklist.
  3. On each commit Claude makes — deeper agentic review that reads surrounding code. Uses the same guidance file.

Every time a rule fires, the reminder text includes the rule ID (e.g. Jelleo SOL-001:) and a link back to this repo so you can see the underlying bounty case study.

Examples

The examples/ directory contains 23 paired vulnerable/fixed snippets — one for every machine-checkable rule (Rust on-chain; TypeScript for the integrator rules). They're self-tested: the scanner must fire on each vulnerable file and clear on each fixed one, so they can't drift from the rules. Useful for understanding a bug class before reading the rule definition.

Versioning

This repo follows Semantic Versioning. Pin a tagged release rather than main (the plugin-guidance.md digest ships from v1.11.0 onward — before that tag exists, use the Quick install from main):

curl -sL https://raw.githubusercontent.com/Copenhagen0x/solana-security-standard/v1.11.0/plugin-guidance.md \
     -o .claude/claude-security-guidance.md

A bare curl like this has no integrity check — for checksum + signed-tag verification use the Verified install flow above.

See CHANGELOG.md for the full version history.

Maintained by

Jelleo — continuous Solana program audits. Every cycle is Ed25519-signed and Merkle-rooted; all artifacts public at jelleo.com/cycles.

Each new bounty cycle we publish adds rules to this guidance. If you want a deeper audit of your Solana program, see jelleo.com.