{"_id":"solaudit","_rev":"7-0394eb87d83e0846e04e90f74ca8b0cc","name":"solaudit","dist-tags":{"latest":"0.3.3"},"versions":{"0.1.0":{"name":"solaudit","version":"0.1.0","keywords":["solana","anchor","security","static-analysis","audit"],"author":{"name":"Cody Pack"},"license":"MIT","_id":"solaudit@0.1.0","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"homepage":"https://github.com/blueeyez425-art/solaudit#readme","bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"bin":{"solaudit":"dist/cli.js"},"dist":{"shasum":"ebaa9efe724174d9cb9572fb9267df0fee6017da","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.1.0.tgz","fileCount":5,"integrity":"sha512-vsxfoJGTGLzdECrr5FVOdyoYEhFslEvRDtgN2j54wJv3RnjLpPJRP72pWqbgEpWyfOFXRilI6dg0zUUQMjABZw==","signatures":[{"sig":"MEQCIDn0FMbg/MGHSzZePVgrrwXRUNd8RVyCRv6zXPfwuzQyAiAHxadtSXZDgTM6U1i6AtsEybRIJuE168kdN9SxUnfMIg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35039},"main":"./dist/index.js","type":"module","engines":{"node":">=18"},"gitHead":"380f548b4268df627c629e0efebceefaf9387cbf","scripts":{"test":"bun test","build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"npm run build"},"_npmUser":{"name":"umakariharu","email":"blueeyez425@gmail.com"},"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"11.16.0","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest"},"_npmOperationalInternal":{"tmp":"tmp/solaudit_0.1.0_1787705661271_0.5224028080664025","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"solaudit","version":"0.1.2","keywords":["solana","anchor","security","static-analysis","audit"],"author":{"name":"Cody Pack"},"license":"MIT","_id":"solaudit@0.1.2","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"homepage":"https://github.com/blueeyez425-art/solaudit#readme","bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"bin":{"solaudit":"dist/cli.js"},"dist":{"shasum":"859fb2ab2ad89a276e9d39162120da0d174b502f","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.1.2.tgz","fileCount":5,"integrity":"sha512-Pu3aX0hPIyXL14B4RcVyPCtgsjNUlxsk1T4ktXB6SoLB3Md2D4MyFgEjBD+tf+od0jXwyJrumgAycazzHZD0HQ==","signatures":[{"sig":"MEUCIQDztV1IEAU+dNm1TlRU8zwJGjQNG2EYL0LpWZYNmCj+vgIgUytqdBEdSm/R84f4bbxdjHSQMwiV+cQl1OdgwZEETYc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35097},"main":"./dist/index.js","type":"module","engines":{"node":">=18"},"gitHead":"f7d5f8a99c17d3e0cf11a2e26d87442c9e17586f","scripts":{"test":"bun test","build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"npm run build"},"_npmUser":{"name":"umakariharu","email":"blueeyez425@gmail.com"},"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"11.16.0","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"_nodeVersion":"24.19.0","_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest"},"_npmOperationalInternal":{"tmp":"tmp/solaudit_0.1.2_1787706013088_0.44356859159098305","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"solaudit","version":"0.2.0","keywords":["solana","anchor","security","static-analysis","audit"],"author":{"name":"Cody Pack"},"license":"MIT","_id":"solaudit@0.2.0","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"homepage":"https://github.com/blueeyez425-art/solaudit#readme","bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"bin":{"solaudit":"dist/cli.js"},"dist":{"shasum":"96b2272530566074d1d784b188a1064e4952fc5c","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.2.0.tgz","fileCount":5,"integrity":"sha512-6hai1sa/x5RjhgDb2mRmsmz4tHipFEZClh5qfyVed1RuQf3Ec/PzJBA16Gvifr2kbFsEIgyLXEPn3yXJoZObeA==","signatures":[{"sig":"MEUCIQCCKhbK1dYngww068OPH7JsDyby6hIaoakDK+G/YPOWBQIgIBMDWhFC9jdvGi4ZRIh5Cg9Eow5DbPBDaeRBUq4qr4w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIAYjY7fkshogDiNc2RAFdmtxYXCE+ymDsHzyI2Lfj4KxAiBbRxMeDeZZ+fMu52id8oYWCf8GpXmECij1CuW1kaRJmw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/solaudit@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":40726},"main":"./dist/cli.js","type":"module","engines":{"node":">=18"},"gitHead":"2049dc382768290a95911dd78c7f5b4c642749f9","scripts":{"build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"bun run build && cp -r ../examples . && cp ../README.md ../LICENSE ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"c842ed98-8236-48d9-9516-c706e9a0af84"}},"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"12.2.0","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"_nodeVersion":"24.21.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest","@solaudit/core":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/solaudit_0.2.0_1791765415453_0.06435865224683912","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"solaudit","version":"0.3.0","keywords":["solana","anchor","security","static-analysis","audit"],"author":{"name":"Cody Pack"},"license":"MIT","_id":"solaudit@0.3.0","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"homepage":"https://github.com/blueeyez425-art/solaudit#readme","bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"bin":{"solaudit":"dist/cli.js"},"dist":{"shasum":"fcc63ec266480fb41c91508a1f49c3ebd485286a","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.3.0.tgz","fileCount":5,"integrity":"sha512-TJguadwZGG5JqVfnJi1RJ9XUflwPCYVpSWfaRIzZdx9GMfIZ42NTK3iNt8toZcqVduZeahaVKjfBwR8ZxxOM1A==","signatures":[{"sig":"MEUCIQC/MTgLOW1Xs2C0PyjZY+Si+PyFt8hmA2KAfa3NbycRRAIgHajNLmkTPLCaVgQeYadM5rFH5BvYf/oD1jdv0R+wCmg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIEaRDCPpCNzPhiklQhSxbTpkKCXnjs/K43O2MYh2azbLAiEAoKSuQ0rm1mO35FhUMwRme2Im1+gT6AMiwQcDuKgSwRw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/solaudit@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":46268},"main":"./dist/cli.js","type":"module","engines":{"node":">=18"},"gitHead":"db0ba2072e4a698f1af41a796c750b63577c831e","scripts":{"build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"bun run build && cp -r ../examples . && cp ../README.md ../LICENSE ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"c842ed98-8236-48d9-9516-c706e9a0af84"}},"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"12.2.0","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"_nodeVersion":"24.21.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest","@solaudit/core":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/solaudit_0.3.0_1792266566950_0.2880144637892197","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"solaudit","version":"0.3.1","keywords":["solana","anchor","security","static-analysis","audit"],"author":{"name":"Cody Pack"},"license":"MIT","_id":"solaudit@0.3.1","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"homepage":"https://github.com/blueeyez425-art/solaudit#readme","bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"bin":{"solaudit":"dist/cli.js"},"dist":{"shasum":"652e741a8f8cc21e8bf4e97c43e310f7fc95e6e5","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.3.1.tgz","fileCount":5,"integrity":"sha512-1Ic0BkElWpScT4+HD7jGuYkhxEifkaSAtjhgSjoQhqzMDM7GvP7DAYzTzKr3uXmI2mZnzUwyWeyXEZFlKrRdWg==","signatures":[{"sig":"MEQCIG4mZqohwa+9QlR/ij8TXy5KZRz13Tx0uoZtUghCRNbRAiBNy0BDwLIF3H5AMMcUkG5ARnzo14/E6WQyeAWSuTmE0Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDPQ0g7Z20p1iSQbC7Y4DjN1UK9XF/rbJslKfcO/wa6FAIgWPfbx7um0riCSrxwLRRZp/brBxNr3UdxENSZGpMF308=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/solaudit@0.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":61829},"main":"./dist/cli.js","type":"module","engines":{"node":">=18"},"gitHead":"613de740aebcefd5a05fa9d2d44ef5976c0b3f97","scripts":{"build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"bun run build && cp -r ../examples . && cp ../README.md ../LICENSE ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"c842ed98-8236-48d9-9516-c706e9a0af84"}},"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"12.2.0","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"_nodeVersion":"24.22.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest","@solaudit/core":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/solaudit_0.3.1_1792541900569_0.30579569309374355","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"solaudit","version":"0.3.2","keywords":["solana","anchor","security","static-analysis","audit"],"author":{"name":"Cody Pack"},"license":"MIT","_id":"solaudit@0.3.2","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"homepage":"https://github.com/blueeyez425-art/solaudit#readme","bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"bin":{"solaudit":"dist/cli.js"},"dist":{"shasum":"2fb323f8e09c605e44703443c3ffcb9909ecbcbd","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.3.2.tgz","fileCount":11,"integrity":"sha512-0mSm+W6ccfVSWLNpmXbFvgBagzqjbqTvtlAJiSzQvlnt5jT+Fae1k0p0HwrpxQ3n71DPT/Gr+SZi43XF3SORVw==","signatures":[{"sig":"MEQCIETmSl96Kg31XoZjI5OI1QTm4axPdGBLonoR9G5LKAmfAiAAovuZpa7Xhqwnttli4/ncuZ1KO/EgpOFwI5oPuszq0A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIHOVvuCevh44V36i0L/LAgFA5V/7D3Bc7llICiQk6QJpAiEAu7BPtRVKXnS2YO+Bdig2YgjiGzWfTUbIcAKfC6NvjoM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/solaudit@0.3.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":108000},"main":"./dist/cli.js","type":"module","engines":{"node":">=18"},"gitHead":"0234b4cbf1c17ca42c5bac8f65e8f1d32350afab","scripts":{"build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"bun run build && cp -r ../examples . && cp ../README.md ../LICENSE ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"c842ed98-8236-48d9-9516-c706e9a0af84"}},"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"12.2.1","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"_nodeVersion":"24.21.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest","@solaudit/core":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/solaudit_0.3.2_1792894676520_0.35917838663355406","host":"s3://npm-registry-packages-npm-production"}},"0.3.3":{"_id":"solaudit@0.3.3","bin":{"solaudit":"dist/cli.js"},"bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"dist":{"shasum":"0edea603aef4f63463530bcaff8709e92d3310bf","tarball":"https://registry.npmjs.org/solaudit/-/solaudit-0.3.3.tgz","fileCount":12,"integrity":"sha512-+QEu5gbI1BJq+2LQ+HgfZfarmiBBL7h089mKevRwrdTxup5YYYwZt6iHpUQOD29+mJgqu3yft0YzywA+q0TlQg==","signatures":[{"sig":"MEUCIASlA7t14DqzEUVCtHJNtQmrq/i3/FWv91UgHyCw6DFSAiEA6BgvN/g3dXAX84/K46NwRPN2GMdJwyi9JeiEw/92B4E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICdXaSF392rZ6lCSSsP6kG0qBiSVe48FuODXmmFgHvwFAiBLqaUFAUAO0q2Xre18D7NuDdDOWdjhvYqwG50SrxPYuA=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/solaudit@0.3.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":126558},"main":"./dist/cli.js","name":"solaudit","type":"module","author":{"name":"Cody Pack"},"engines":{"node":">=18"},"gitHead":"941d14480731b7f881d8943269eca44cd8ea72e8","license":"MIT","scripts":{"build":"bun build src/cli.ts --outdir dist --target node --sourcemap=none","start":"bun src/cli.ts","prepublishOnly":"bun run build && cp -r ../examples . && cp ../README.md ../LICENSE ."},"version":"0.3.3","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"c842ed98-8236-48d9-9516-c706e9a0af84"}},"homepage":"https://github.com/blueeyez425-art/solaudit#readme","keywords":["solana","anchor","security","static-analysis","audit"],"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"_npmVersion":"12.2.1","description":"Open-source static analysis CLI for Anchor/Solana programs","directories":{},"maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"_nodeVersion":"24.21.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"bun-types":"latest","@solaudit/core":"workspace:*"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/solaudit_0.3.3_1793146105489_0.8297938069104651"}}},"time":{"created":"2026-08-26T00:54:21.118Z","modified":"2026-10-28T00:08:25.974Z","0.1.0":"2026-08-26T00:54:21.448Z","0.1.2":"2026-08-26T01:00:13.216Z","0.2.0":"2026-10-12T00:36:55.555Z","0.3.0":"2026-10-17T19:49:27.024Z","0.3.1":"2026-10-21T00:18:20.674Z","0.3.2":"2026-10-25T02:17:56.601Z","0.3.3":"2026-10-28T00:08:25.605Z"},"bugs":{"url":"https://github.com/blueeyez425-art/solaudit/issues"},"author":{"name":"Cody Pack"},"license":"MIT","homepage":"https://github.com/blueeyez425-art/solaudit#readme","keywords":["solana","anchor","security","static-analysis","audit"],"repository":{"url":"git+https://github.com/blueeyez425-art/solaudit.git","type":"git"},"description":"Open-source static analysis CLI for Anchor/Solana programs","maintainers":[{"name":"umakariharu","email":"blueeyez425@gmail.com"}],"readme":"# SolAudit\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)\n[![npm version](https://img.shields.io/badge/npm-v0.3.0-blue.svg)](https://www.npmjs.com/package/solaudit)\n[![build](https://img.shields.io/badge/build-passing-brightgreen.svg)](./.github/workflows/ci.yml)\n\n**A zero-dependency static-analysis engine that scans Anchor/Solana Rust programs for the vulnerability patterns behind the most common on-chain exploits — available as a CLI and as a free web app.**\n\nSolAudit reads `.rs` source files, applies a set of pattern-matching security rules (missing signer checks, arbitrary CPIs, unchecked deserialization, integer overflow, and more), and gives you an actionable report in seconds — no RPC calls, no wallet, no build step required to run it.\n\n- **CLI** — `npx solaudit ./program`, for local development and CI.\n- **Web app** — [solaudit-web.vercel.app](https://solaudit-web.vercel.app/) — paste a public GitHub repo URL or upload a single `.rs` file, no install required.\n\n---\n\n## Repository layout\n\nThis is a Bun workspaces monorepo. The CLI and the web app share one scanning engine, so there is a single source of truth for every rule — no drift between the two.\n\n```\npackages/core/    Shared engine: rules, scanner, output formatters (published nowhere; workspace-only)\ncli/              npm package \"solaudit\" — the command-line tool\nweb/              Next.js app deployed to Vercel — the web version\nexamples/         Intentionally vulnerable sample Anchor program, used by both the CLI and web tests\n```\n\n## CLI\n\n```bash\n# Run instantly with npx (no install)\nnpx solaudit ./program\n\n# Or install globally with Bun\nbun add -g solaudit\nsolaudit ./program\n```\n\n```bash\nsolaudit [path] [options]\n```\n\n| Flag | Description |\n|---|---|\n| `--json` | Print raw scan results as JSON |\n| `--sarif` | Print results as SARIF 2.1.0 (for GitHub Code Scanning) |\n| `--min-severity <level>` | Only report findings at or above `CRITICAL`\\|`HIGH`\\|`MEDIUM`\\|`LOW`\\|`INFO` |\n| `--experimental` | Also run opt-in experimental rules (`SOL-012` Duplicate Mutable Accounts, `SOL-013` Token Account Not Bound to Mint); higher signal, more false positives |\n| `--include-tests` | Also scan test/fuzz/fixture/example code (skipped by default; findings there are rarely actionable) |\n| `--help` | Show usage |\n\n### Example\n\n```bash\n$ solaudit ./examples\n```\n\n```\nSolAudit v0.3.2 — static analysis for Anchor/Solana programs\nScanned 1 file(s) at 2026-08-27T06:00:00.000Z\n──────────────────────────────────────────────────────────────────────\n\nCRITICAL (2)\n   CRITICAL  SOL-001 Missing Signer Check\n    examples/vulnerable.rs:35\n    │ token::transfer(cpi_ctx, amount)?;\n    └─ Verify the authority/owner account is a Signer or explicitly\n       check `.is_signer` before transferring or minting tokens.\n\n──────────────────────────────────────────────────────────────────────\nSummary\n  CRITICAL 2   HIGH 3   MEDIUM 3   LOW 6   INFO 0\n  Total findings: 14 across 1 file(s)\n```\n\nExit code is `1` when any `CRITICAL` or `HIGH` finding is present — making SolAudit a natural CI gate.\n\n## Web app\n\n**Live at [solaudit-web.vercel.app](https://solaudit-web.vercel.app/)** — no CLI, no local Anchor toolchain, no wallet required:\n\n1. Paste a public GitHub repo URL **or** upload a single `.rs` file.\n2. The server fetches `.rs` files via GitHub's API (no `git clone`) and scans them with the exact same engine as the CLI.\n3. Get a report grouped by severity, right in the browser.\n\nOptional: set `GITHUB_TOKEN` (see `web/.env.example`) to raise the GitHub API rate limit from 60 to 5,000 requests/hour. No special token scopes are needed for public repos.\n\n### Running the web app locally\n\n```bash\nbun install          # from the repo root — links the workspace packages\ncd web\nbun run dev\n```\n\n## Rules\n\n| ID | Severity | Name | What it catches |\n|---|---|---|---|\n| `SOL-001` | CRITICAL | Missing Signer Check | `transfer`/`mint_to` calls with no signer evidence anywhere: no nearby `is_signer` check, no `Signer<'info>` field on the governing Accounts struct, and no PDA signing (`invoke_signed` / `new_with_signer`). Also flags PDA-signed transfers whose *destination* is a caller-supplied unchecked account with no `Signer` governing the instruction (the classic vault drain) |\n| `SOL-002` | HIGH | Unchecked Account Deserialization | `Account::try_from` / `AccountLoader::try_from` on an account with no validating `#[account(...)]` constraint (constraint-aware: fields carrying `owner`/`constraint`/`has_one` bindings are recognized as validated) |\n| `SOL-003` | HIGH | Arbitrary CPI | `invoke`/`invoke_signed` whose program ID comes from a raw (unchecked) program account (`program_id: ctx.accounts.*` or a raw `*_program` field); typed `Program<'info, T>` targets are recognized as safe |\n| `SOL-004` | HIGH | Missing Bump Seed Canonicalization / Unverified PDA | `create_program_address` called directly with a bump that didn't come from a nearby `find_program_address` (which is canonical by construction); also raw, mutable vault/treasury/pool-style accounts used in value movement with no `seeds`/`address` binding |\n| `SOL-005` | MEDIUM | Integer Overflow Risk | Raw `+`/`-`/`*` arithmetic *written into account state* (field/compound assignment) on balance-like values instead of `checked_*`/`saturating_*`; also variable-exponent `pow()` in value math (e.g. `2u64.pow(level)` in a fee curve) |\n| `SOL-006` | HIGH | Type Cosplay / Missing Discriminator Check | Manual `try_from_slice` deserialization with no discriminator validation or `Account<'info, T>` wrapper |\n| `SOL-007` | MEDIUM | Insecure Account Initialization | `#[account(init, ...)]` constraints missing `payer` and/or `space` |\n| `SOL-008` | LOW | Missing Owner Check | Raw `AccountInfo`/`UncheckedAccount` fields with no constraint binding whose data is trusted (deserialized/read, including through `let x = &ctx.accounts.f` aliases) or whose key is assigned into persistent state, with no genuine `.owner ==` comparison; usages are scoped to the owning struct's handlers |\n| `SOL-009` | HIGH | Insecure Manual Account Closure | An account's lamports manually drained to zero (`lamports.borrow_mut() = 0` or `try_borrow_mut_lamports() = 0`) without discriminator zeroing or owner reassignment (unlike Anchor's `close = destination`), enabling closed-account revival |\n| `SOL-010` | MEDIUM | Reinitialization Risk via init_if_needed | `#[account(init_if_needed, ...)]` without canonical PDA seeds / `has_one` constraints, letting a pre-existing attacker-crafted account pass as freshly initialized |\n| `SOL-011` | MEDIUM | Missing Rent-Exemption Check | A partial lamport withdrawal with no nearby `Rent::get()?.minimum_balance(...)` check, risking runtime garbage-collection of the account |\n\nEach rule is implemented as real regex/line-scanning logic in [`packages/core/src/rules/index.ts`](./packages/core/src/rules/index.ts) — see that file (and its accompanying [tests](./packages/core/src/rules/index.test.ts)) for the exact matching heuristics and false-positive guards.\n\n## Accuracy\n\nOn the committed labeled suite in [`benchmark/`](./benchmark), the deterministic engine scores **100% precision, 100% recall, 100% F1** on rule-covered categories.\n\n### Real-world validation (0.3.1)\n\n0.3.0 was scanned against 9 major open-source protocols (marginfi, Drift, Orca Whirlpools, Marinade, Squads, Phoenix, Clockwork, Saber, and Cashio — the real $50M exploit, as a control). The result drove a rewrite of how the engine reads Anchor code: it now parses `#[derive(Accounts)]` structs and understands the constraint layer (`Signer`, `owner`/`has_one`/`constraint`/`seeds`, handler `Context<T>` mapping, `#[cfg(test)]` exclusion), instead of pattern-matching handler bodies alone.\n\n- **Default findings across the 9 repos dropped from 1,232 to 158 (−87%)** — marginfi went from 521 findings to 20; Drift from 454 to 77.\n- The remaining findings are *more* actionable, not fewer ideas: suppressions only happen on positive evidence of validation.\n- Under `--experimental`, the new `SOL-013` rule fires on Cashio's actual vulnerable pattern — a token account whose mint is never bound despite a mint account being in scope (the class behind the infinite-mint exploit).\n\nBenchmark label integrity note: three samples' labels were revised in 0.3.1 to match SOL-008's sharpened definition (raw accounts whose *data* is trusted or whose key is *assigned into state*); each revision is documented inline in [`benchmark/labels.json`](./benchmark/labels.json).\n\n### Ground-truth validation (0.3.2): SolScape\n\n0.3.1 was measured against **purpose-built ground truth**: [SolScape](https://github.com/blueeyez425-art/solaudit/tree/main/examples/solscape), a complete (intentionally vulnerable) Anchor game program — a persistent on-chain territory map with a marketplace, treasury, and player profiles — seeded with 9 real exploit classes (missing-signer treasury drain, unchecked PDA substitution, overflow price curve, arbitrary CPI, unbound token mint, close-then-revive, raw-byte trust, reinitialization) plus 4 correctly-secured control handlers. The answer key was written **before** the scan.\n\n- **0.3.1 caught 2 of 9 seeded bugs** and false-flagged 2 of 4 controls. We published that scorecard, then fixed the engine.\n- **0.3.2 catches 8 of 9 by default, 9 of 9 with `--experimental`** (the unbound-mint class is SOL-013), with **all 4 controls clean**.\n\n**0.3.3 fix:** SOL-005 had a redundant in-rule test-path guard that silently skipped it whenever a target lived under an `examples/`-style path — meaning the documented SolScape reproduction command under-reported by one class. The guard is removed (filtering happens once, at the scanner layer, honoring `--include-tests`); the reproduction command now genuinely yields 9/9. Found while compiling SolScape; caught by the same fixture.\n- Fixes: SOL-001 now detects PDA-signed transfers to caller-chosen unchecked recipients when no `Signer` governs the instruction (the classic vault drain); SOL-003 only flags CPIs whose *program* is a raw account (typed `Program<'info, T>` no longer flags); SOL-004 also flags unseeds-verified vault/treasury/pool accounts used in value movement; SOL-005 catches variable-exponent `pow()` in value math; SOL-008 follows `let x = &ctx.accounts.f` aliases, scopes usages to the owning struct's handlers, and no longer mistakes `field.owner = ...` assignments for checks; SOL-009 recognizes `try_borrow_mut_lamports() = 0` manual closes.\n- marginfi re-scan sanity check: 24 findings (was 20) — the main program stays clean; the new signal lands in mock/integration programs.\n\nFixture revisions disclosed: SolScape's `withdraw_treasury` was rewritten to the genuinely exploitable `invoke_signed` shape (v1's plain `invoke` could not actually drain), `close_tile` now leaves data intact (v1 zeroed it, which is the *safe* pattern), and `buy_tile_spl` gained the realistic typed-token + mint shape SOL-013 is designed to scope to. v1 is archived in the fixture directory.\n\n**Duplicate mutable accounts** and **token accounts unbound to their mint** (the Cashio class) are covered by the experimental `SOL-012` and `SOL-013` rules, available via `solaudit --experimental`. A “distinctness” heuristic false-positives on common legitimate patterns (for example a deposit instruction’s user/vault token accounts of the same type with no explicit `!=` constraint), so it stays opt-in to protect the default ruleset's precision. These numbers describe this suite, not general security effectiveness.\n\n## Output formats (CLI)\n\n- **Human** (default) — colorized terminal report grouped by severity.\n- **JSON** (`--json`) — the full `ScanResult` object (`scannedFiles`, `findings[]`, `summary`).\n- **SARIF** (`--sarif`) — [SARIF 2.1.0](https://sarifweb.azurewebsites.net/) output compatible with GitHub Code Scanning.\n- **Experimental rules** (`--experimental`) — opt into noisier, higher-signal heuristics (`SOL-012` Duplicate Mutable Accounts, `SOL-013` Token Account Not Bound to Mint). Recommended for deep manual reviews rather than CI gates.\n\n## GitHub Actions\n\nSolAudit ships as a ready-to-use [GitHub Action](./action.yml). Drop this into `.github/workflows/solaudit.yml` in your own repo and every push/PR gets scanned automatically, with results uploaded straight to your repo's Security tab:\n\n```yaml\nname: SolAudit\n\non: [push, pull_request]\n\npermissions:\n  contents: read\n  security-events: write   # required to upload SARIF results\n\njobs:\n  scan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - uses: blueeyez425-art/solaudit@main\n        with:\n          path: ./programs        # file or directory to scan (default: .)\n          min-severity: INFO      # lowest severity to report (default: INFO)\n          fail-on-findings: true  # fail the build on any CRITICAL/HIGH finding (default: true)\n          upload-sarif: true      # upload results to code scanning (default: true)\n```\n\nNo `security-events: write` permission in your workflow? Set `upload-sarif: false` and the action will still run the scan and fail the build on CRITICAL/HIGH findings — it just won't publish to the Security tab.\n\nPrefer to wire it up manually instead of using the packaged action:\n\n```yaml\n- uses: actions/checkout@v4\n- run: npx solaudit ./programs --sarif > results.sarif\n- uses: github/codeql-action/upload-sarif@v3\n  with:\n    sarif_file: results.sarif\n```\n\nThis repository's own [`.github/workflows/ci.yml`](./.github/workflows/ci.yml) runs the full test suite, builds the CLI and web app, and uses this repo's own action against `examples/` on every push.\n\n## Development\n\n```bash\nbun install                    # installs and links all workspaces\ncd packages/core && bun test   # run the engine's unit test suite\ncd cli && bun run build        # bundle cli/src/cli.ts -> cli/dist/cli.js\ncd web && bun run build        # production-build the web app\n```\n\n## Contributing\n\nContributions are very welcome — new rules, false-positive fixes, additional output formats, or web UI improvements are all in scope.\n\n1. Fork the repo and create a branch from `main`.\n2. Add or update a rule in `packages/core/src/rules/index.ts` (each rule is a self-contained `Rule` object).\n3. Add unit tests covering both a triggering and a non-triggering case (`packages/core/src/rules/index.test.ts`).\n4. Run `bun test` (from `packages/core`) before opening a PR.\n\nPlease open an issue first for larger changes so we can discuss the approach.\n\n## Support\n\nSolAudit is free and open source, and development continues with or without tips. If it catches a bug or saves you real time and you'd like to say thanks, tips are appreciated — never expected: [flipcash.com/d142ad60-e966-4967-bfa3-6d2332e59342](https://flipcash.com/d142ad60-e966-4967-bfa3-6d2332e59342)\n\n## License\n\n[MIT](./LICENSE) © 2026 Cody Pack\n","readmeFilename":"README.md"}