@elytrasec/engine 0.4.4 → 0.4.5

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 (2) hide show
  1. package/dist/index.js +69 -1
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -5164,6 +5164,71 @@ var rugSurfaceRules = [
5164
5164
  languages: SOL
5165
5165
  }
5166
5166
  ];
5167
+ var modernDeFiRules = [
5168
+ {
5169
+ id: "cp-sol-erc4626-inflation",
5170
+ title: "ERC-4626 vault: missing inflation-attack protection",
5171
+ description: "ERC-4626 deposit/mint computes shares as `assets * totalSupply / totalAssets`. On an empty vault, an attacker who is the first depositor can deposit 1 wei, then DIRECTLY transfer a large amount of underlying to the vault \u2014 inflating the share/asset ratio. Subsequent depositors get rounded to ZERO shares for any deposit smaller than the inflated rate. Cream, Hundred, and many forks lost funds this way.",
5172
+ suggestion: "Use OpenZeppelin's ERC4626 v5+ which adds 1e6 virtual shares/assets (decimal offset). OR: in deposit(), require msg.sender to mint to a dead address first (initial burn of N shares). OR: enforce a minimum total-supply invariant.",
5173
+ multilinePattern: /function\s+(?:deposit|mint)\s*\([^)]*\)\s*(?:external|public)[^{;]*\{[\s\S]{0,1500}?(?:totalSupply|_totalSupply)\s*\([^)]*\)\s*[*/]\s*\w(?![\s\S]{0,800}?(?:_decimalsOffset|virtualShares|VIRTUAL_SHARES|MINIMUM_LIQUIDITY|10\s*\*\*\s*\d|DEAD_SHARES|_burnDead|dead\s*\(|initialBurn))/,
5174
+ severity: "high",
5175
+ category: "solidity",
5176
+ confidence: "medium",
5177
+ languages: SOL
5178
+ },
5179
+ {
5180
+ id: "cp-sol-eip712-missing-chainid",
5181
+ title: "EIP-712 domain separator computed without chainId",
5182
+ description: "An EIP-712 typed-data signature scheme that omits `block.chainid` from the DOMAIN_SEPARATOR allows the same signature to be replayed on a fork or testnet. Several bridge and permit exploits have come from this exact gap.",
5183
+ suggestion: "Always include `block.chainid` in the EIP-712 domain hash, OR inherit from OpenZeppelin's EIP712 which handles it. Recompute the separator when chainid changes (fork detection).",
5184
+ // Catches the domain-separator computation. File-level FP filter in pattern-scanner.ts
5185
+ // suppresses this rule entirely if the file has any chainid reference anywhere.
5186
+ multilinePattern: /(?:DOMAIN_SEPARATOR|_domainSeparator|domainSeparator)\s*=\s*keccak256\s*\(\s*abi\.encode\s*\([\s\S]{20,500}?\)\s*\)/,
5187
+ severity: "high",
5188
+ category: "solidity",
5189
+ confidence: "medium",
5190
+ languages: SOL
5191
+ },
5192
+ {
5193
+ id: "cp-sol-swap-zero-deadline",
5194
+ title: "Swap call with zero or absent deadline (MEV vulnerable)",
5195
+ description: "Calling a Uniswap V2/V3/V4 router swap with deadline = 0, deadline = block.timestamp (no protection), or deadline = type(uint256).max means the transaction can sit in the mempool indefinitely and be sandwiched whenever the price moves against you. Users lose money to MEV bots.",
5196
+ suggestion: "Enforce a real deadline: `deadline = block.timestamp + 15 minutes` at minimum. Pass it from the user, not computed inside the function. Reject calls with deadline > block.timestamp + 1 hour.",
5197
+ // Catches both named-arg (deadline: 0) and positional last-arg = 0 or block.timestamp or type(uint).max.
5198
+ // Multiline + tolerant of nested parens (address(this), etc.). Catches positional last-arg
5199
+ // = 0, block.timestamp, or type(uint).max as the deadline.
5200
+ multilinePattern: /(?:swapExactTokensForTokens|swapTokensForExactTokens|exactInput|exactOutput|swap[A-Z]\w*)\s*\([\s\S]{0,400}?,\s*(?:0|block\.timestamp|type\s*\(\s*uint256\s*\)\s*\.\s*max)\s*\)\s*;/,
5201
+ severity: "medium",
5202
+ category: "solidity",
5203
+ confidence: "low",
5204
+ languages: SOL
5205
+ },
5206
+ {
5207
+ id: "cp-sol-bridge-missing-source-check",
5208
+ title: "Cross-chain receive function: missing source-chain / trusted-remote check",
5209
+ description: "LayerZero `lzReceive`, Axelar `_execute`, Hyperlane `handle`, Wormhole `receiveMessage` and similar cross-chain receivers MUST verify (a) the source chain ID and (b) the trusted-remote sender address. Without these checks ANY contract on any chain can forge a message and trigger the receive logic \u2014 leading to unauthorized mint/withdraw of bridged assets.",
5210
+ suggestion: "Add explicit checks: `require(_srcChainId == trustedSrcChain)` and `require(keccak256(_srcAddress) == keccak256(trustedRemote))`. For LayerZero use `lzApp.setTrustedRemote`. For Axelar verify `sourceChain` + `sourceAddress`.",
5211
+ // Bridge-specific function names; file-level filter in pattern-scanner.ts skips ERC-4337
5212
+ // and similar accounts. Negative lookahead for trusted-remote / source-check in body.
5213
+ multilinePattern: /function\s+(?:lzReceive|nonblockingLzReceive|_nonblockingLzReceive|_handleMessage|receiveMessage|handle)\s*\([^)]*\)\s*(?:external|internal|public)[^{;]*\{(?![\s\S]{0,1500}?(?:trustedRemote|_trustedRemoteLookup|sourceChain\s*==|_srcChainId\s*==|trustedSrcChain|trustedSender|_validateMessageSource|_authorizeSource|onlyEndpoint|onlyMailbox|onlyGateway|interchainSecurityModule))/,
5214
+ severity: "critical",
5215
+ category: "solidity",
5216
+ confidence: "medium",
5217
+ languages: SOL
5218
+ },
5219
+ {
5220
+ id: "cp-sol-permit2-no-deadline-check",
5221
+ title: "Permit signature accepted without deadline / expiry check",
5222
+ description: "EIP-2612 permit() (and similar typed-data signature endpoints) must check that `deadline >= block.timestamp`. Without this, a leaked signature is valid forever. Several memecoin-launchpad bugs of 2024 leaked permits and lost early-mover allocations.",
5223
+ suggestion: 'Add `require(deadline >= block.timestamp, "Permit expired")` at the top of permit-like functions. Reject if deadline is type(uint256).max (suggests caller forgot to set one).',
5224
+ // Also accept assembly-style timestamp/deadline check (Solady pattern: gt(timestamp(), deadline))
5225
+ multilinePattern: /function\s+(?:permit|permitWithSig|permitTransfer|permitTransferFrom)\s*\([^)]*deadline[^)]*\)[^{;]*\{(?![\s\S]{0,1500}?(?:deadline\s*[><]=?\s*block\.timestamp|block\.timestamp\s*[<>]=?\s*deadline|require\s*\([^)]*deadline|gt\s*\(\s*timestamp\s*\(\s*\)\s*,\s*deadline|PermitExpired|ExpiredSignature|EXPIRED))/,
5226
+ severity: "high",
5227
+ category: "solidity",
5228
+ confidence: "medium",
5229
+ languages: SOL
5230
+ }
5231
+ ];
5167
5232
  var ALL_RULES2 = [
5168
5233
  ...securityRules,
5169
5234
  ...solidityRules2,
@@ -5179,7 +5244,8 @@ var ALL_RULES2 = [
5179
5244
  ...eip7702Rules,
5180
5245
  ...tstoreRules,
5181
5246
  ...uniswapV4Rules,
5182
- ...hackReplayRules
5247
+ ...hackReplayRules,
5248
+ ...modernDeFiRules
5183
5249
  ];
5184
5250
 
5185
5251
  // src/static/pattern-scanner.ts
@@ -5516,6 +5582,8 @@ function scanFile(relPath, content, rules, changedRanges) {
5516
5582
  if (rule.id === "cp-clean-callback-hell" && isTestFile(relPath)) continue;
5517
5583
  if (rule.id === "cp-sec-command-injection" && isScriptDir(relPath)) continue;
5518
5584
  if (rule.id === "cp-hack-wormhole-unchecked-signature-set" && /\b(?:EIP712|DOMAIN_SEPARATOR|_hashTypedDataV4|PERMIT_TYPEHASH|DELEGATION_TYPEHASH|ERC1271|EIP712Upgradeable)\b/.test(content)) continue;
5585
+ if (rule.id === "cp-sol-eip712-missing-chainid" && /\b(?:block\.chainid|chainId|chainid)\b/.test(content)) continue;
5586
+ if (rule.id === "cp-sol-bridge-missing-source-check" && /\b(?:EntryPoint|UserOperation|PackedUserOperation|IERC7579|IERC4337|executionCalldata|onlyEntryPoint)\b/.test(content)) continue;
5519
5587
  rule.multilinePattern.lastIndex = 0;
5520
5588
  const isGlobal = rule.multilinePattern.flags.includes("g");
5521
5589
  let match;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@elytrasec/engine",
3
- "version": "0.4.4",
4
- "description": "Core analysis engine for Elytra \u2014 173 detection rules including 12 famous-hack patterns and 11 rug-surface checks, static + AI scanning, scoring.",
3
+ "version": "0.4.5",
4
+ "description": "Core analysis engine for Elytra \u2014 181 detection rules including 12 famous-hack patterns, 11 rug-surface checks, 5 modern-DeFi detectors (ERC-4626 inflation, EIP-712 chainId, bridge source check, permit deadline, MEV swap), static + AI scanning, scoring.",
5
5
  "license": "MIT",
6
6
  "author": "ElytraSec <hello@elytrasec.io>",
7
7
  "homepage": "https://elytrasec.io",