11 - Security Audit Assignment and Account Abstraction
Part 1: Task 1 - Evaluation
Part 2: Semester Task II - Security Audit Assignment
Each student acts as both Auditor (auditing a peer’s project) and Developer (responding to audit of their own project).
Grading Methodology
| Component | Points | Criteria |
|---|---|---|
| Report Quality | 10 points | Methodology (2.5), findings evaluation system (2.5), system overview (2.5), trust model (2.5). Inspire with Ackee Blockchain or Trail of Bits reports. |
| Triage & Response | 10 points | Triage findings (accept/reject with reasoning) and implement fixes. |
| Findings | 20 points | Staking mechanism by severity: Critical (10), High (5), Medium (3), Low (1). Instructor validates findings based on project owner’s triage. Valid findings earn points; invalid findings lose points. Score range: 0-20. |
Workflow
As Developer (initial setup):
- Grant read access to assigned Auditor(s) for your Task I repository
As Auditor:
- Fork Developer’s repository and make fork private
- Invite Developer as collaborator to your private fork
- Create audit branch (
audit/username) in your private fork - Push audit report PDF to audit branch in your fork
- Create GitHub issues in your private fork for each finding (use severity labels: Critical, High, Medium, Low)
- Once audit complete, create Pull Request from audit branch to main in your fork
- Link issues in PR description (e.g., "Findings: #1, #2, #3")
Important: All audit work stays in your private fork. Do not push anything to Developer’s original repository.
As Developer (triage and fixes):
- Accept collaboration invite to each Auditor’s private fork
- Review audit PR and linked issues in each fork
- Triage each issue (accept/reject with technical reasoning)
- For accepted findings: create fix branch in that fork, implement fixes, reference issue in commits
- Close accepted issues after fixes; reject invalid findings with justification
Important: Apply fixes separately in each Auditor’s private fork. Do not share fixes between auditors' forks or push to your original repository during audit period.
Privacy: Each Auditor works in their own private fork. Multiple Auditors cannot see each other’s findings.
All materials (PR, report PDF, issues, triage responses) remain in private fork for instructor evaluation.
Part 3: Account Abstraction
Introduction
This section explores Account Abstraction – a fundamental improvement to Ethereum’s account model that addresses limitations of Externally Owned Accounts (EOAs) introduced in Tutorials 3 and 4.
Tutorial Prerequisites
- Understanding of EOAs and Contract Accounts (Tutorial 3)
- Familiarity with Ethereum transaction model (Tutorial 4)
- Basic knowledge of Safe multisig wallets (Tutorial 3)
Tutorial Objectives
After completing this section, students should be able to:
- Explain the limitations of EOAs and why account abstraction is necessary
- Describe the architecture of EIP-4337 and its key components
- Compare EIP-4337 and EIP-7702 approaches to account abstraction
- Identify security trade-offs in smart contract wallets
Problem Statement: EOA Limitations
EOAs are public-private key pairs with a binary access model:
- Possession of the private key → enables any operation within the rules of the EVM
- Absence of the private key → prevents all operations
Security Limitations
| Limitation | Description |
|---|---|
| Single point of failure | Loss of seed phrase results in permanent asset inaccessibility |
| Theft vulnerability | Stolen keys grant immediate access to all funds |
| No recovery mechanism | No equivalent to password recovery in traditional systems |
Functional Limitations
| Limitation | Description |
|---|---|
| Gas payment | Transaction fees require maintaining an ETH balance |
| No batching | Each operation requires a separate transaction |
| Fixed authentication | Only ECDSA signature verification is supported |
Account Abstraction: The Solution
Account abstraction decouples authentication logic from the protocol layer, enabling smart contracts to define custom:
- Authentication – Multi-signature, biometrics, social recovery, passkeys
- Authorization – Spending limits, whitelisted addresses, time-locks
- Execution – Transaction batching, automation, gas abstraction
Implementation: EIP-4337
EIP-4337 introduces account abstraction without modifying Ethereum’s core protocol. Deployed to Mainnet on March 1, 2023, it has seen significant adoption, particularly on Layer 2 networks, with millions of smart accounts deployed across Ethereum, Arbitrum, Optimism, Polygon, and Base.
Architecture
| Component | Role |
|---|---|
| Smart Contract Wallet | User’s account implementing custom validation logic |
| UserOperation | Pseudo-transaction object describing user intent |
| Bundler | Off-chain actor collecting UserOperations into regular transactions |
| EntryPoint Contract | Singleton contract validating and executing UserOperations |
| Paymaster | Optional contract sponsoring gas fees for users |
| Aggregator | Optional contract aggregating signatures from multiple UserOperations |
UserOperation Structure
{
"sender": "0x...", // Smart wallet address
"nonce": "0x1",
"initCode": "0x...", // Wallet deployment code (if needed)
"callData": "0x...", // Operation to execute
"callGasLimit": "0x...",
"verificationGasLimit": "0x...",
"preVerificationGas": "0x...",
"maxFeePerGas": "0x...",
"maxPriorityFeePerGas": "0x...",
"paymasterAndData": "0x...", // Gas sponsorship data
"signature": "0x..." // Wallet-specific signature
}Transaction Flow
The following diagram illustrates the complete EIP-4337 architecture and transaction flow:

