solidity-argus 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.
Files changed (167) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +93 -37
  3. package/package.json +33 -7
  4. package/skills/INVENTORY.md +88 -57
  5. package/skills/README.md +26 -23
  6. package/skills/case-studies/beanstalk-governance/SKILL.md +52 -0
  7. package/skills/case-studies/bzx-flash-loan/SKILL.md +53 -0
  8. package/skills/case-studies/cream-finance/SKILL.md +52 -0
  9. package/skills/case-studies/curve-reentrancy/SKILL.md +52 -0
  10. package/skills/case-studies/dao-hack/SKILL.md +51 -0
  11. package/skills/case-studies/euler-finance/SKILL.md +52 -0
  12. package/skills/case-studies/harvest-finance/SKILL.md +52 -0
  13. package/skills/case-studies/level-finance/SKILL.md +51 -0
  14. package/skills/case-studies/mango-markets/SKILL.md +53 -0
  15. package/skills/case-studies/nomad-bridge/SKILL.md +51 -0
  16. package/skills/case-studies/parity-multisig/SKILL.md +55 -0
  17. package/skills/case-studies/poly-network/SKILL.md +51 -0
  18. package/skills/case-studies/rari-fuse/SKILL.md +51 -0
  19. package/skills/case-studies/ronin-bridge/SKILL.md +52 -0
  20. package/skills/case-studies/wormhole-bridge/SKILL.md +51 -0
  21. package/skills/manifests/smartbugs.json +1 -3
  22. package/skills/manifests/sunweb3sec.json +1 -3
  23. package/skills/vulnerability-patterns/access-control/SKILL.md +14 -0
  24. package/skills/vulnerability-patterns/arbitrary-storage-location/SKILL.md +13 -1
  25. package/skills/vulnerability-patterns/assert-violation/SKILL.md +8 -1
  26. package/skills/vulnerability-patterns/asserting-contract-from-code-size/SKILL.md +12 -1
  27. package/skills/vulnerability-patterns/authorization-txorigin/SKILL.md +2 -1
  28. package/skills/vulnerability-patterns/cross-chain-bridge-vulnerabilities/SKILL.md +217 -0
  29. package/skills/vulnerability-patterns/default-visibility/SKILL.md +13 -1
  30. package/skills/vulnerability-patterns/delegatecall-untrusted-callee/SKILL.md +2 -1
  31. package/skills/vulnerability-patterns/dos-gas-limit/SKILL.md +8 -1
  32. package/skills/vulnerability-patterns/dos-revert/SKILL.md +1 -0
  33. package/skills/vulnerability-patterns/erc4626-exchange-rate-manipulation/SKILL.md +64 -0
  34. package/skills/vulnerability-patterns/fee-on-transfer-tokens/SKILL.md +93 -0
  35. package/skills/vulnerability-patterns/flash-loan-attacks/SKILL.md +1 -0
  36. package/skills/vulnerability-patterns/floating-pragma/SKILL.md +8 -1
  37. package/skills/vulnerability-patterns/front-running-attacks/SKILL.md +209 -0
  38. package/skills/vulnerability-patterns/gas-optimization-patterns/SKILL.md +203 -0
  39. package/skills/vulnerability-patterns/governance-attacks/SKILL.md +208 -0
  40. package/skills/vulnerability-patterns/hash-collision/SKILL.md +8 -1
  41. package/skills/vulnerability-patterns/inadherence-to-standards/SKILL.md +12 -1
  42. package/skills/vulnerability-patterns/incorrect-constructor/SKILL.md +8 -1
  43. package/skills/vulnerability-patterns/incorrect-inheritance-order/SKILL.md +8 -1
  44. package/skills/vulnerability-patterns/insufficient-gas-griefing/SKILL.md +12 -1
  45. package/skills/vulnerability-patterns/lack-of-precision/SKILL.md +7 -1
  46. package/skills/vulnerability-patterns/logic-errors/SKILL.md +10 -0
  47. package/skills/vulnerability-patterns/missing-parameter-bounds/SKILL.md +44 -0
  48. package/skills/vulnerability-patterns/missing-protection-signature-replay/SKILL.md +17 -1
  49. package/skills/vulnerability-patterns/msgvalue-loop/SKILL.md +12 -1
  50. package/skills/vulnerability-patterns/off-by-one/SKILL.md +7 -1
  51. package/skills/vulnerability-patterns/oracle-manipulation/SKILL.md +9 -0
  52. package/skills/vulnerability-patterns/outdated-compiler-version/SKILL.md +8 -1
  53. package/skills/vulnerability-patterns/overflow-underflow/SKILL.md +1 -0
  54. package/skills/vulnerability-patterns/proxy-vulnerabilities/SKILL.md +209 -0
  55. package/skills/vulnerability-patterns/reentrancy/SKILL.md +9 -0
  56. package/skills/vulnerability-patterns/shadowing-state-variables/SKILL.md +8 -1
  57. package/skills/vulnerability-patterns/share-accounting-desynchronization/SKILL.md +44 -0
  58. package/skills/vulnerability-patterns/signature-malleability/SKILL.md +2 -1
  59. package/skills/vulnerability-patterns/stateful-parameter-update-drift/SKILL.md +44 -0
  60. package/skills/vulnerability-patterns/unbounded-return-data/SKILL.md +12 -1
  61. package/skills/vulnerability-patterns/unchecked-return-values/SKILL.md +2 -1
  62. package/skills/vulnerability-patterns/unencrypted-private-data-on-chain/SKILL.md +8 -1
  63. package/skills/vulnerability-patterns/unexpected-ecrecover-null-address/SKILL.md +8 -1
  64. package/skills/vulnerability-patterns/uninitialized-storage-pointer/SKILL.md +8 -1
  65. package/skills/vulnerability-patterns/unsafe-erc20-transfers/SKILL.md +132 -0
  66. package/skills/vulnerability-patterns/unsafe-low-level-call/SKILL.md +12 -1
  67. package/skills/vulnerability-patterns/unsecure-signatures/SKILL.md +12 -1
  68. package/skills/vulnerability-patterns/unsupported-opcodes/SKILL.md +11 -1
  69. package/skills/vulnerability-patterns/unused-variables/SKILL.md +8 -1
  70. package/skills/vulnerability-patterns/use-of-deprecated-functions/SKILL.md +8 -1
  71. package/skills/vulnerability-patterns/weak-sources-randomness/SKILL.md +8 -1
  72. package/skills/vulnerability-patterns/weird-tokens/SKILL.md +10 -0
  73. package/skills/vulnerability-patterns/zero-address-misconfiguration/SKILL.md +48 -0
  74. package/src/agents/argus-prompt.ts +24 -7
  75. package/src/agents/pythia-prompt.ts +3 -4
  76. package/src/agents/scribe-prompt.ts +7 -2
  77. package/src/agents/sentinel-prompt.ts +32 -3
  78. package/src/cli/cli-program.ts +29 -26
  79. package/src/cli/commands/check-skills.ts +135 -0
  80. package/src/cli/commands/doctor.ts +48 -26
  81. package/src/cli/commands/init.ts +5 -3
  82. package/src/cli/commands/install.ts +7 -5
  83. package/src/cli/commands/lint-skills.ts +16 -12
  84. package/src/cli/index.ts +5 -5
  85. package/src/cli/types.ts +3 -3
  86. package/src/config/index.ts +1 -1
  87. package/src/config/loader.ts +4 -6
  88. package/src/config/schema.ts +4 -5
  89. package/src/config/types.ts +2 -2
  90. package/src/constants/defaults.ts +2 -0
  91. package/src/create-hooks.ts +145 -34
  92. package/src/create-managers.ts +10 -8
  93. package/src/create-tools.ts +13 -9
  94. package/src/features/background-agent/background-manager.ts +93 -87
  95. package/src/features/background-agent/index.ts +1 -1
  96. package/src/features/context-monitor/context-monitor.ts +3 -3
  97. package/src/features/context-monitor/index.ts +2 -2
  98. package/src/features/error-recovery/session-recovery.ts +2 -4
  99. package/src/features/error-recovery/tool-error-recovery.ts +12 -7
  100. package/src/features/index.ts +5 -5
  101. package/src/features/persistent-state/audit-state-manager.ts +143 -60
  102. package/src/features/persistent-state/global-run-index.ts +38 -0
  103. package/src/features/persistent-state/index.ts +1 -1
  104. package/src/features/persistent-state/run-journal.ts +86 -0
  105. package/src/hooks/config-handler.ts +28 -11
  106. package/src/hooks/context-budget.ts +2 -5
  107. package/src/hooks/event-hook.ts +47 -23
  108. package/src/hooks/hook-system.ts +4 -4
  109. package/src/hooks/index.ts +5 -5
  110. package/src/hooks/knowledge-sync-hook.ts +18 -21
  111. package/src/hooks/recon-context-builder.ts +2 -2
  112. package/src/hooks/safe-create-hook.ts +6 -7
  113. package/src/hooks/tool-tracking-hook.ts +104 -50
  114. package/src/hooks/types.ts +2 -1
  115. package/src/index.ts +23 -36
  116. package/src/knowledge/retry.ts +22 -22
  117. package/src/knowledge/scvd-client.ts +88 -95
  118. package/src/knowledge/scvd-errors.ts +35 -35
  119. package/src/knowledge/scvd-index.ts +78 -80
  120. package/src/knowledge/scvd-sync.ts +106 -101
  121. package/src/managers/index.ts +1 -1
  122. package/src/managers/types.ts +19 -14
  123. package/src/plugin-interface.ts +7 -9
  124. package/src/shared/binary-utils.ts +44 -35
  125. package/src/shared/deep-merge.ts +55 -36
  126. package/src/shared/file-utils.ts +21 -19
  127. package/src/shared/index.ts +11 -5
  128. package/src/shared/jsonc-parser.ts +123 -28
  129. package/src/shared/logger.ts +16 -3
  130. package/src/shared/project-utils.ts +30 -0
  131. package/src/skills/analysis/cluster.ts +414 -0
  132. package/src/skills/analysis/gates.ts +227 -0
  133. package/src/skills/analysis/index.ts +33 -0
  134. package/src/skills/analysis/normalize.ts +217 -0
  135. package/src/skills/analysis/similarity.ts +224 -0
  136. package/src/skills/argus-skill-resolver.ts +17 -6
  137. package/src/skills/skill-schema.ts +11 -10
  138. package/src/solodit-lifecycle.ts +202 -0
  139. package/src/state/audit-state.ts +8 -8
  140. package/src/state/finding-store.ts +68 -55
  141. package/src/state/types.ts +88 -67
  142. package/src/tools/argus-skill-load-tool.ts +12 -7
  143. package/src/tools/contract-analyzer-tool.ts +60 -77
  144. package/src/tools/forge-coverage-tool.ts +226 -0
  145. package/src/tools/forge-fuzz-tool.ts +127 -127
  146. package/src/tools/forge-test-tool.ts +153 -157
  147. package/src/tools/gas-analysis-tool.ts +264 -0
  148. package/src/tools/pattern-checker-tool.ts +185 -190
  149. package/src/tools/pattern-loader.ts +5 -111
  150. package/src/tools/proxy-detection-tool.ts +224 -0
  151. package/src/tools/report-generator-tool.ts +268 -200
  152. package/src/tools/slither-tool.ts +266 -218
  153. package/src/tools/solodit-search-tool.ts +216 -119
  154. package/src/tools/sync-knowledge-tool.ts +7 -11
  155. package/src/utils/audit-artifact-detector.ts +28 -29
  156. package/src/utils/dependency-scanner.ts +37 -37
  157. package/src/utils/project-detector.ts +111 -124
  158. package/src/utils/solidity-parser.ts +103 -74
  159. package/skills/patterns/access-control.yaml +0 -31
  160. package/skills/patterns/erc4626.yaml +0 -29
  161. package/skills/patterns/flash-loan.yaml +0 -20
  162. package/skills/patterns/oracle.yaml +0 -30
  163. package/skills/patterns/proxy.yaml +0 -30
  164. package/skills/patterns/reentrancy.yaml +0 -30
  165. package/skills/patterns/signature.yaml +0 -31
  166. package/src/hooks/event-hook-v2.ts +0 -99
  167. package/src/state/plugin-state.ts +0 -14
