solana-security

solana-security is a cursor rule for Cursor from Copenhagen0x/solana-security-standard. It costs 2,113 tokens per session, scanned A, original, MIT.

A security checklist for Solana programs and transaction-sending JavaScript or TypeScript, treating every caller as potentially hostile.

In plain words
What is it for?
Reviewing or fixing Anchor/Rust on-chain programs and the specified off-chain code, with findings tied to SOL rule identifiers.
Why use it?
It helps identify authorization, accounting, stale-data, and transaction-integration mistakes before they become blockchain vulnerabilities.

Cursor rule for Cursor

Written for Cursor: installed under .cursor/.

Good fit Reviewing or fixing Anchor/Rust on-chain programs and the specified off-chain code, with findings tied to SOL rule identifiers.

Compare 6 cursor rules from other repositories ↓
Install with agentmods
npx agentmods add rules/copenhagen0x/solana-security-standard/solana-security
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Clone the repo
git clone --depth 1 https://github.com/Copenhagen0x/solana-security-standard

Made for: Cursor.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for solana-security

README.md
[![agentmods](https://agentmods.dev/badge/rules/copenhagen0x/solana-security-standard/solana-security.svg)](https://agentmods.dev/rules/copenhagen0x/solana-security-standard/solana-security)
Your own site
<a href="https://agentmods.dev/rules/copenhagen0x/solana-security-standard/solana-security"><img src="https://agentmods.dev/badge/rules/copenhagen0x/solana-security-standard/solana-security.svg" alt="Measured on agentmods" height="20"></a>
Per session 2,113 This file is loaded in full into every session.
When invoked 2,113 The same file — it is already loaded in full.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.02113 $0.02113
Opus 5 $0.01056 $0.01056
Sonnet 5 $0.00423 $0.00423
Haiku 4.5 $0.00211 $0.00211

Measured 8d ago against content hash d8668e6a27f3, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-08, from the pricing page.

Security

Grade A, and why

solana-security scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 8d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

integrations/cursor/.cursor/rules/solana-security.mdc · 70 lines

How it starts

The opening of the file, as written. The whole thing — 70 lines — stays where its author put it; the contents beside it link to each section on GitHub.

When you write, edit, or review Solana code in this project — on-chain Anchor/Rust programs AND the TypeScript/JavaScript that builds and sends transactions (bots, keepers, integrators) — apply the Solana Security Standard (SOL-0XX) below. Solana programs are stateless: treat every caller as hostile until cryptographically proven otherwise. For each rule, flag the pattern, fix it as described, and cite the SOL-0XX id in your explanation. Off-chain code (client / cli / offchain / sdk / tests) is generally exempt from the on-chain (Rust) rules, EXCEPT the integrator rules SOL-029..031, which apply specifically to that transaction-sending TypeScript/JavaScript. Full catalog: https://github.com/Copenhagen0x/solana-security-standard . Audits: jelleo.com .

Threat model

Assume every caller is hostile until cryptographically proven otherwise. Dominant classes: trust-boundary breaks (instruction data → trusted state), authority confusion (signer/PDA/owner), state integrity (cross-market leaks), time & lifecycle (caller clocks, terminal guards), value accounting (decimals, lamports, post-CPI staleness), oracle trust (stale prices), Anchor gaps (constraints, init_if_needed, bump). Integrator layer (SOL-029-031): off-chain TS/JS tx code (preflight, fees, stale routes), flagged on .ts/.js.

Review checklist

Critical first: SOL-001, 003, 004, 021, 023, 024, 015, 006/007, 014, 019, 032, 033, 034 (titles below).

Rules — flag the pattern, apply the fix, cite the SOL-0XX id

  • SOL-001 · Unauthenticated now_slot — authenticate against Clock::get()?.slot
  • SOL-002 · Cross-market state asymmetry — gate every write by per-market authorization
  • SOL-003 · Wrapper re-implements engine — delegate to the engine; the wrapper only marshals accounts
  • SOL-004 · Penalty/health terms omitted — include every term the spec lists
  • SOL-005 · Anchor resize without checks — verify all three before resizing
  • SOL-006 · Missing signer check — Signer<>, or check is_signer
  • SOL-007 · Missing owner verification — check owner first
  • SOL-008 · Unverified PDA — derive and compare
  • SOL-009 · CPI without authority check — check authority before the CPI
  • SOL-010 · Reinit attack — reject a re-init before the write (check discriminator)
  • SOL-011 · Lamport drain via close — drain + zero + controlled destination
  • SOL-012 · Rent exemption check missing — assert rent-exempt
  • SOL-013 · Token Program ID confusion — anchor_spl::token::ID via typed accounts
  • SOL-014 · Unchecked integer arithmetic — a.checked_add(b).ok_or(Overflow)?
  • SOL-015 · Anchor constraints missing — tie related accounts together with constraints
  • SOL-016 · Bump seed unvalidated — bare bump / find_program_address
  • SOL-017 · Raw AccountInfo without typed deserialize — typed deserialize + length/field checks
  • SOL-018 · Hardcoded System Program ID — solana_program::system_program::ID
  • SOL-019 · Missing discriminator check — try_deserialize
  • SOL-020 · SetAuthority without verification — verify current authority first
  • SOL-021 · Terminal op gated on a live-only condition — a terminal release that ignores freshness/expiry
  • SOL-022 · Write-only "impaired" counter — add the inverse settlement
  • SOL-023 · Fee/penalty rounds toward the user — div_ceil what the user owes — round against the less-trusted party (fee UP, payout DOWN)
  • SOL-024 · Stale / unchecked oracle price — get_price_no_older_than(...); reject wide-confidence
  • SOL-025 · Sysvar read by raw deserialize — Clock::get() / Anchor Sysvar<>
  • SOL-026 · Duplicate mutable account (native programs) — require_keys_neq!
  • SOL-027 · Unvalidated remaining_accounts — validate every account like a declared one
  • SOL-028 · Missing slippage / min-out bound — take + enforce a caller bound
  • SOL-029 · Preflight simulation disabled — keep preflight on, or simulate + assert err === null
  • SOL-030 · Static priority fee — derive from getRecentPrioritizationFees() and clamp
  • SOL-031 · Stale Jupiter quote — refetch/reject when contextSlot lags the current slot
  • SOL-032 · Decimals assumed, not read — read mint.decimals; normalize first
  • SOL-033 · Stale account read after CPI — reload() / re-read after the CPI
  • SOL-034 · Manual lamport mutation — mutate both sides; assert conservation
  • SOL-035 · Instructions sysvar substitution — pin the sysvar (Anchor Sysvar<Instructions>, or assert key == sysvar::instructions::ID) AND validate the introspected instruction's program id plus its parsed signer pubkey and message against the expected values — confirming only that "a precompile ran" is bypassable with any real signature
  • SOL-036 · ATA derivation unpinned — Anchor associated_token::mint + associated_token::authority constraints, or compare against get_associated_token_address(owner, mint) (owner+mint from validated on-chain state, not caller data) before use
  • SOL-037 · Arbitrary CPI target — pin the callee — a typed Program<'info, T>, or assert the program id equals the expected constant — AND validate the accounts (and any PDA-signer seeds/amounts) passed into the CPI; pinning the program alone leaves account substitution / confused-deputy open (see SOL-027)
  • SOL-038 · PDA seed collision — fixed-width per-type seed tag of a consistent width across the registry (e.g. all u32) from one program-wide enum registry (never per-file constants, never mixed tag widths); hash/length-prefix every variable element or separate two variables with a fixed-width element, never adjoin two unbounded ones
  • SOL-039 · Asymmetric partial-CPI state — propagate the CPI with ? so the whole instruction reverts; if you must catch the error, roll back every prior self-mutation
  • SOL-040 · Credit from requested, not measured (Token-2022) — credit the measured pre/post balance delta (reload() before/after), not the requested amount; pin BOTH the destination ATA mint AND authority (a measured delta alone is not enough)
  • SOL-041 · Forced-balance / supply desync — drive math from a program-owned recorded ledger updated by measured deltas; read the raw balance only to assert live >= recorded
  • SOL-042 · Unbounded account-iteration compute DoS — require!(list.len() <= MAX) with MAX proven to fit the CU budget, or paginate across txns with a stored cursor
  • SOL-043 · Unbounded storage / slot-exhaustion griefing — per-caller fixed-size caller-paid PDAs, or a self-limiting shared cap (decrement-on-close + a refundable stake); admin-gate close
  • SOL-044 · Hardcoded slot-time rate — accrue on Clock::get()?.unix_timestamp deltas (store last_update_ts), never a hardcoded slots-per-period constant
  • SOL-045 · Incremental Merkle insertion error — delegate root maintenance AND proof verification to spl-account-compression via CPI (pin merkle_tree.owner); else differential-test the tree
  • SOL-046 · Hand-rolled dispatch bypasses framework guards — route through #[program] + #[derive(Accounts)], or manually re-validate every account on every native arm (discriminator, owner, PDA, signer)
  • SOL-047 · Forged receipt token / mint — pin the receipt mint to the stored canonical mint (address = vault.receipt_mint) AND bind the burned account's token::mint
  • SOL-048 · Default/zero value accepted as valid — reject the zero sentinel at the gate (require_keys_neq!(stored, Pubkey::default())) and assert is_initialized on a bound config account
  • SOL-049 · Struct-padding / non-canonical flag read — use Anchor #[account(zero_copy)] / the real Pod derive (never a hand unsafe impl); store flags as u8 and assert canonicality on every load and write AND validate the account owner + discriminator (canonicalization alone is bypassable)
  • SOL-050 · Serialization symmetry mismatch — pack and unpack through ONE shared (de)serializer over the same type; guard with a size_of tripwire + a unpack(pack(x)) == x test
  • SOL-051 · Predictable on-chain entropy — use a VRF (Switchboard/ORAO) or a real commit-reveal; owner-check the oracle result account and bind it to this draw
  • SOL-052 · Token-2022 semantics assumed — pin classic Program<Token> on every token CPI, or measure the received delta and reject unsupported Token-2022 extensions before value moves

Read the full file on GitHub · 70 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 8d ago First seen · 70 lines · 2,113 tokens per session scan A d8668e6a27f3

Subscribe to this mod's changes

solana-security is a cursor rule published in the GitHub repository Copenhagen0x/solana-security-standard (37 stars, last pushed 6d ago), licensed MIT. It adds 2,113 tokens to every session, about $0.0106 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.