# Security checks

This chapter enumerates the built-in security rules. Each rule is identified by a `rule_id`; rule IDs are stable across releases and are the recommended granularity for `disabled_rules` entries in `.solforge.toml`.

The catalogue below is grouped by category. Severities are the *default* severity emitted by each rule; in some cases a rule emits at a higher severity when additional conditions hold, in which case the variation is noted in the rule's description.

## Account-validation rules

### `missing-signer-check` — *high*

Triggers on any instruction that mutates an account without requiring a `Signer` constraint somewhere in the same instruction. The rule recognises both Anchor's `#[account(signer)]` constraint and the lower-level `isSigner=true` field on the IDL account.

A common false-positive source is an instruction whose mutation is justified by a CPI from a program-derived address; in that case, mark the instruction with the `solforge:cpi-only` IDL tag and the rule will skip it.

### `missing-owner-check` — *high*

Triggers on instructions whose mutable accounts are not constrained to a known owner. An account whose owner is implied by Anchor's `Account<'info, T>` wrapper is not flagged; an account passed as `AccountInfo` without a manual owner check is.

### `arbitrary-cpi` — *critical*

Triggers when an instruction performs a CPI to a program ID derived from an account passed at runtime, rather than to a known program ID. This is almost always a bug; the rule emits at *critical* unless the destination ID is constrained by an `address = <pubkey>` Anchor constraint.

## Authority-management rules

### `bump-not-canonical` — *medium*

Triggers when a PDA is constructed with a bump value taken from instruction input rather than computed from `find_program_address`. Anchor 0.27+ enforces the canonical bump by default, but programs that hand-roll PDAs may bypass the check.

### `closed-account-rehydration` — *high*

Triggers when an account marked `close = receiver` is referenced by another instruction without a fresh existence check. A closed account whose lamports were not zeroed can be rehydrated in the same transaction with attacker-controlled data.

## Arithmetic rules

### `unchecked-math` — *medium*

Triggers when an instruction handler performs arithmetic on a `u64` value without using the `checked_*` family of methods. The rule reads the IDL's instruction body where available; for programs whose Rust source is not adjacent to the IDL, the rule downgrades itself to `info`.

### `lossy-cast` — *low*

Triggers on casts from a wider integer to a narrower one without a bounds check. This is rarely a security finding on its own; the rule exists to support the recipe in [Reproducing mainnet bugs locally](/solanatestforge-docs/part-iii-recipes/reproducing-mainnet-bugs.md), where a real-world incident hinged on a `u64 → u32` cast.

## Reentrancy rules

### `cpi-before-state-mutation` — *high*

Triggers on instructions that issue a CPI before all of their account mutations have been written. Solana's runtime does not protect against reentrancy in the EVM sense, but a reordered CPI can still expose intermediate state to an attacker who has placed a callback in the destination program.

## Disabling a rule

To skip a rule for a single project, add its ID to `[security].disabled_rules` in `.solforge.toml`. The rule will not be evaluated and will not appear in the report. This is the recommended way to acknowledge a rule as out of scope.

To skip a rule for a single run, pass `--disable-rule <id>` on the command line. This is appropriate for one-off debugging; for permanent decisions, prefer the configuration file.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://solanatestforge.gitbook.io/solanatestforge-docs/part-ii-reference/security-checks.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