@@ -1,22 +1,22 @@
1
- import type { ContractProfile } from "../state/types";
1
+ import type { ContractProfile } from "../state/types"
2
2
 
3
3
  interface ABIFunction {
4
- type: string;
5
- name: string;
6
- inputs?: Array<{ name: string; type: string }>;
7
- outputs?: Array<{ name: string; type: string }>;
8
- stateMutability?: string;
4
+ type: string
5
+ name: string
6
+ inputs?: Array<{ name: string; type: string }>
7
+ outputs?: Array<{ name: string; type: string }>
8
+ stateMutability?: string
9
9
  }
10
10
 
11
11
  interface StorageLayoutItem {
12
- label: string;
13
- type: string;
14
- slot: string;
12
+ label: string
13
+ type: string
14
+ slot: string
15
15
  }
16
16
 
17
17
  interface StorageLayout {
18
- storage: StorageLayoutItem[];
19
- types: Record<string, { label: string }>;
18
+ storage: StorageLayoutItem[]
19
+ types: Record<string, { label: string }>
20
20
  }
21
21
 
22
22
  /**
@@ -25,12 +25,48 @@ interface StorageLayout {
25
25
  * Falls back to the original string if no JSON delimiter is found.
26
26
  */
27
27
  function extractJson(raw: string, opener: "[" | "{"): string {
28
- const closer = opener === "[" ? "]" : "}";
29
- const start = raw.indexOf(opener);
30
- if (start === -1) return raw;
31
- const end = raw.lastIndexOf(closer);
32
- if (end === -1) return raw;
33
- return raw.slice(start, end + 1);
28
+ const _closer = opener === "[" ? "]" : "}"
29
+ const start = raw.indexOf(opener)
30
+ if (start === -1) return raw
31
+
32
+ let depth = 0
33
+ let inString = false
34
+ let escaped = false
35
+
36
+ for (let i = start; i < raw.length; i++) {
37
+ const ch = raw.charAt(i)
38
+
39
+ if (inString) {
40
+ if (escaped) {
41
+ escaped = false
42
+ continue
43
+ }
44
+ if (ch === "\\") {
45
+ escaped = true
46
+ continue
47
+ }
48
+ if (ch === '"') {
49
+ inString = false
50
+ }
51
+ continue
52
+ }
53
+
54
+ if (ch === '"') {
55
+ inString = true
56
+ continue
57
+ }
58
+
59
+ if (ch === "{" || ch === "[") {
60
+ depth++
61
+ } else if (ch === "}" || ch === "]") {
62
+ depth--
63
+ if (depth === 0) {
64
+ return raw.slice(start, i + 1)
65
+ }
66
+ }
67
+ }
68
+
69
+ return raw
34
70
  }
