brainblast 0.2.0 → 0.3.0

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.
@@ -0,0 +1,55 @@
1
+ # Pure-data rule (facts). Binds to vetted templates by `check.kind`/`test.kind`.
2
+ # Promoted from findings/metaplex-metadata-immutable.json after the
3
+ # proof-as-classifier loop (synth-prove) closed RED->GREEN against the
4
+ # new `object-arg-property-literal-equals` checker kind.
5
+ id: metaplex-metadata-immutable
6
+ severity: critical
7
+ title: Metaplex createV1 called with isMutable false to seal token metadata at mint
8
+ component:
9
+ name: Metaplex Token Metadata
10
+ type: Blockchain
11
+ version: unversioned
12
+ sourceUrl: https://developers.metaplex.com/token-metadata
13
+ detect:
14
+ modules: ["@metaplex-foundation/mpl-token-metadata"]
15
+ # Brand-specific terms only. Bare "token"/"mint" cross-match SPL-token,
16
+ # Bags, and other handlers. Metaplex candidates still resolve via the
17
+ # @metaplex-foundation/mpl-token-metadata import or the createV1/createNft
18
+ # trigger calls.
19
+ nameRegex: "metaplex|mpl|createNft"
20
+ triggerCalls: [createV1, createNft, createAndMint, createMetadataAccountV3]
21
+ check:
22
+ kind: object-arg-property-literal-equals
23
+ params:
24
+ call: createV1
25
+ argIndex: 1
26
+ propName: isMutable
27
+ expectedValue: false
28
+ passDetail: >-
29
+ createV1 passes isMutable: false — token metadata is permanently sealed
30
+ at mint time. Name, symbol, and URI cannot be changed regardless of who
31
+ holds the update authority.
32
+ failAbsentDetail: >-
33
+ createV1 omits isMutable (SDK defaults to true). The update authority
34
+ retains the ability to change the token name, symbol, and URI after mint —
35
+ permanently. Seal the metadata by passing isMutable: false. There is no
36
+ on-chain migration path once metadata is minted as mutable.
37
+ failWrongDetail: >-
38
+ createV1 passes isMutable: true explicitly. Token metadata will remain
39
+ mutable after mint — the update authority key becomes a permanent attack
40
+ surface. Pass isMutable: false to seal it at mint time.
41
+ failArgDetail: >-
42
+ createV1's options argument is not an inline object literal; cannot
43
+ statically verify isMutable. Inline the options object so static analysis
44
+ can confirm isMutable: false.
45
+ failDynamicDetail: >-
46
+ isMutable is set via a variable or expression; cannot confirm it resolves
47
+ to false statically. Use the boolean literal false directly.
48
+ absentCallDetail: >-
49
+ Handler is in Metaplex scope but does not call createV1; the
50
+ metadata-immutability rule does not apply here.
51
+ scopeNotMetDetail: >-
52
+ File does not import from @metaplex-foundation/mpl-token-metadata; the
53
+ metadata-immutability rule does not apply.
54
+ test:
55
+ kind: metaplex-immutable-metadata
@@ -9,7 +9,11 @@ component:
9
9
  sourceUrl: https://docs.privy.io/authentication/user-authentication/access-tokens
10
10
  detect:
11
11
  modules: [jose, jsonwebtoken, "@privy-io/node", "@privy-io/server-auth"]
12
- nameRegex: "token|auth|verify|privy|jwt"
12
+ # Brand-specific terms only. Bare "token"/"auth" cross-match unrelated
13
+ # Solana handlers (launchToken, etc.) and produce spurious cant_tell noise.
14
+ # Privy handlers are still picked up by the @privy-io/* / jose / jsonwebtoken
15
+ # imports, and by triggerCalls like decodeJwt / jwtVerify.
16
+ nameRegex: "privy|jwt"
13
17
  triggerCalls: [decodeJwt, jwtVerify, verify, decode]
14
18
  check:
15
19
  kind: required-call-with-options
