anchor-audit 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +699 -19
- package/dist/index.js +1 -1
- package/dist/reporter.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,28 +1,708 @@
|
|
|
1
|
-
# anchor-audit
|
|
1
|
+
# anchor-audit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/anchor-audit)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
A security audit toolkit for [Anchor](https://www.anchor-lang.com/) smart contracts on Solana.
|
|
6
|
+
|
|
7
|
+
Anchor programs handle real money on-chain. A single missing signer check or unchecked arithmetic operation can drain a protocol entirely. `anchor-audit` gives developers a fast, structured first pass over their code before it ships.
|
|
8
|
+
|
|
9
|
+
> **Disclaimer:** `anchor-audit` is a triage aid, not a substitute for a professional human audit. See [Limitations](#limitations).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What is anchor-audit?
|
|
14
|
+
|
|
15
|
+
`anchor-audit` checks your Rust/Anchor source files against a catalog of **50 known Solana security rules** - things like missing signer checks, arbitrary CPI targets, arithmetic overflows, and reinitialization attacks. It sends your code to an AI model that reads each rule and flags any matching patterns, then formats the results into a structured report.
|
|
16
|
+
|
|
17
|
+
It ships as two tools that share the same 50-rule catalog:
|
|
18
|
+
|
|
19
|
+
| Tool | What it is | When to use it |
|
|
20
|
+
|------|-----------|----------------|
|
|
21
|
+
| **Claude Code Skill** | A prompt skill for Claude Code | When you're already in a Claude Code session and want a quick review |
|
|
22
|
+
| **CLI (`anchor-audit`)** | A command-line tool | When you want a full automated report you can save, diff, and share |
|
|
23
|
+
|
|
24
|
+
Both tools stay in sync: when a rule is improved in `/rules/`, both the skill and the CLI benefit automatically.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Table of Contents
|
|
29
|
+
|
|
30
|
+
- [Quick Start](#quick-start)
|
|
31
|
+
- [Claude Code Skill](#claude-code-skill)
|
|
32
|
+
- [CLI Setup](#cli-setup)
|
|
33
|
+
- [Cloud Providers](#cloud-providers)
|
|
34
|
+
- [Local Models](#local-models-no-api-key-no-cost)
|
|
35
|
+
- [Running an Audit](#running-an-audit)
|
|
36
|
+
- [Understanding the Flags](#understanding-the-flags)
|
|
37
|
+
- [Reading the Report](#reading-the-report)
|
|
38
|
+
- [Performance Guide](#performance-guide)
|
|
39
|
+
- [Rule Catalog](#rule-catalog)
|
|
40
|
+
- [Limitations](#limitations)
|
|
41
|
+
- [Contributing](#contributing)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
**Option A - Claude Code Skill (fastest):**
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/guptaaayush432/anchor-audit
|
|
50
|
+
cp anchor-audit/SKILL.md ~/.claude/skills/anchor-audit.md
|
|
51
|
+
# Then in any Claude Code session: "audit my program in ./programs/my-vault"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Option B - CLI with a cloud provider:**
|
|
55
|
+
```bash
|
|
56
|
+
npm install -g anchor-audit
|
|
57
|
+
|
|
58
|
+
# Copy the example env file and add your key
|
|
59
|
+
cp .env.example .env
|
|
60
|
+
# Edit .env and fill in the key for your chosen provider
|
|
61
|
+
|
|
62
|
+
# Basic run - uses Anthropic claude-sonnet-4-6 by default
|
|
63
|
+
anchor-audit ./programs/my-vault
|
|
64
|
+
|
|
65
|
+
# Show progress as each rule batch is processed
|
|
66
|
+
anchor-audit ./programs/my-vault --verbose
|
|
67
|
+
|
|
68
|
+
# Use a different provider or model
|
|
69
|
+
anchor-audit ./programs/my-vault --provider openai --model gpt-4o
|
|
70
|
+
anchor-audit ./programs/my-vault --provider groq
|
|
71
|
+
|
|
72
|
+
# Only check critical and high severity rules (faster)
|
|
73
|
+
anchor-audit ./programs/my-vault --severity high
|
|
74
|
+
|
|
75
|
+
# Deeper analysis with more output per finding
|
|
76
|
+
anchor-audit ./programs/my-vault --effort high
|
|
77
|
+
|
|
78
|
+
# Fast triage - high severity rules only, low token budget
|
|
79
|
+
anchor-audit ./programs/my-vault --severity high --effort low
|
|
80
|
+
|
|
81
|
+
# Save report to a file
|
|
82
|
+
anchor-audit ./programs/my-vault --output AUDIT.md
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Option C - CLI with Ollama (free, runs locally):**
|
|
86
|
+
```bash
|
|
87
|
+
npm install -g anchor-audit
|
|
88
|
+
ollama pull llama3.1:8b
|
|
89
|
+
anchor-audit ./programs/my-vault --provider ollama --effort low
|
|
90
|
+
# Change the model and reasoning effort accordingly
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Claude Code Skill
|
|
96
|
+
|
|
97
|
+
The Claude Code Skill lets you audit Anchor programs directly inside a Claude Code session - no API key needed beyond your existing Claude/Codex subscription, no extra installation beyond copying one file.
|
|
98
|
+
|
|
99
|
+
### Install
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/guptaaayush432/anchor-audit
|
|
103
|
+
cp anchor-audit/SKILL.md ~/.claude/skills/anchor-audit.md
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### How to use it
|
|
107
|
+
|
|
108
|
+
Once installed, Claude/Codex picks up the skill automatically whenever you ask it to review Anchor code. Just describe what you want in plain English:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
> audit my anchor program in ./programs/my-vault
|
|
112
|
+
> review the withdraw instruction for authorization issues
|
|
113
|
+
> check this code for unchecked arithmetic
|
|
114
|
+
> does my vault have any CPI safety issues?
|
|
115
|
+
> look for missing signer checks in programs/staking/src/lib.rs
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Claude/Codex will read your source files, apply the 50-rule catalog, and respond with a structured list of findings.
|
|
119
|
+
|
|
120
|
+
### When to use the Skill vs the CLI
|
|
121
|
+
|
|
122
|
+
| | Skill | CLI |
|
|
123
|
+
|--|-------|-----|
|
|
124
|
+
| Requires separate API key | No | Yes (or local model) |
|
|
125
|
+
| Interactive follow-up questions | Yes | No |
|
|
126
|
+
| Saves a report file automatically | No | Yes |
|
|
127
|
+
| Full 50-rule batch scan | Depends on context | Always |
|
|
128
|
+
| Good for | Quick reviews while coding | Full audits before shipping |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## CLI Setup
|
|
133
|
+
|
|
134
|
+
### Requirements
|
|
135
|
+
|
|
136
|
+
- Node.js 20 or later (`node --version` to check)
|
|
137
|
+
- An AI provider - cloud (needs API key) or local (needs Ollama/LM Studio/vLLM running)
|
|
138
|
+
|
|
139
|
+
### Install
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
npm install -g anchor-audit
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Verify it works:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
anchor-audit --help
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Cloud Providers
|
|
154
|
+
|
|
155
|
+
Cloud providers are the easiest to start with and produce the most accurate results.
|
|
156
|
+
|
|
157
|
+
### Setting up your API key
|
|
158
|
+
|
|
159
|
+
All API keys are loaded from a `.env` file in your project root. Copy the example file and fill in the key for the provider you want to use:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
cp .env.example .env
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Then open `.env` and add your key:
|
|
166
|
+
|
|
167
|
+
```env
|
|
168
|
+
# Only fill in the provider you plan to use
|
|
169
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
170
|
+
OPENAI_API_KEY=sk-...
|
|
171
|
+
GEMINI_API_KEY=...
|
|
172
|
+
GROQ_API_KEY=gsk_...
|
|
173
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Never use `export KEY=...` in your terminal - that sets the key globally for all tools and sessions, which can accidentally bill API credits when you did not intend to.
|
|
177
|
+
|
|
178
|
+
### Anthropic (default, recommended)
|
|
179
|
+
|
|
180
|
+
Best overall accuracy for security auditing. Uses `claude-sonnet-4-6` by default.
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# In .env: ANTHROPIC_API_KEY=sk-ant-...
|
|
184
|
+
anchor-audit ./programs/my-vault
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Where to get a key:** [console.anthropic.com](https://console.anthropic.com)
|
|
188
|
+
|
|
189
|
+
For the deepest analysis, use a more powerful model:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
anchor-audit ./programs/my-vault --model claude-opus-4-8
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### OpenAI (ChatGPT)
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# In .env: OPENAI_API_KEY=sk-...
|
|
199
|
+
anchor-audit ./programs/my-vault --provider openai
|
|
200
|
+
anchor-audit ./programs/my-vault --provider openai --model gpt-4o
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Where to get a key:** [platform.openai.com](https://platform.openai.com)
|
|
204
|
+
|
|
205
|
+
### Google Gemini
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
# In .env: GEMINI_API_KEY=...
|
|
209
|
+
anchor-audit ./programs/my-vault --provider google
|
|
210
|
+
anchor-audit ./programs/my-vault --provider google --model gemini-2.0-flash
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
**Where to get a key:** [aistudio.google.com](https://aistudio.google.com)
|
|
214
|
+
|
|
215
|
+
### Groq
|
|
216
|
+
|
|
217
|
+
Groq offers a generous free tier - a good way to try the tool at no cost with a cloud model.
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# In .env: GROQ_API_KEY=gsk_...
|
|
221
|
+
anchor-audit ./programs/my-vault --provider groq
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Where to get a key:** [console.groq.com](https://console.groq.com)
|
|
225
|
+
|
|
226
|
+
### OpenRouter (access 100+ models with one key)
|
|
227
|
+
|
|
228
|
+
OpenRouter routes to Anthropic, OpenAI, Meta, Mistral, and many others. Useful if you want to compare results across models.
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# In .env: OPENROUTER_API_KEY=sk-or-...
|
|
232
|
+
anchor-audit ./programs/my-vault --provider openrouter
|
|
233
|
+
anchor-audit ./programs/my-vault --provider openrouter --model meta-llama/llama-3.3-70b-instruct
|
|
234
|
+
anchor-audit ./programs/my-vault --provider openrouter --model google/gemini-2.0-flash
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Where to get a key:** [openrouter.ai](https://openrouter.ai)
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Local Models (no API key, no cost)
|
|
242
|
+
|
|
243
|
+
> **Warning:** Local models produce significantly worse results than cloud models. In testing, an 8B local model (qwen3 via Ollama) returned zero findings on a real-world program that a cloud model flagged multiple issues in. Use local models only for quick exploratory checks during development - never for a final audit before shipping.
|
|
244
|
+
|
|
245
|
+
Local models run entirely on your machine. No data leaves your computer, there are no API costs, and you can audit private code without sending it to a third party.
|
|
246
|
+
|
|
247
|
+
The trade-off is speed and accuracy - local models are slower and miss many real issues that a cloud model would catch. See [Performance Guide](#performance-guide) for tips.
|
|
248
|
+
|
|
249
|
+
### Ollama
|
|
250
|
+
|
|
251
|
+
[Ollama](https://ollama.com) is the easiest way to run local models on macOS, Linux, or Windows.
|
|
252
|
+
|
|
253
|
+
**Step 1 - Install Ollama:**
|
|
254
|
+
```bash
|
|
255
|
+
# macOS
|
|
256
|
+
brew install ollama
|
|
257
|
+
|
|
258
|
+
# Or download from https://ollama.com
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Step 2 - Pull a model:**
|
|
262
|
+
```bash
|
|
263
|
+
# Small and fast (good for quick checks)
|
|
264
|
+
ollama pull llama3.1:8b
|
|
265
|
+
|
|
266
|
+
# Larger and more accurate (slower)
|
|
267
|
+
ollama pull qwen2.5-coder:32b
|
|
268
|
+
ollama pull llama3.3:70b
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Step 3 - Start the Ollama server** (it may already be running):
|
|
272
|
+
```bash
|
|
273
|
+
ollama serve
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Step 4 - Run the audit:**
|
|
277
|
+
```bash
|
|
278
|
+
# No API key needed
|
|
279
|
+
anchor-audit ./programs/my-vault --provider ollama --model llama3.1:8b
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
To use a non-default port:
|
|
283
|
+
```bash
|
|
284
|
+
anchor-audit ./programs/my-vault --provider ollama \
|
|
285
|
+
--base-url http://localhost:5000/v1 \
|
|
286
|
+
--model llama3.1:8b
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### LM Studio
|
|
290
|
+
|
|
291
|
+
[LM Studio](https://lmstudio.ai) provides a desktop GUI for downloading and running local models.
|
|
292
|
+
|
|
293
|
+
**Step 1** - Download and open LM Studio
|
|
294
|
+
**Step 2** - Download a model from the Discover tab (e.g. Mistral 7B, Qwen 2.5)
|
|
295
|
+
**Step 3** - Go to the Local Server tab and click **Start Server**
|
|
296
|
+
**Step 4** - Run the audit:
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
# LM Studio's server runs on port 1234 by default
|
|
300
|
+
anchor-audit ./programs/my-vault --provider lmstudio --model local-model
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
The `--model local-model` value is a placeholder - LM Studio uses whichever model is currently loaded in its UI.
|
|
304
|
+
|
|
305
|
+
### vLLM
|
|
306
|
+
|
|
307
|
+
[vLLM](https://vllm.ai) is a high-throughput inference engine for production-grade local deployments.
|
|
308
|
+
|
|
309
|
+
```bash
|
|
310
|
+
# Start vLLM server first (example)
|
|
311
|
+
python -m vllm.entrypoints.openai.api_server \
|
|
312
|
+
--model mistralai/Mistral-7B-Instruct-v0.3 \
|
|
313
|
+
--port 8000
|
|
314
|
+
|
|
315
|
+
# Then run the audit
|
|
316
|
+
anchor-audit ./programs/my-vault --provider vllm --model mistralai/Mistral-7B-Instruct-v0.3
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Custom endpoint
|
|
320
|
+
|
|
321
|
+
Any server that speaks the OpenAI chat completions API format works with `--provider custom`:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
anchor-audit ./programs/my-vault \
|
|
325
|
+
--provider custom \
|
|
326
|
+
--base-url http://192.168.1.10:8080/v1 \
|
|
327
|
+
--model my-model-name
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## Running an Audit
|
|
333
|
+
|
|
334
|
+
### Basic usage
|
|
6
335
|
|
|
7
336
|
```bash
|
|
8
|
-
|
|
337
|
+
# Print findings to the terminal
|
|
338
|
+
anchor-audit ./programs/my-vault
|
|
339
|
+
|
|
340
|
+
# Save to a file
|
|
341
|
+
anchor-audit ./programs/my-vault --output AUDIT.md
|
|
342
|
+
|
|
343
|
+
# Show progress as each rule batch is sent to the model
|
|
344
|
+
anchor-audit ./programs/my-vault --verbose
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Filter by severity
|
|
348
|
+
|
|
349
|
+
`--severity` controls **which rules are checked**. Rules below the chosen level are skipped entirely - fewer rules means fewer batches, which means a faster run.
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
--severity critical → 4 rules → 1 batch (fastest)
|
|
353
|
+
--severity high → 25 rules → 5 batches
|
|
354
|
+
--severity medium → 42 rules → 9 batches
|
|
355
|
+
--severity low → 50 rules → 10 batches (default, slowest)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Only check the 4 most critical rules (missing signer, owner, auth, arbitrary CPI)
|
|
360
|
+
anchor-audit ./programs/my-vault --severity critical
|
|
361
|
+
|
|
362
|
+
# Check critical + high rules (covers the most dangerous 25 rules)
|
|
363
|
+
anchor-audit ./programs/my-vault --severity high
|
|
364
|
+
|
|
365
|
+
# Check everything (default)
|
|
366
|
+
anchor-audit ./programs/my-vault
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### Control analysis depth
|
|
370
|
+
|
|
371
|
+
`--effort` controls **how many output tokens the model is allowed to generate per batch**. More tokens means the model can write longer, more detailed findings - but each batch takes longer.
|
|
372
|
+
|
|
373
|
+
| Effort | Max tokens | Best for |
|
|
374
|
+
|--------|-----------|----------|
|
|
375
|
+
| `low` | 2,048 | Local models, fast triage |
|
|
376
|
+
| `medium` | 4,096 | Default, balanced |
|
|
377
|
+
| `high` | 8,192 | Cloud models, thorough reports |
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
# Fast triage - good for local models or quick CI checks
|
|
381
|
+
anchor-audit ./programs/my-vault --effort low --severity high
|
|
382
|
+
|
|
383
|
+
# Deep analysis - good for pre-release audits with a cloud model
|
|
384
|
+
anchor-audit ./programs/my-vault --effort high
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Run only specific rules
|
|
388
|
+
|
|
389
|
+
If you already know which issues to look for, skip the rest:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# Check only for missing signer (001), arbitrary CPI (017), and missing auth (030)
|
|
393
|
+
anchor-audit ./programs/my-vault --rules 001,017,030
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### JSON output
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Print JSON to stdout
|
|
400
|
+
anchor-audit ./programs/my-vault --format json
|
|
401
|
+
|
|
402
|
+
# Save JSON to file
|
|
403
|
+
anchor-audit ./programs/my-vault --format json --output audit.json
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Combining flags
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
# Recommended for local models: fast, focused on high-severity issues
|
|
410
|
+
anchor-audit ./programs/my-vault \
|
|
411
|
+
--provider ollama --model llama3.1:8b \
|
|
412
|
+
--severity high --effort low \
|
|
413
|
+
--verbose
|
|
414
|
+
|
|
415
|
+
# Recommended for pre-release audit with Anthropic
|
|
416
|
+
anchor-audit ./programs/my-vault \
|
|
417
|
+
--provider anthropic --model claude-opus-4-8 \
|
|
418
|
+
--effort high \
|
|
419
|
+
--output AUDIT_$(date +%Y-%m-%d).md
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Understanding the Flags
|
|
425
|
+
|
|
426
|
+
| Flag | Default | Description |
|
|
427
|
+
|------|---------|-------------|
|
|
428
|
+
| `--provider <name>` | `anthropic` | Which AI provider to use. See [Providers](#cloud-providers) |
|
|
429
|
+
| `--model <id>` | per-provider | Override the default model for the chosen provider |
|
|
430
|
+
| `--api-key <key>` | env var | Pass your API key inline instead of via environment variable |
|
|
431
|
+
| `--base-url <url>` | per-provider | Override the server URL (useful for local models on non-default ports) |
|
|
432
|
+
| `--severity <level>` | `low` | Only check rules at this level or above. Does not filter the *output* - it skips rules entirely |
|
|
433
|
+
| `--effort <level>` | `medium` | How many tokens the model can use per batch. Higher = more detail, slower |
|
|
434
|
+
| `--rules <ids>` | all 50 | Comma-separated list of rule IDs to run, e.g. `001,017,030` |
|
|
435
|
+
| `--format <fmt>` | `markdown` | Output format: `markdown` or `json` |
|
|
436
|
+
| `--output <path>` | - | Write the report to this file in addition to the auto-saved copy |
|
|
437
|
+
| `--verbose` | off | Print each batch as it's sent to the model - useful for tracking progress |
|
|
438
|
+
|
|
439
|
+
**Provider defaults:**
|
|
440
|
+
|
|
441
|
+
| Provider | Type | Default model | API key env var |
|
|
442
|
+
|----------|------|--------------|-----------------|
|
|
443
|
+
| `anthropic` | Cloud | `claude-sonnet-4-6` | `ANTHROPIC_API_KEY` |
|
|
444
|
+
| `openai` | Cloud | `gpt-4o` | `OPENAI_API_KEY` |
|
|
445
|
+
| `google` | Cloud | `gemini-2.0-flash` | `GEMINI_API_KEY` |
|
|
446
|
+
| `groq` | Cloud | `llama-3.3-70b-versatile` | `GROQ_API_KEY` |
|
|
447
|
+
| `openrouter` | Cloud | `anthropic/claude-sonnet-4-6` | `OPENROUTER_API_KEY` |
|
|
448
|
+
| `ollama` | Local | `llama3.1:8b` | none required |
|
|
449
|
+
| `lmstudio` | Local | `local-model` | none required |
|
|
450
|
+
| `vllm` | Local | `local-model` | none required |
|
|
451
|
+
| `custom` | Either | `gpt-4o` | `OPENAI_API_KEY` |
|
|
452
|
+
|
|
453
|
+
**Exit codes:**
|
|
454
|
+
|
|
455
|
+
| Code | Meaning |
|
|
456
|
+
|------|---------|
|
|
457
|
+
| `0` | Audit complete - no critical or high findings |
|
|
458
|
+
| `1` | Audit complete - at least one critical or high finding was found |
|
|
459
|
+
| `2` | Error - bad path, missing API key, connection refused, etc. |
|
|
460
|
+
|
|
461
|
+
Exit code `1` is useful in CI: add `anchor-audit` as a pipeline step and it will block the build if critical issues are found.
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Reading the Report
|
|
466
|
+
|
|
467
|
+
Every audit produces a markdown report with three sections:
|
|
468
|
+
|
|
469
|
+
### Audit Metadata
|
|
470
|
+
|
|
471
|
+
At the top of every report, you'll see exactly how and when it was generated:
|
|
9
472
|
|
|
10
|
-
Options:
|
|
11
|
-
--output <path> output file (default: stdout)
|
|
12
|
-
--rules <ids> comma-separated rule IDs (default: all)
|
|
13
|
-
--severity <min> minimum severity to report (critical | high | medium | low)
|
|
14
|
-
--format <fmt> markdown (default) | json
|
|
15
|
-
--verbose print per-rule progress
|
|
16
|
-
--api-key <key> override ANTHROPIC_API_KEY env var
|
|
17
|
-
--model <id> override default model (claude-sonnet-4-6)
|
|
18
473
|
```
|
|
474
|
+
| Field | Value |
|
|
475
|
+
|----------------|--------------------------------|
|
|
476
|
+
| Date | 2026-06-19 |
|
|
477
|
+
| Time | 14:30:15 UTC |
|
|
478
|
+
| Model | claude-sonnet-4-6 |
|
|
479
|
+
| Provider | anthropic |
|
|
480
|
+
| Effort | medium |
|
|
481
|
+
| CLI Version | v0.1.0 |
|
|
482
|
+
| Project | my-vault |
|
|
483
|
+
| Git Branch | main |
|
|
484
|
+
| Git Commit | a1b2c3d |
|
|
485
|
+
| OS | Darwin 25.0.0 (arm64) |
|
|
486
|
+
| Duration | 42.3s |
|
|
487
|
+
| Files Analyzed | 3 |
|
|
488
|
+
| Total Findings | 7 |
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Summary table
|
|
492
|
+
|
|
493
|
+
A quick count of findings by severity so you know at a glance how serious the results are:
|
|
494
|
+
|
|
495
|
+
```
|
|
496
|
+
| Severity | Count |
|
|
497
|
+
|----------|-------|
|
|
498
|
+
| Critical | 2 |
|
|
499
|
+
| High | 3 |
|
|
500
|
+
| Medium | 1 |
|
|
501
|
+
| Low | 1 |
|
|
502
|
+
| Total | 7 |
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Findings
|
|
506
|
+
|
|
507
|
+
Each finding looks like this:
|
|
508
|
+
|
|
509
|
+
```
|
|
510
|
+
### [CRITICAL] Rule 001: Missing signer check in set_admin
|
|
511
|
+
|
|
512
|
+
**File:** `src/lib.rs:42`
|
|
513
|
+
|
|
514
|
+
**Description:** The `authority` account is passed as `AccountInfo` but is
|
|
515
|
+
never verified as a signer. Any account can be passed here, letting an
|
|
516
|
+
attacker call set_admin with a fake authority.
|
|
517
|
+
|
|
518
|
+
**Vulnerable code:**
|
|
519
|
+
pub authority: AccountInfo<'info>,
|
|
520
|
+
|
|
521
|
+
**Recommendation:** Change `AccountInfo<'info>` to `Signer<'info>`. Anchor
|
|
522
|
+
will then automatically verify the account signed the transaction.
|
|
523
|
+
|
|
524
|
+
**Reference:** rules/001-missing-signer-check.md
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Auto-saved reports
|
|
528
|
+
|
|
529
|
+
Every run automatically saves a timestamped copy to a `reports/` folder so you never lose a result:
|
|
530
|
+
|
|
531
|
+
```
|
|
532
|
+
reports/
|
|
533
|
+
my-vault-2026-06-19T14-30-15Z.md
|
|
534
|
+
my-vault-2026-06-20T09-12-44Z.md
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
The `reports/` directory is gitignored by default. Use `--output` to save a named copy in a specific location as well.
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Performance Guide
|
|
542
|
+
|
|
543
|
+
### Cloud models
|
|
544
|
+
|
|
545
|
+
Cloud models are fast and accurate. The full 50-rule audit typically finishes in **1–3 minutes**. No special configuration needed beyond an API key.
|
|
546
|
+
|
|
547
|
+
### Local models
|
|
548
|
+
|
|
549
|
+
Local models run on your hardware. Speed depends on your machine's CPU, RAM, and whether you have a GPU:
|
|
550
|
+
|
|
551
|
+
| Hardware | 8B model speed | 50-rule audit time |
|
|
552
|
+
|----------|---------------|-------------------|
|
|
553
|
+
| MacBook (Apple Silicon) | 30–60 tok/s | ~5–10 min |
|
|
554
|
+
| Gaming GPU (RTX 4090) | 100–150 tok/s | ~2–4 min |
|
|
555
|
+
| CPU only | 5–15 tok/s | 20–40 min |
|
|
556
|
+
|
|
557
|
+
**Tips for faster local audits:**
|
|
558
|
+
|
|
559
|
+
```bash
|
|
560
|
+
# 1. Use --effort low to halve the output token budget
|
|
561
|
+
anchor-audit ./programs/my-vault --provider ollama --effort low
|
|
562
|
+
|
|
563
|
+
# 2. Use --severity high to cut from 10 batches to 5 batches
|
|
564
|
+
anchor-audit ./programs/my-vault --provider ollama --effort low --severity high
|
|
565
|
+
|
|
566
|
+
# 3. Use --severity critical for a 1-batch quick check (4 rules only)
|
|
567
|
+
anchor-audit ./programs/my-vault --provider ollama --severity critical
|
|
568
|
+
|
|
569
|
+
# 4. Use a smaller model - 3B or 4B models are 2–3x faster than 8B
|
|
570
|
+
ollama pull llama3.2:3b
|
|
571
|
+
anchor-audit ./programs/my-vault --provider ollama --model llama3.2:3b --effort low
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
**Recommended combinations:**
|
|
575
|
+
|
|
576
|
+
| Goal | Command |
|
|
577
|
+
|------|---------|
|
|
578
|
+
| Fastest possible check (local) | `--provider ollama --severity critical --effort low` |
|
|
579
|
+
| Balanced local scan | `--provider ollama --severity high --effort low` |
|
|
580
|
+
| Full local scan (patient) | `--provider ollama --effort low` |
|
|
581
|
+
| Best accuracy (cloud) | `--provider anthropic --model claude-opus-4-8 --effort high` |
|
|
582
|
+
| Free cloud option | `--provider groq --severity high` |
|
|
583
|
+
|
|
584
|
+
> **Note on accuracy:** The same rules are sent to every model. A stronger model (Claude Opus, GPT-4o) will find more real issues and produce fewer false positives than a smaller local model. Use local models for quick iterative checks during development, and a strong cloud model for pre-release audits.
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
## Rule Catalog
|
|
589
|
+
|
|
590
|
+
50 rules across 8 categories. Click any rule ID to read the full description, vulnerable pattern, fix pattern, and references.
|
|
591
|
+
|
|
592
|
+
| ID | Rule | Severity | Category |
|
|
593
|
+
|----|------|----------|----------|
|
|
594
|
+
| [001](rules/001-missing-signer-check.md) | Missing signer check | Critical | Account validation |
|
|
595
|
+
| [002](rules/002-missing-owner-check.md) | Missing owner check | Critical | Account validation |
|
|
596
|
+
| [003](rules/003-missing-discriminator-check.md) | Missing discriminator check (type cosplay) | High | Account validation |
|
|
597
|
+
| [004](rules/004-account-substitution.md) | Account substitution | High | Account validation |
|
|
598
|
+
| [005](rules/005-sysvar-spoofing.md) | Sysvar spoofing | High | Account validation |
|
|
599
|
+
| [006](rules/006-missing-rent-exemption-check.md) | Missing rent-exemption check | Low | Account validation |
|
|
600
|
+
| [007](rules/007-account-aliasing.md) | Account aliasing (duplicate mutable accounts) | High | Account validation |
|
|
601
|
+
| [008](rules/008-uninitialized-account-use.md) | Uninitialized account use | High | Account validation |
|
|
602
|
+
| [009](rules/009-missing-mut-constraint.md) | Missing `mut` constraint | Medium | Account validation |
|
|
603
|
+
| [010](rules/010-missing-close-constraint.md) | Missing or improper close constraint | Medium | Account validation |
|
|
604
|
+
| [011](rules/011-pda-seed-collision.md) | PDA seed collision | High | PDA |
|
|
605
|
+
| [012](rules/012-missing-bump-validation.md) | Missing bump validation | Medium | PDA |
|
|
606
|
+
| [013](rules/013-non-canonical-bump-accepted.md) | Non-canonical bump accepted | High | PDA |
|
|
607
|
+
| [014](rules/014-predictable-pda.md) | Predictable / attacker-controlled PDA seeds | High | PDA |
|
|
608
|
+
| [015](rules/015-insecure-pda-across-upgrades.md) | Insecure PDA layout across upgrades | Medium | PDA |
|
|
609
|
+
| [016](rules/016-bump-mismatch.md) | Stored bump mismatch | Medium | PDA |
|
|
610
|
+
| [017](rules/017-arbitrary-cpi.md) | Arbitrary CPI (unvalidated target) | Critical | CPI |
|
|
611
|
+
| [018](rules/018-cpi-confused-deputy.md) | CPI confused deputy | High | CPI |
|
|
612
|
+
| [019](rules/019-missing-program-id-check-spl.md) | Missing program ID check on SPL CPIs | High | CPI |
|
|
613
|
+
| [020](rules/020-reentrancy-via-cpi.md) | Reentrancy via CPI | High | CPI |
|
|
614
|
+
| [021](rules/021-untrusted-callback.md) | Untrusted callback execution | High | CPI |
|
|
615
|
+
| [022](rules/022-cpi-with-attacker-accounts.md) | CPI invoked with attacker-controlled accounts | High | CPI |
|
|
616
|
+
| [023](rules/023-lamport-overflow.md) | Lamport arithmetic overflow / underflow | High | Math |
|
|
617
|
+
| [024](rules/024-token-amount-overflow.md) | Token amount arithmetic overflow | High | Math |
|
|
618
|
+
| [025](rules/025-precision-loss.md) | Precision loss (division before multiplication) | Medium | Math |
|
|
619
|
+
| [026](rules/026-rounding-direction.md) | Incorrect rounding direction | Medium | Math |
|
|
620
|
+
| [027](rules/027-token-decimal-mismatch.md) | Token decimal mismatch | Medium | Math |
|
|
621
|
+
| [028](rules/028-integer-cast-truncation.md) | Integer cast truncation | Medium | Math |
|
|
622
|
+
| [029](rules/029-off-by-one.md) | Off-by-one errors | Low | Math |
|
|
623
|
+
| [030](rules/030-missing-authorization.md) | Missing authorization on privileged instruction | Critical | Auth |
|
|
624
|
+
| [031](rules/031-reinitialization-attack.md) | Reinitialization attack | High | Auth |
|
|
625
|
+
| [032](rules/032-closed-account-revival.md) | Closed account revival | High | Auth |
|
|
626
|
+
| [033](rules/033-init-if-needed-misuse.md) | `init_if_needed` misuse | High | Auth |
|
|
627
|
+
| [034](rules/034-missing-has-one.md) | Missing `has_one` relationship enforcement | High | Auth |
|
|
628
|
+
| [035](rules/035-insecure-admin-transfer.md) | Insecure admin transfer (no acceptance handshake) | Medium | Auth |
|
|
629
|
+
| [036](rules/036-missing-pause-guards.md) | Missing pause / freeze guards | Low | Auth |
|
|
630
|
+
| [037](rules/037-clock-manipulation.md) | Clock / time-based logic without bounds | Medium | Auth |
|
|
631
|
+
| [038](rules/038-missing-address-validation.md) | Missing `address` validation on fixed-identity accounts | Medium | Constraints |
|
|
632
|
+
| [039](rules/039-constraint-evaluation-stage.md) | Constraint evaluation stage (pre- vs post-state) | Medium | Constraints |
|
|
633
|
+
| [040](rules/040-realloc-zero-init.md) | `realloc` without zero-init | Medium | Constraints |
|
|
634
|
+
| [041](rules/041-missing-payer-on-init.md) | `init` without `payer` (or wrong payer) | Low | Constraints |
|
|
635
|
+
| [042](rules/042-incorrect-space-allocation.md) | Incorrect `space` allocation | Medium | Constraints |
|
|
636
|
+
| [043](rules/043-account-vs-account-info.md) | `Account` vs `AccountInfo` misuse | High | Constraints |
|
|
637
|
+
| [044](rules/044-token-account-owner-unverified.md) | Token account owner unverified | High | SPL Token |
|
|
638
|
+
| [045](rules/045-token-mint-unverified.md) | Token mint unverified | High | SPL Token |
|
|
639
|
+
| [046](rules/046-ata-assumption-errors.md) | Associated token account assumption errors | Medium | SPL Token |
|
|
640
|
+
| [047](rules/047-token-program-id-hardcoded.md) | Token program ID hardcoded vs. validated | Medium | SPL Token |
|
|
641
|
+
| [048](rules/048-compute-budget-abuse.md) | Compute budget abuse (unbounded work) | Medium | Runtime |
|
|
642
|
+
| [049](rules/049-log-spam-dos.md) | Log spam / excessive logging DoS | Low | Runtime |
|
|
643
|
+
| [050](rules/050-stack-overflow-deep-cpi.md) | Stack / CPI depth exhaustion | Low | Runtime |
|
|
644
|
+
|
|
645
|
+
**Severity breakdown:** 4 Critical · 21 High · 17 Medium · 8 Low
|
|
646
|
+
|
|
647
|
+
---
|
|
648
|
+
|
|
649
|
+
## Limitations
|
|
650
|
+
|
|
651
|
+
`anchor-audit` is a **static, pattern-based triage tool**. It is useful for catching known vulnerability classes quickly, but it has real limits you need to understand before relying on it.
|
|
652
|
+
|
|
653
|
+
**What it may miss:**
|
|
654
|
+
- Business-logic vulnerabilities specific to your protocol's design
|
|
655
|
+
- Economic attacks (price manipulation, oracle exploits, flash loan vectors)
|
|
656
|
+
- Bugs that only appear when multiple instructions are called in sequence
|
|
657
|
+
- Issues in client-side TypeScript/JavaScript code
|
|
658
|
+
|
|
659
|
+
**What it may get wrong:**
|
|
660
|
+
- False positives - patterns that look like a rule but are safe in context (e.g. an `AccountInfo` that is verified elsewhere)
|
|
661
|
+
- False negatives - real issues the model fails to recognize because the code pattern is unusual
|
|
662
|
+
|
|
663
|
+
**What it does not cover:**
|
|
664
|
+
- Dynamic analysis or fuzzing
|
|
665
|
+
- Runtime behavior
|
|
666
|
+
- Cross-program interaction analysis beyond CPI rule patterns
|
|
667
|
+
|
|
668
|
+
**Model accuracy varies:**
|
|
669
|
+
|
|
670
|
+
The same 50 rules are sent to every model. A larger, more capable model produces more accurate findings. Expect:
|
|
671
|
+
- Strong cloud models (Claude Opus, GPT-4o): high precision, few false positives
|
|
672
|
+
- Smaller local models (7B–8B): more false positives, may miss subtle issues
|
|
673
|
+
- Free cloud tiers: varies; Groq's Llama models perform well for their cost
|
|
674
|
+
|
|
675
|
+
**Never deploy to mainnet based solely on a clean `anchor-audit` report.** Always review findings manually, and get an independent professional audit before any program that holds real funds goes live.
|
|
676
|
+
|
|
677
|
+
---
|
|
678
|
+
|
|
679
|
+
## Contributing
|
|
680
|
+
|
|
681
|
+
### Adding or improving a rule
|
|
682
|
+
|
|
683
|
+
Each rule is a single markdown file in `/rules/` following a fixed template with seven required sections: description, vulnerable pattern, why it's dangerous, fix pattern, detection heuristic, references, and real-world exploits.
|
|
684
|
+
|
|
685
|
+
1. Copy the template from [rules/README.md](rules/README.md) into a new file: `rules/NNN-kebab-name.md`
|
|
686
|
+
2. Fill in all seven sections - no section may be left blank
|
|
687
|
+
3. Cite your sources in the References section (Neodyme, Sec3, Helius, Anchor book, Cyfrin Updraft, public audit reports)
|
|
688
|
+
4. Add a row to [rules/INDEX.md](rules/INDEX.md)
|
|
689
|
+
5. Run the test suite - it validates every rule file automatically
|
|
690
|
+
|
|
691
|
+
### Running tests locally
|
|
692
|
+
|
|
693
|
+
```bash
|
|
694
|
+
npm install
|
|
695
|
+
npm test # 272 unit tests - all rules, scanner, reporter
|
|
696
|
+
npm run typecheck # TypeScript strict check
|
|
697
|
+
npm run lint # ESLint
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Reporting issues
|
|
701
|
+
|
|
702
|
+
Open an issue at [github.com/guptaaayush432/anchor-audit/issues](https://github.com/guptaaayush432/anchor-audit/issues).
|
|
19
703
|
|
|
20
|
-
|
|
704
|
+
---
|
|
21
705
|
|
|
22
|
-
##
|
|
706
|
+
## License
|
|
23
707
|
|
|
24
|
-
-
|
|
25
|
-
- `src/scanner.ts` — file collection + filtering
|
|
26
|
-
- `src/rules-loader.ts` — loads `/rules/*.md` at runtime
|
|
27
|
-
- `src/auditor.ts` — Claude API orchestration (rules batched 4–6 per call)
|
|
28
|
-
- `src/reporter.ts` — markdown/JSON report generation
|
|
708
|
+
[MIT](./LICENSE) - Aayush Gupta, 2026
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ program
|
|
|
42
42
|
.option("--base-url <url>", "base URL for OpenAI-compatible endpoint (required for --provider custom; " +
|
|
43
43
|
"optional override for ollama/lmstudio/vllm defaults)")
|
|
44
44
|
.option("--effort <level>", "analysis depth — low (2 k tokens) | medium (4 k) | high (8 k)", "medium")
|
|
45
|
-
.version("0.1.
|
|
45
|
+
.version("0.1.1")
|
|
46
46
|
.action(async (targetPath, opts) => {
|
|
47
47
|
const startTime = new Date();
|
|
48
48
|
const provider = (opts.provider ?? "anthropic");
|
package/dist/reporter.js
CHANGED
|
@@ -20,7 +20,7 @@ import { writeFileSync, mkdirSync } from "node:fs";
|
|
|
20
20
|
import { join } from "node:path";
|
|
21
21
|
import chalk from "chalk";
|
|
22
22
|
import { SEVERITY_ORDER } from "./auditor.js";
|
|
23
|
-
const VERSION = "0.1.
|
|
23
|
+
const VERSION = "0.1.1";
|
|
24
24
|
export function countBySeverity(findings) {
|
|
25
25
|
const c = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
26
26
|
for (const f of findings)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anchor-audit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "AI-driven security audit CLI for Anchor programs on Solana",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
],
|
|
17
17
|
"scripts": {
|
|
18
18
|
"build": "tsc -p tsconfig.json",
|
|
19
|
-
"prepublishOnly": "rm -rf ./rules && cp -r ../rules ./rules && npm run build",
|
|
20
|
-
"postpublish": "rm -rf ./rules"
|
|
19
|
+
"prepublishOnly": "rm -rf ./rules && cp -r ../rules ./rules && cp ../README.md ./README.md && npm run build",
|
|
20
|
+
"postpublish": "rm -rf ./rules && git checkout README.md"
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"solana",
|