35
71
 
36
72
  /**
@@ -41,7 +77,7 @@ function extractJson(raw: string, opener: "[" | "{"): string {
41
77
  */
42
78
  export async function extractContractInfo(
43
79
  contractName: string,
44
- projectDir: string
80
+ projectDir: string,
45
81
  ): Promise<ContractProfile> {
46
82
  const result: ContractProfile = {
47
83
  name: contractName,
@@ -52,23 +88,21 @@ export async function extractContractInfo(
52
88
  accessControlPattern: "none",
53
89
  externalCalls: [],
54
90
  riskIndicators: [],
55
- };
91
+ }
56
92
 
57
93
  try {
58
94
  // Run forge inspect abi
59
- const abiResult = Bun.spawnSync(
60
- ["forge", "inspect", contractName, "abi", "--json"],
61
- {
62
- cwd: projectDir,
63
- stdout: "pipe",
64
- stderr: "pipe",
65
- }
66
- );
95
+ const abiResult = Bun.spawnSync(["forge", "inspect", contractName, "abi", "--json"], {
96
+ cwd: projectDir,
97
+ stdout: "pipe",
98
+ stderr: "pipe",
99
+ timeout: 15_000,
100
+ })
67
101
 
68
102
  if (!abiResult.success) {
69
- const errorMsg = abiResult.stderr?.toString() || "Unknown error";
70
- result.error = `Failed to inspect ABI: ${errorMsg}`;
71
- return result;
103
+ const errorMsg = abiResult.stderr?.toString() || "Unknown error"
104
+ result.error = `Failed to inspect ABI: ${errorMsg}`
105
+ return result
72
106
  }
73
107
 
74
108
  // Run forge inspect storage-layout
@@ -78,65 +112,66 @@ export async function extractContractInfo(
78
112
  cwd: projectDir,
79
113
  stdout: "pipe",
80
114
  stderr: "pipe",
81
- }
82
- );
115
+ timeout: 15_000,
116
+ },
117
+ )
83
118
 
