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.
git clone --depth 1 https://github.com/Copenhagen0x/solana-security-standardWrote 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.
[](https://agentmods.dev/rules/copenhagen0x/solana-security-standard/solana-security)<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>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.
| Model | Per session | Once 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 |
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.
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 checkis_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::IDvia 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_ceilwhat 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()/ AnchorSysvar<> - 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
contextSlotlags 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 assertkey == 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::authorityconstraints, or compare againstget_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_timestampdeltas (storelast_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'stoken::mint - SOL-048 · Default/zero value accepted as valid — reject the zero sentinel at the gate (
require_keys_neq!(stored, Pubkey::default())) and assertis_initializedon a bound config account - SOL-049 · Struct-padding / non-canonical flag read — use Anchor
#[account(zero_copy)]/ the realPodderive (never a handunsafe 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_oftripwire + aunpack(pack(x)) == xtest - 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
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.
- 8d ago First seen · 70 lines · 2,113 tokens per session scan A d8668e6a27f3
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.
Other cursor rules, from other repositories
binding-rules-quick-reference
Quick index of project binding rules (canonical text in CLAUDE.md).
go-conventions
Go conventions for all Go code (modules, naming, errors, logging, metrics).
ponytail
Ponytail, lazy senior dev mode. Always pick the simplest solution that works.
angular-20
This rule provides comprehensive best practices and coding standards for Angular development, focusing on modern TypeScript, standalone components, signals, and performance optimizations.
dev-standard
Apache Superset development standards and guidelines for Cursor IDE.
cli-error-handling
CLI command error handling patterns.