.claude/skills/solidity-guard/skills/access-control-reviewer/SKILL.md
Comprehensive access control and authorization review for Solidity contracts. Checks ownership, role-based access, proxy authorization, centralization risks, and privilege escalation vulnerabilities.
npx skillsauth add alt-research/solidityguard access-control-reviewerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Systematically validate access control in Solidity contracts. Access control failures are the #1 vulnerability category in 2025, responsible for $1.6B+ in losses.
State-changing function without any authorization check.
// VULNERABLE
function setPrice(uint newPrice) external {
price = newPrice; // Anyone can call!
}
// SECURE
function setPrice(uint newPrice) external onlyOwner {
price = newPrice;
}
// VULNERABLE — phishing attack via intermediate contract
require(tx.origin == owner);
// SECURE
require(msg.sender == owner);
// VULNERABLE
function destroy() external {
selfdestruct(payable(msg.sender));
}
// SECURE
function destroy() external onlyOwner {
selfdestruct(payable(owner));
}
Implementation contract not initialized, allowing anyone to take ownership.
Single admin can change critical parameters without timelock or multisig.
Post-Pectra, tx.origin == msg.sender no longer guarantees caller is an EOA. EOAs can have code via EIP-7702 delegation.
// VULNERABLE — broken after EIP-7702 (Pectra upgrade)
require(tx.origin == msg.sender, "No contracts");
// EOA with delegated code passes this check but executes arbitrary logic!
// SECURE — use ERC-165 or explicit whitelist
// Or: accept that EOAs can have code and design accordingly
EIP-7702 authorization tuples can be replayed on other chains if chain ID is not validated.
// VULNERABLE — no chain ID in authorization validation
function setDelegation(address delegate, bytes calldata sig) external {
// Missing: chainId check in signature verification
}
// SECURE — always include chain ID in EIP-7702 authorization
// The protocol enforces this, but custom implementations may not
Paymaster sponsors gas but doesn't validate actual execution cost or effects.
// VULNERABLE — paymaster pays for any UserOp
function validatePaymasterUserOp(UserOperation calldata userOp, ...)
external returns (bytes memory context, uint256 validationData) {
return ("", 0); // Approves everything!
}
// SECURE — validate user, op limits, and track spending
function validatePaymasterUserOp(UserOperation calldata userOp, ...)
external returns (bytes memory context, uint256 validationData) {
require(approvedUsers[userOp.sender], "Not approved");
require(userOp.callGasLimit <= MAX_GAS, "Gas too high");
require(dailySpend[userOp.sender] + cost <= DAILY_LIMIT, "Limit exceeded");
// ...
}
Validation phase has side effects that affect execution phase, violating ERC-4337 separation.
rg "function.*(external|public)" contracts/ | grep -v "view\|pure"
For each state-changing function, verify:
onlyOwner, onlyRole, or custom access modifiermsg.sender not tx.origintx.origin == msg.sender to detect EOA (EIP-7702 breaks this)initializer modifierOwner / Admin
├── Can: pause, unpause, upgrade, setFee
├── Should have: timelock, multisig
│
Operator / Manager
├── Can: harvest, rebalance
│
User
└── Can: deposit, withdraw, claim
rg "initializer|_disableInitializers|__gap" contracts/
rg "upgradeTo|upgradeToAndCall|_authorizeUpgrade" contracts/
rg "tx\.origin.*==.*msg\.sender|msg\.sender.*==.*tx\.origin" contracts/ # ETH-086
rg "extcodesize|isContract" contracts/ # ETH-089 — unreliable post-7702
rg "IPaymaster|validatePaymasterUserOp|UserOperation" contracts/ # ETH-091
rg "validateUserOp|IAccount" contracts/ # ETH-093
import "@openzeppelin/contracts/access/Ownable.sol";
// Single owner, transferable
import "@openzeppelin/contracts/access/AccessControl.sol";
// Role-based, granular permissions
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
import "@openzeppelin/contracts/access/Ownable2Step.sol";
// Two-step ownership transfer (safer)
tx.origin for authenticationtx.origin == msg.sender to detect EOA (broken by EIP-7702)extcodesize == 0 to detect EOA (broken by EIP-7702)selfdestructtools
Advanced Solidity/EVM smart contract security auditor with 104 vulnerability patterns, multi-tool integration, and professional report generation.
development
Comprehensive Solidity contract security scanner detecting 104 vulnerability patterns across reentrancy, access control, arithmetic, DeFi, proxy, and token categories. Integrates Slither, Aderyn, and Mythril with manual analysis.
testing
Analyzes storage layout, proxy patterns, and state variable security in Solidity contracts. Detects storage collisions, uninitialized pointers, and upgrade risks. Use when auditing proxy/upgradeable contracts.
development
Validates Solidity implementation against specification documents. Extracts behavior from docs (README, specs, NatSpec) and verifies code matches documented intent. Uses Trail of Bits methodology for divergence detection.