-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3cdbace
commit 4282ba0
Showing
20 changed files
with
715 additions
and
214 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
contract VulnerableContract { | ||
// Uninitialized state variable (high-severity vulnerability) | ||
address public owner; | ||
mapping(address => uint256) public balances; | ||
|
||
// 1. Reentrancy vulnerability (state update after external call) | ||
function deposit() public payable { | ||
balances[msg.sender] += msg.value; | ||
} | ||
|
||
function withdraw(uint256 amount) public { | ||
require(balances[msg.sender] >= amount, "Insufficient balance"); | ||
|
||
// Vulnerable: external call before state update (reentrancy issue) | ||
(bool success, ) = msg.sender.call{value: amount}(""); | ||
require(success, "Transfer failed"); | ||
|
||
balances[msg.sender] -= amount; // State update after external call | ||
} | ||
|
||
// 2. Unchecked low-level call (high-severity vulnerability) | ||
function unsafeTransfer(address recipient, uint256 amount) public { | ||
require(msg.sender == owner, "Only owner can transfer"); | ||
|
||
// Vulnerable: no return value check on low-level call | ||
recipient.call{value: amount}(""); | ||
} | ||
|
||
// 3. Block timestamp used for critical logic (high-severity vulnerability) | ||
function isExpired(uint256 expirationTime) public view returns (bool) { | ||
return block.timestamp > expirationTime; | ||
} | ||
|
||
// 4. Arbitrary function execution (access control vulnerability) | ||
function setOwner(address newOwner) public { | ||
owner = newOwner; // No access control, anyone can set the owner | ||
} | ||
|
||
// 5. Transfer entire contract balance (no proper access control) | ||
function drain(address payable recipient) public { | ||
require(msg.sender == owner, "Only owner can drain the contract"); | ||
|
||
// Transfer all funds to the recipient (arbitrary transfer vulnerability) | ||
(bool success, ) = recipient.call{value: address(this).balance}(""); | ||
require(success, "Drain failed"); | ||
} | ||
|
||
// 6. Receive function to accept ETH | ||
receive() external payable {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
contract NonEtherReentrancyContract { | ||
// Uninitialized state variable (high-severity vulnerability) | ||
address public owner; | ||
|
||
mapping(address => uint256) public userPoints; | ||
mapping(address => bool) public rewardedUsers; | ||
|
||
// Initialize owner in the constructor | ||
constructor() { | ||
owner = msg.sender; | ||
} | ||
|
||
// 1. Reentrancy vulnerability: State can be manipulated by reentrant calls | ||
function rewardPoints(address user, uint256 points) public { | ||
require(!rewardedUsers[user], "User already rewarded"); | ||
|
||
// Mark the user as rewarded (vulnerable to reentrancy) | ||
rewardedUsers[user] = true; | ||
|
||
// External call, vulnerable to reentrancy | ||
(bool success, ) = user.call(""); | ||
require(success, "External call failed"); | ||
|
||
// Update user points after external call (reentrancy risk) | ||
userPoints[user] += points; | ||
} | ||
|
||
// 2. Unchecked low-level call vulnerability | ||
function updateOwner(address newOwner) public { | ||
require(msg.sender == owner, "Not the contract owner"); | ||
|
||
// Unchecked low-level call | ||
(bool success, ) = newOwner.call(""); | ||
// No success check — possible state inconsistency | ||
|
||
owner = newOwner; | ||
} | ||
|
||
// 3. Block timestamp used in business logic (manipulatable by miners) | ||
function isGameActive(uint256 startTime, uint256 duration) public view returns (bool) { | ||
// Vulnerable: Uses block.timestamp for critical logic | ||
return block.timestamp >= startTime && block.timestamp <= startTime + duration; | ||
} | ||
|
||
// 4. Arbitrary state manipulation (owner-only action but still vulnerable) | ||
function resetUser(address user) public { | ||
require(msg.sender == owner, "Only owner can reset users"); | ||
|
||
// Vulnerability: Arbitrary state reset without checks | ||
userPoints[user] = 0; | ||
rewardedUsers[user] = false; | ||
} | ||
|
||
// 5. Receive function to accept ETH (no ETH manipulation in vulnerabilities) | ||
receive() external payable {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.20; | ||
|
||
contract SecureToken { | ||
// Events | ||
event Transfer(address indexed from, address indexed to, uint256 value); | ||
event Approval(address indexed owner, address indexed spender, uint256 value); | ||
event Minted(address indexed to, uint256 amount); | ||
event Burned(address indexed from, uint256 amount); | ||
|
||
// State variables | ||
string public name = "SecureToken"; | ||
string public symbol = "SEC"; | ||
uint8 public decimals = 18; | ||
uint256 public totalSupply; | ||
address public owner; | ||
|
||
// Constants | ||
uint256 public constant MAX_SUPPLY = 1000000 * 10**18; // 1 million tokens | ||
uint256 public constant MAX_MINT_PER_TX = 10000 * 10**18; // 10k tokens | ||
|
||
// Reentrancy guard | ||
uint256 private constant _NOT_ENTERED = 1; | ||
uint256 private constant _ENTERED = 2; | ||
uint256 private _status; | ||
|
||
// Mappings | ||
mapping(address => uint256) public balanceOf; | ||
mapping(address => mapping(address => uint256)) public allowance; | ||
|
||
// Modifiers | ||
modifier nonReentrant() { | ||
require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); | ||
_status = _ENTERED; | ||
_; | ||
_status = _NOT_ENTERED; | ||
} | ||
|
||
modifier onlyOwner() { | ||
require(msg.sender == owner, "Not owner"); | ||
_; | ||
} | ||
|
||
// Constructor | ||
constructor() { | ||
owner = msg.sender; | ||
_status = _NOT_ENTERED; | ||
_mint(msg.sender, 100000 * 10**18); // 100k initial supply | ||
} | ||
|
||
// Internal mint function | ||
function _mint(address to, uint256 amount) internal { | ||
require(to != address(0), "Cannot mint to zero address"); | ||
require(totalSupply + amount <= MAX_SUPPLY, "Would exceed max supply"); | ||
|
||
totalSupply += amount; | ||
balanceOf[to] += amount; | ||
emit Transfer(address(0), to, amount); | ||
} | ||
|
||
// Internal burn function | ||
function _burn(address from, uint256 amount) internal { | ||
require(balanceOf[from] >= amount, "Insufficient balance"); | ||
|
||
balanceOf[from] -= amount; | ||
totalSupply -= amount; | ||
emit Transfer(from, address(0), amount); | ||
} | ||
|
||
// External functions | ||
function mint(address to, uint256 amount) | ||
external | ||
onlyOwner | ||
nonReentrant | ||
{ | ||
require(amount > 0, "Amount must be greater than 0"); | ||
require(amount <= MAX_MINT_PER_TX, "Amount exceeds max mint per transaction"); | ||
|
||
_mint(to, amount); | ||
emit Minted(to, amount); | ||
} | ||
|
||
function burn(uint256 amount) | ||
external | ||
nonReentrant | ||
{ | ||
require(amount > 0, "Amount must be greater than 0"); | ||
_burn(msg.sender, amount); | ||
emit Burned(msg.sender, amount); | ||
} | ||
|
||
function transfer(address to, uint256 amount) | ||
public | ||
nonReentrant | ||
returns (bool) | ||
{ | ||
require(to != address(0), "Cannot transfer to zero address"); | ||
require(amount > 0, "Amount must be greater than 0"); | ||
require(balanceOf[msg.sender] >= amount, "Insufficient balance"); | ||
|
||
balanceOf[msg.sender] -= amount; | ||
balanceOf[to] += amount; | ||
emit Transfer(msg.sender, to, amount); | ||
return true; | ||
} | ||
|
||
function approve(address spender, uint256 amount) | ||
public | ||
returns (bool) | ||
{ | ||
require(spender != address(0), "Cannot approve zero address"); | ||
allowance[msg.sender][spender] = amount; | ||
emit Approval(msg.sender, spender, amount); | ||
return true; | ||
} | ||
|
||
function transferFrom(address from, address to, uint256 amount) | ||
public | ||
nonReentrant | ||
returns (bool) | ||
{ | ||
require(from != address(0), "Cannot transfer from zero address"); | ||
require(to != address(0), "Cannot transfer to zero address"); | ||
require(amount > 0, "Amount must be greater than 0"); | ||
require(balanceOf[from] >= amount, "Insufficient balance"); | ||
require(allowance[from][msg.sender] >= amount, "Insufficient allowance"); | ||
|
||
allowance[from][msg.sender] -= amount; | ||
balanceOf[from] -= amount; | ||
balanceOf[to] += amount; | ||
emit Transfer(from, to, amount); | ||
return true; | ||
} | ||
} |
Oops, something went wrong.