84
119
  if (!storageResult.success) {
85
- const errorMsg = storageResult.stderr?.toString() || "Unknown error";
86
- result.error = `Failed to inspect storage layout: ${errorMsg}`;
87
- return result;
120
+ const errorMsg = storageResult.stderr?.toString() || "Unknown error"
121
+ result.error = `Failed to inspect storage layout: ${errorMsg}`
122
+ return result
88
123
  }
89
124
 
90
125
  // Parse ABI
91
- const abiRaw = abiResult.stdout?.toString() || "[]";
92
- const abiOutput = extractJson(abiRaw, "[");
93
- let abi: ABIFunction[] = [];
126
+ const abiRaw = abiResult.stdout?.toString() || "[]"
127
+ const abiOutput = extractJson(abiRaw, "[")
128
+ let abi: ABIFunction[] = []
94
129
  try {
95
- abi = JSON.parse(abiOutput);
130
+ abi = JSON.parse(abiOutput)
96
131
  } catch (e) {
97
- result.error = `Failed to parse ABI JSON: ${e instanceof Error ? e.message : "Unknown error"}`;
98
- return result;
132
+ result.error = `Failed to parse ABI JSON: ${e instanceof Error ? e.message : "Unknown error"}`
133
+ return result
99
134
  }
100
135
 