Flow explanation:
- User creates UserOperation – The Smart Contract Wallet generates a UserOperation containing transaction details:
sender,callData,signature,nonce, and gas parameters (callGasLimit,verificationGasLimit,maxFeePerGas) - Alternative Mempool – UserOperations are sent to a separate mempool (not Ethereum’s standard mempool) where bundlers can access them
- Bundler collects operations – The Bundler (off-chain actor) selects multiple UserOperations and bundles them together
- Bundler simulates – The Bundler calls the EntryPoint Contract’s
simulateValidation()to verify operations will succeed before submitting - Bundler executes – The Bundler submits the bundle to the EntryPoint Contract’s
handleOps()function via a regular Ethereum transaction - Validation phase – The EntryPoint Contract calls each wallet’s
validateUserOp()function:- If an Aggregator is specified, it validates aggregated signatures
- If a Paymaster is specified (
paymasterAndData), it validates and commits to sponsor gas fees - The Smart Contract Wallet verifies the operation is authorized
- Execution phase – If validation passes, the EntryPoint Contract executes the operation (
callData) in the wallet’s context - Result – The Smart Contract Wallet executes the intended operation (e.g., token transfer, contract interaction)
This separation of validation and execution enables arbitrary authentication logic while maintaining protocol security guarantees.
Implementation: EIP-7702
EIP-7702 enables native account abstraction by allowing EOAs to delegate to smart contract code. Deployed as part of Ethereum’s Pectra upgrade on May 7, 2025.
Mechanism
EIP-7702 introduces a delegation designator that points an EOA to a smart contract:
- EOA sets delegation to a smart contract address
- When the EOA receives a transaction, EVM loads the designated contract’s code
- Code executes in the context of the EOA (using EOA’s storage and balance)
- EOA gains smart contract capabilities while retaining its address
Comparison: EIP-4337 vs EIP-7702
| Aspect | EIP-4337 | EIP-7702 |
|---|---|---|
| Protocol changes | None required | Requires hard fork |
| Account type | New smart contract wallets | Upgrades existing EOAs |
| Address | New address | Keeps existing EOA address |
| Status | Live (March 2023) | Deployed (May 2025) |
| Gas overhead | Higher (bundler infrastructure) | Lower (native execution) |
Important:
Complementary Approaches: EIP-7702 does not replace EIP-4337. EOAs upgraded via EIP-7702 can utilize EIP-4337 infrastructure (bundlers, paymasters) for advanced features. The ecosystem is evolving toward a hybrid model.
Key Features Enabled
Social Recovery
Designation of guardians who can facilitate account recovery:
contract SocialRecoveryWallet {
address[] public guardians;
uint256 public threshold;
mapping(address => mapping(address => bool)) public recoveryApprovals;
function initiateRecovery(address newOwner) external {
require(isGuardian(msg.sender), "Not a guardian");
recoveryApprovals[newOwner][msg.sender] = true;
if (countApprovals(newOwner) >= threshold) {
owner = newOwner;
}
}
}Gas Sponsorship (Paymasters)
Third-party gas payment enabling:
- Dapp-sponsored transactions – Applications subsidize user onboarding
- Token payments – Gas fees paid in ERC-20 tokens (USDC, DAI)
- Subscription models – Prepaid transaction allowances
Session Keys
Temporary, scoped permissions for dapps:
struct SessionKey {
address key;
uint256 validUntil;
uint256 spendingLimit;
address[] allowedContracts;
}Transaction Batching
Atomic execution of multiple operations:
// Single transaction replacing approve + swap
wallet.executeBatch([
Call(token, abi.encodeCall(IERC20.approve, (dex, amount))),
Call(dex, abi.encodeCall(IDex.swap, (tokenIn, tokenOut, amount)))
]);Security Considerations
Advantages
- Reduced single point of failure – Multiple recovery mechanisms available
- Programmable security – Custom rules per transaction type or value
- Phishing resistance – Eliminates seed phrase as attack vector
- Replay protection – Implemented in smart contract logic
New Attack Vectors
- Smart contract bugs – Wallet code vulnerabilities can compromise all funds
- Bundler centralization – Dependence on bundlers for transaction inclusion
- Paymaster trust – Malicious paymasters may censor or front-run transactions
- Increased complexity – Larger attack surface compared to EOAs
- Delegatecall vulnerabilities – Untrusted delegatecalls can execute arbitrary code in wallet context
Delegatecall Attack Vector: The Bybit Hack
On February 21, 2025, cryptocurrency exchange Bybit suffered a $1.5 billion hack — the largest in crypto history. This wasn’t a smart contract vulnerability but an operational security failure exploiting Safe wallet’s delegatecall functionality.
Attack Mechanics:
Attackers compromised the Safe signing frontend used by all Bybit multisig signers. When signers authorized what appeared to be routine transactions, they were actually signing transactions that:
- Changed the implementation address of their Safe multisig wallet via
delegatecall - Replaced it with a malicious implementation granting attacker control
- Bypassed the multisig security entirely
The delegatecall opcode is particularly dangerous in smart contract wallets because it executes external code in the wallet’s context with full access to storage and balance.
Why Signers Didn’t Detect the Attack:
- Malware modified the wallet interface to hide transaction details
- Blind signing on hardware wallets — devices display only transaction hashes, not complete semantic information
- Single verification interface without secondary confirmation mechanisms
Attack Scenario:
// Malicious contract
contract Malicious {
// Storage slot 0 matches wallet's owner variable
address public owner;
function attack() external {
// Changes the wallet's owner to attacker
owner = msg.sender;
}
}
// If wallet executes: delegatecall(malicious.attack())
// The attacker becomes the new ownerLessons from Bybit:
- Disable
delegatecallentirely in production wallets, or restrict it to whitelisted contracts - Verify the operation field (0 = CALL, 1 = DELEGATECALL) before signing
- Implement secondary verification using independent tools (see below)
- Configure Safe Guards — Use on-chain security protocols to prevent unauthorized operations
Safe Guards: On-Chain Protection
Safe Guards are on-chain security modules that can prevent the Bybit-style attack at the protocol level. Guards implement pre-checks and post-checks for every transaction.
Example: ScopeGuard
function checkTransaction(
address to,
uint256 value,
bytes memory data,
Enum.Operation operation,
...
) external view override {
// Prevent delegatecalls to untrusted addresses
require(
operation != Enum.Operation.DelegateCall ||
allowedTargets[to].delegateCallAllowed,
"Delegate call not allowed to this address"
);
// Whitelist target addresses
require(allowedTargets[to].allowed, "Target address is not allowed");
// Restrict ETH transfers
if (value > 0) {
require(allowedTargets[to].valueAllowed, "Cannot send ETH to this target");
}
// Whitelist function selectors
if (data.length >= 4) {
require(
!allowedTargets[to].scoped ||
allowedTargets[to].allowedFunctions[bytes4(data)],
"Target function is not allowed"
);
}
}Guard Use Cases:
- Prevent all delegatecalls — Block operation type 1 entirely
- Whitelist addresses — Only allow transactions to approved contracts
- Function-level restrictions — Permit only specific function selectors
- Timelocks — Delay high-value transactions for monitoring
- Invariant checking — Verify state transitions after execution
Important:
Safe Guards could have prevented the Bybit hack entirely. If Bybit had configured a guard to block delegatecall operations or whitelist allowed targets, the malicious implementation swap would have failed on-chain, regardless of compromised frontends or blind signing.
For detailed analysis:
Transaction Verification Best Practices
Always verify Safe transactions before signing using independent tools. The Safe Transaction Hash Verification Tool provides cryptographic verification:
Usage Example:
# Verify a Safe transaction on Arbitrum
./safe_hashes.sh --network arbitrum \
--address 0x111CEEee040739fD91D29C34C33E6B3E112F2177 \
--nonce 234Output includes:
- Domain hash
- Message hash
- Safe transaction hash
- Decoded method and parameters
- Warnings for delegatecalls to untrusted addresses
Warning:
Smart contract wallets require thorough security audits. A vulnerability in wallet validation logic could enable unauthorized access to user funds.