@@ -0,0 +1,55 @@
1
+ # Pure-data rule (facts). Binds to vetted templates by `check.kind`/`test.kind`.
2
+ # Promoted from findings/token-2022-program-id-mismatch.json after the
3
+ # proof-as-classifier loop (synth-prove) closed RED->GREEN against the
4
+ # new `arg-equals-constant-identifier` checker kind.
5
+ id: token-2022-program-id-pinned
6
+ severity: critical
7
+ title: Token-2022 createMint passes TOKEN_2022_PROGRAM_ID as the program ID argument
8
+ component:
9
+ name: SPL Token-2022
10
+ type: Blockchain
11
+ version: unversioned
12
+ sourceUrl: https://spl.solana.com/token-2022
13
+ detect:
14
+ modules: ["@solana/spl-token"]
15
+ # Keep the regex narrow to terms specific to SPL-token-mint construction;
16
+ # bare "token"/"launch" would cross-match unrelated handlers (Privy
17
+ # verifyPrivyToken, etc.). Real Token-2022 handlers still resolve via the
18
+ # @solana/spl-token import or the createMint trigger call.
19
+ nameRegex: "createMint|mint22|token2022"
20
+ triggerCalls: [createMint]
21
+ check:
22
+ kind: arg-equals-constant-identifier
23
+ params:
24
+ call: createMint
25
+ argIndex: 7
26
+ expectedIdentifier: TOKEN_2022_PROGRAM_ID
27
+ forbiddenIdentifiers: [TOKEN_PROGRAM_ID]
28
+ # Scope predicate: only enforce when the file imports TOKEN_2022_PROGRAM_ID.
29
+ # Without this, every legacy-mint codebase would false-positive.
30
+ requireImport: TOKEN_2022_PROGRAM_ID
31
+ passDetail: >-
32
+ createMint passes {expected} as its programId argument — Token-2022
33
+ features will work as designed.
34
+ failForbiddenDetail: >-
35
+ createMint passes {got} (legacy Token program) where Token-2022 was
36
+ intended. The mint will be owned by the legacy program; Token-2022
37
+ features (transfer hooks, transfer fees, confidential transfers) will
38
+ not work and there is NO on-chain fix — a mint's owner program is part
39
+ of its identity.
40
+ failMissingDetail: >-
41
+ createMint omits its programId argument (or passes undefined), which
42
+ silently defaults to the LEGACY Token program even though the file
43
+ imports {expected}. Pass {expected} explicitly.
44
+ failOtherDetail: >-
45
+ createMint passes '{got}' as programId; expected {expected}. If this is
46
+ a custom constant, alias it to {expected} or pass the canonical name so
47
+ the trap detector and downstream readers agree.
48
+ absentCallDetail: >-
49
+ Handler is in the SPL-token scope but does not call createMint; the
50
+ Token-2022 pin rule does not apply here.
51
+ scopeNotMetDetail: >-
52
+ File does not import TOKEN_2022_PROGRAM_ID; legacy-token codebase — the
53
+ Token-2022 pin rule does not apply.
54
+ test:
55
+ kind: token-program-consistency
package/package.json CHANGED
@@ -1,35 +1,76 @@
1
1
  {
2
2
  "name": "brainblast",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Deterministic auditor for catastrophic AI-integration bugs: scan a repo, find the silent money/auth traps, and generate the behavioral test that proves they're fixed.",
6
- "keywords": ["security", "static-analysis", "stripe", "webhook", "jwt", "solana", "bags", "ci", "ai", "audit"],
6
+ "keywords": [
7
+ "security",
8
+ "static-analysis",
9
+ "audit",
10
+ "stripe",
11
+ "webhook",
12
+ "jwt",
13
+ "solana",
14
+ "anchor",
15
+ "metaplex",
16
+ "token-2022",
17
+ "trust-graph",
18
+ "bags",
19
+ "rent",
20
+ "ci",
21
+ "ai"
22
+ ],
7
23
  "license": "MIT",
8
24
  "author": "DSB-117",
9
25
  "homepage": "https://github.com/DSB-117/brainblast/tree/main/packages/core#readme",
10
- "bugs": { "url": "https://github.com/DSB-117/brainblast/issues" },
11
- "repository": { "type": "git", "url": "git+https://github.com/DSB-117/brainblast.git", "directory": "packages/core" },
12
- "bin": { "brainblast": "dist/cli.js" },
26
+ "bugs": {
27
+ "url": "https://github.com/DSB-117/brainblast/issues"
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/DSB-117/brainblast.git",
32
+ "directory": "packages/core"
33
+ },
34
+ "bin": {
35
+ "brainblast": "dist/cli.js"
36
+ },
13
37
  "exports": {
14
- ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" }
38
+ ".": {
39
+ "types": "./dist/index.d.ts",
40
+ "import": "./dist/index.js"
41
+ }
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md"
46
+ ],
47
+ "engines": {
48
+ "node": ">=18"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public",
52
+ "provenance": true
15
53
  },
16
- "files": ["dist", "README.md"],
17
- "engines": { "node": ">=18" },
18
- "publishConfig": { "access": "public", "provenance": true },
19
54
  "scripts": {
20
55
  "build": "tsup",
21
56
  "prepublishOnly": "npm run typecheck && npm test && npm run build",
22
57
  "audit": "tsx src/cli.ts",
23
58
  "prove": "tsx scripts/prove.ts",
59
+ "synth": "tsx scripts/synth-prove.ts",
60
+ "synth:bags": "tsx scripts/synth-prove.ts findings/bags-known-answer.json",
24
61
  "test": "vitest run",
25
62
  "coverage": "vitest run --coverage",
26
63
  "typecheck": "tsc --noEmit -p tsconfig.json"
27
64
  },
28
65
  "dependencies": {
66
+ "tree-sitter": "^0.22.4",
67
+ "tree-sitter-rust": "^0.24.0",
29
68
  "ts-morph": "^23",
30
69
  "yaml": "^2"
31
70
  },
32
71
  "devDependencies": {
72
+ "@metaplex-foundation/mpl-token-metadata": "^3.4.0",
73
+ "@solana/spl-token": "^0.4.14",
33
74
  "@types/node": "^22",
34
75
  "@vitest/coverage-v8": "^2",
35
76
  "jose": "^5",