101
136
  // Parse storage layout
102
- const storageRaw = storageResult.stdout?.toString() || "{}";
103
- const storageOutput = extractJson(storageRaw, "{");
104
- let storageLayout: StorageLayout = { storage: [], types: {} };
137
+ const storageRaw = storageResult.stdout?.toString() || "{}"
138
+ const storageOutput = extractJson(storageRaw, "{")
139
+ let storageLayout: StorageLayout = { storage: [], types: {} }
105
140
  try {
106
- storageLayout = JSON.parse(storageOutput);
141
+ storageLayout = JSON.parse(storageOutput)
107
142
  } catch (e) {
108
- result.error = `Failed to parse storage layout JSON: ${e instanceof Error ? e.message : "Unknown error"}`;
109
- return result;
143
+ result.error = `Failed to parse storage layout JSON: ${e instanceof Error ? e.message : "Unknown error"}`
144
+ return result
110
145
  }
111
146
 
112
147
  // Extract functions from ABI
113
- const functions = abi.filter((item) => item.type === "function");
148
+ const functions = abi.filter((item) => item.type === "function")
114
149
  result.functions = functions.map((func) => ({
115
150
  name: func.name || "",
116
151
  visibility: mapStateMutabilityToVisibility(func.stateMutability || "nonpayable"),
117
152
  mutability: func.stateMutability || "nonpayable",
118
153
  modifiers: [],
119
- }));
154
+ }))
120
155
 
121
156
  // Extract state variables from storage layout
122
157
  result.stateVars = storageLayout.storage.map((item) => {
123
- const typeInfo = storageLayout.types[item.type];
124
- const typeLabel = typeInfo?.label || item.type;
158
+ const typeInfo = storageLayout.types[item.type]
159
+ const typeLabel = typeInfo?.label || item.type
125
160
 
126
161
  return {
127
162
  name: item.label,
128
163
  type: typeLabel,
129
164
  visibility: "internal", // Default visibility for storage vars
130
- };
131
- });
165
+ }
166
+ })
132
167
 
133
168
  // Detect access control pattern
134
- result.accessControlPattern = detectAccessControlPattern(result.functions);
169
+ result.accessControlPattern = detectAccessControlPattern(result.functions)
135
170
 
136
- return result;
171
+ return result
137
172
  } catch (e) {
138
- result.error = `Unexpected error: ${e instanceof Error ? e.message : "Unknown error"}`;
139
- return result;
173
+ result.error = `Unexpected error: ${e instanceof Error ? e.message : "Unknown error"}`
174
+ return result
140
175
  }
141
176
  }
142
177
 
@@ -144,18 +179,16 @@ export async function extractContractInfo(
144
179
  * Map Solidity stateMutability to visibility
145
180
  * ABI doesn't directly specify visibility, so we infer from mutability
146
181
  */
147
- function mapStateMutabilityToVisibility(
148
- stateMutability: string
149
- ): string {
182
+ function mapStateMutabilityToVisibility(stateMutability: string): string {
150
183
  switch (stateMutability) {
151
184
  case "pure":
152
185
  case "view":
153
- return "view";
186
+ return "view"
154
187
  case "payable":
155
188
  case "nonpayable":
156
- return "external";
189
+ return "external"
157
190
  default:
158
- return "external";
191
+ return "external"
159
192
  }
160
193
  }
161
194
 
@@ -163,28 +196,24 @@ function mapStateMutabilityToVisibility(
163
196
  * Detect access control pattern from function names and signatures
164
197
  */
165
198
  function detectAccessControlPattern(
166
- functions: Array<{ name: string; visibility: string; mutability: string; modifiers: string[] }>
199
+ functions: Array<{ name: string; visibility: string; mutability: string; modifiers: string[] }>,
167
200
  ): "ownable" | "access-control" | "custom" | "none" {
168
- const functionNames = functions.map((f) => f.name.toLowerCase());
201
+ const functionNames = functions.map((f) => f.name.toLowerCase())
169
202
 
170
203
  // Check for Ownable pattern
171
204
  if (functionNames.includes("owner") || functionNames.includes("transferownership")) {
172
- return "ownable";
205
+ return "ownable"
173
206
  }
174
207
 
175
208
  // Check for AccessControl pattern (OpenZeppelin)
176
209
  if (functionNames.includes("hasrole") || functionNames.includes("grantrole")) {
177
- return "access-control";
210
+ return "access-control"
178
211
  }
179
212
 
180
213
  // Check for custom access control patterns
181
- if (
182
- functionNames.some((name) =>
183
- name.includes("onlyadmin") || name.includes("requireadmin")
184
- )
185
- ) {
186
- return "custom";
214
+ if (functionNames.some((name) => name.includes("onlyadmin") || name.includes("requireadmin"))) {
215
+ return "custom"
187
216
  }
188
217
 
189
- return "none";
218
+ return "none"
190
219
  }
@@ -1,31 +0,0 @@
1
- pack_name: access-control
2
- pack_version: "1.0"
3
- patterns:
4
- - name: missing-access-modifier
5
- category: access-control
6
- severity: High
7
- swc: SWC-105
8
- confidence: Low
9
- version: "1.0"
10
- regex: 'function\s+\w+\s*\([^)]*\)\s+(external|public)'
11
- description: External or public function — verify appropriate access control modifiers (onlyOwner, onlyRole, require(msg.sender)) are applied
12
- remediation: Add access control modifiers to sensitive functions; use OpenZeppelin AccessControl or Ownable patterns
13
-
14
- - name: unprotected-initialize
15
- category: access-control
16
- severity: Critical
17
- confidence: High
18
- version: "1.0"
19
- regex: 'function\s+initialize'
20
- description: Initializer function detected — if missing initializer modifier, anyone can call and take ownership of the contract
21
- remediation: Use OpenZeppelin Initializable with initializer modifier; call _disableInitializers() in constructor for implementation contracts
22
-
23
- - name: default-visibility
24
- category: access-control
25
- severity: Medium
26
- swc: SWC-100
27
- confidence: Low
28
- version: "1.0"
29
- regex: 'function\s+\w+\s*\([^)]*\)\s*\{'
30
- description: Function without explicit visibility specifier — defaults to public in older Solidity versions, potentially exposing internal logic
31
- remediation: Always specify visibility (external, public, internal, private) explicitly for every function
@@ -1,29 +0,0 @@
1
- pack_name: erc4626
2
- pack_version: "1.0"
3
- patterns:
4
- - name: inflation-attack
5
- category: erc4626
6
- severity: Critical
7
- confidence: High
8
- version: "1.0"
9
- regex: 'deposit.*totalSupply.*==.*0|convertToShares.*totalSupply'
10
- description: ERC-4626 vault first-depositor inflation attack — attacker can donate assets to vault before first deposit to manipulate share price and steal subsequent deposits
11
- remediation: Mint dead shares on first deposit (e.g., 10**3 to address(0)); use virtual offset in share calculation; set minimum deposit amount
12
-
13
- - name: donation-attack
14
- category: erc4626
15
- severity: High
16
- confidence: Medium
17
- version: "1.0"
18
- regex: 'balanceOf.*address.*this.*totalAssets|asset\.balanceOf'
19
- description: Vault totalAssets derived from balanceOf — vulnerable to donation attack where attacker sends assets directly to inflate share price
20
- remediation: Use internal accounting for totalAssets instead of balanceOf; track deposits and withdrawals explicitly
21
-
22
- - name: rounding-error
23
- category: erc4626
24
- severity: Medium
25
- confidence: Medium
26
- version: "1.0"
27
- regex: 'mulDiv|roundUp|roundDown|FullMath'
28
- description: Custom rounding math in vault share calculations — potential rounding errors that favor attacker (round down on deposit, round up on withdraw)
29
- remediation: Round against the user (down on deposit/mint, up on withdraw/redeem); use OpenZeppelin Math.mulDiv with explicit rounding direction
@@ -1,20 +0,0 @@
1
- pack_name: flash-loan
2
- pack_version: "1.0"
3
- patterns:
4
- - name: unchecked-flash-return
5
- category: flash-loan
6
- severity: High
7
- confidence: Medium
8
- version: "1.0"
9
- regex: 'flashLoan|flashBorrow'
10
- description: Flash loan invocation without verified return — borrowed funds may not be repaid if return value is not checked
11
- remediation: Verify flash loan callback returns expected success value; check token balance after repayment; use established flash loan receiver interfaces
12
-
13
- - name: balance-inflation
14
- category: flash-loan
15
- severity: Medium
16
- confidence: Medium
17
- version: "1.0"
18
- regex: 'balanceOf\(address\(this\)\)'
19
- description: Contract reads its own token balance — vulnerable to donation/inflation attacks where attacker sends tokens directly to manipulate balance-dependent logic
20
- remediation: Track balances via internal accounting instead of balanceOf(address(this)); use shares-based accounting for vaults
@@ -1,30 +0,0 @@
1
- pack_name: oracle-manipulation
2
- pack_version: "1.0"
3
- patterns:
4
- - name: stale-price-check
5
- category: oracle-manipulation
6
- severity: High
7
- swc: SWC-120
8
- confidence: High
9
- version: "1.0"
10
- regex: 'latestRoundData|getPrice'
11
- description: Oracle price feed usage — verify staleness checks (updatedAt, roundId) are enforced to prevent using outdated prices
12
- remediation: Add require(updatedAt > block.timestamp - MAX_STALENESS) after latestRoundData calls; check answeredInRound >= roundId
13
-
14
- - name: twap-manipulation
15
- category: oracle-manipulation
16
- severity: Medium
17
- confidence: Medium
18
- version: "1.0"
19
- regex: 'observe\(|consult\('
20
- description: TWAP oracle usage — time-weighted average prices can be manipulated via sustained trading pressure within the observation window
21
- remediation: Use sufficiently long TWAP windows (30+ minutes); combine with spot price deviation checks; add circuit breakers
22
-
23
- - name: price-feed-decimals
24
- category: oracle-manipulation
25
- severity: Medium
26
- confidence: Medium
27
- version: "1.0"
28
- regex: 'priceFeed|oracle.*decimals'
29
- description: Oracle price feed with decimal handling — potential decimal mismatch between oracle feed (8 decimals) and token (18 decimals)
30
- remediation: Normalize oracle response to consistent decimals; use oracle.decimals() dynamically rather than hardcoded values
@@ -1,30 +0,0 @@
1
- pack_name: proxy
2
- pack_version: "1.0"
3
- patterns:
4
- - name: storage-collision
5
- category: proxy
6
- severity: Critical
7
- swc: SWC-112
8
- confidence: Medium
9
- version: "1.0"
10
- regex: 'delegatecall|IMPLEMENTATION_SLOT'
11
- description: Delegatecall or implementation slot usage — potential storage collision between proxy and implementation contracts if storage layouts diverge
12
- remediation: Use EIP-1967 standard storage slots; use OpenZeppelin TransparentUpgradeableProxy or UUPS; verify storage layout compatibility on upgrades
13
-
14
- - name: uninitialized-proxy
15
- category: proxy
16
- severity: High
17
- confidence: Medium
18
- version: "1.0"
19
- regex: '_disableInitializers|initializer'
20
- description: Proxy initialization pattern detected — verify implementation contract calls _disableInitializers() in constructor and proxy calls initialize()
21
- remediation: Call _disableInitializers() in implementation constructor; ensure initialize() is called atomically during proxy deployment
22
-
23
- - name: selector-clash
24
- category: proxy
25
- severity: Medium
26
- confidence: Low
27
- version: "1.0"
28
- regex: 'fallback\(\)|receive\(\).*delegatecall'
29
- description: Fallback or receive function with delegatecall — risk of function selector clash between proxy admin functions and implementation functions
30
- remediation: Use TransparentUpgradeableProxy pattern to separate admin and user call paths; verify no selector collisions with implementation ABI
@@ -1,30 +0,0 @@
1
- pack_name: reentrancy
2
- pack_version: "1.0"
3
- patterns:
4
- - name: reentrancy-eth-transfer
5
- category: reentrancy
6
- severity: High
7
- swc: SWC-107
8
- confidence: High
9
- version: "1.0"
10
- regex: '\.call\{value:'
11
- description: ETH transfer via low-level call — classic reentrancy vector where external call is made before state updates
12
- remediation: Apply checks-effects-interactions pattern; use ReentrancyGuard; update state before external calls
13
-
14
- - name: reentrancy-erc20
15
- category: reentrancy
16
- severity: Medium
17
- confidence: Medium
18
- version: "1.0"
19
- regex: '\.(transfer|transferFrom)\('
20
- description: ERC-20 token transfer that may precede state changes — potential reentrancy via token callback hooks (ERC-777, ERC-1155)
21
- remediation: Update state variables before token transfers; use ReentrancyGuard for functions with external token interactions
22
-
23
- - name: cross-function-reentrancy
24
- category: reentrancy
25
- severity: High
26
- confidence: Low
27
- version: "1.0"
28
- regex: '(external|public)\s.*\{[^}]*\.call'
29
- description: Public or external function containing a low-level call — potential cross-function reentrancy if shared state is read by other functions
30
- remediation: Use ReentrancyGuard on all functions sharing mutable state; apply checks-effects-interactions across the contract
@@ -1,31 +0,0 @@
1
- pack_name: signature
2
- pack_version: "1.0"
3
- patterns:
4
- - name: replay-attack
5
- category: signature
6
- severity: High
7
- swc: SWC-117
8
- confidence: Medium
9
- version: "1.0"
10
- regex: 'ecrecover|ECDSA\.recover'
11
- description: Signature recovery without nonce tracking — signatures may be replayed across transactions or chains if nonce and chainId are not included in signed data
12
- remediation: Include nonce, chainId, and contract address in signed message hash; increment nonce after use; use EIP-712 typed structured data
13
-
14
- - name: sig-malleability
15
- category: signature
16
- severity: Medium
17
- swc: SWC-117
18
- confidence: Medium
19
- version: "1.0"
20
- regex: ecrecover
21
- description: Raw ecrecover usage — ECDSA signatures are malleable (s-value can be flipped) allowing signature reuse if not checked against canonical form
22
- remediation: Use OpenZeppelin ECDSA.recover which enforces s <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0; reject non-canonical signatures
23
-
24
- - name: missing-nonce
25
- category: signature
26
- severity: High
27
- confidence: Medium
28
- version: "1.0"
29
- regex: 'permit\(|signTypedData'
30
- description: Permit or typed data signing without nonce validation — missing nonce allows signature replay after the original transaction is executed
31
- remediation: Track per-address nonces mapping(address => uint256); include nonce in EIP-712 struct; increment nonce on each use
@@ -1,99 +0,0 @@
1
- import type { AuditState } from "../state/types"
2
- import { createAuditState } from "../state/audit-state"
3
- import { createLogger } from "../shared/logger"
4
-
5
- export type AuditEventType =
6
- | "session.created"
7
- | "session.idle"
8
- | "session.error"
9
- | "session.deleted"
10
- | "audit.phase-changed"
11
- | "audit.finding-added"
12
- | "audit.complete"
13
-
14
- export type EventHookV2Fn = (input: {
15
- event: { type: string; sessionId?: string; properties?: Record<string, unknown> }
16
- }) => Promise<void>
17
-
18
- export type EventSubHandler = (event: {
19
- type: string
20
- sessionId?: string
21
- auditState: AuditState | null
22
- setAuditState: (state: AuditState | null) => void
23
- }) => Promise<void>
24
-
25
- export function createEventHookV2(
26
- projectDir?: string,
27
- subHandlers: EventSubHandler[] = [],
28
- ): {
29
- hook: EventHookV2Fn
30
- getAuditState: () => AuditState | null
31
- setAuditState: (state: AuditState | null) => void
32
- } {
33
- const logger = createLogger()
34
- let currentAuditState: AuditState | null = null
35
-
36
- const getAuditState = (): AuditState | null => currentAuditState
37
- const setAuditState = (state: AuditState | null): void => {
38
- currentAuditState = state
39
- }
40
-
41
- const hook: EventHookV2Fn = async (input): Promise<void> => {
42
- const { type, sessionId } = input.event
43
-
44
- switch (type) {
45
- case "session.created": {
46
- const dir = projectDir ?? process.cwd()
47
- const { state } = createAuditState(dir)
48
- currentAuditState = state
49
- break
50
- }
51
-
52
- case "session.idle": {
53
- if (currentAuditState) {
54
- logger.debug(
55
- `Session idle — phase: ${currentAuditState.currentPhase}, findings: ${currentAuditState.findings.length}`,
56
- )
57
- }
58
- break
59
- }
60
-
61
- case "session.error": {
62
- if (currentAuditState) {
63
- logger.error(
64
- `Session error — state snapshot: ${JSON.stringify({
65
- sessionId: currentAuditState.sessionId,
66
- phase: currentAuditState.currentPhase,
67
- findingsCount: currentAuditState.findings.length,
68
- contractsReviewed: currentAuditState.contractsReviewed,
69
- })}`,
70
- )
71
- }
72
- break
73
- }
74
-
75
- case "session.deleted": {
76
- currentAuditState = null
77
- break
78
- }
79
-
80
- default:
81
- break
82
- }
83
-
84
- for (const handler of subHandlers) {
85
- try {
86
- await handler({
87
- type,
88
- sessionId,
89
- auditState: currentAuditState,
90
- setAuditState,
91
- })
92
- } catch (error) {
93
- logger.error(`Sub-handler failed for event ${type}:`, error)
94
- }
95
- }
96
- }
97
-
98
- return { hook, getAuditState, setAuditState }
99
- }
@@ -1,14 +0,0 @@
1
- import type { ArgusConfig } from "../config/types";
2
- import type { Managers } from "../managers/types";
3
-
4
- /**
5
- * PluginState interface
6
- * Represents the complete state of the Argus plugin instance
7
- * Includes configuration, project context, and manager instances
8
- */
9
- export interface PluginState {
10
- config: ArgusConfig;
11
- projectDir: string;
12
- managers: Managers;
13
- isHookEnabled: (name: string) => boolean;
14
- }