Solidity Smart Contract Audit · Static & Dynamic Analysis · Proof-of-Concept Exploitation
[CLIENT] engaged Red Team Security SRL to perform a comprehensive security assessment of three Solidity smart contracts. No deployment restrictions were given — none of the contracts had been released to any mainnet or testnet at the time of assessment, which allowed unconstrained testing.
Each finding in this report includes:
The assessment combined multiple automated analysis tools with manual code review. Manual review was essential because smart contract security is a niche discipline and no single tool covers the full vulnerability space. Both static and dynamic analysis techniques were applied across all three contracts.
Multiple vulnerabilities were identified across all three contracts, ranging in severity from Informational to Critical. The contract implementations do not meet acceptable security standards in their current state. Deployment to production is strongly advised against until all Critical and High findings are remediated.
| ID | Severity | Category (CWE) | Description | Count |
|---|---|---|---|---|
| SC-01 | Critical | CWE-284 | Unprotected self-destruct function allows any caller to destroy the contract and drain all funds. | 1 |
| SC-02 | Critical | CWE-841 | Reentrancy vulnerability allows an attacker to drain the contract balance via recursive calls before state is updated. | 1 |
| SC-03 | Critical | CWE-682 | Integer underflow in an unchecked arithmetic block enables balance manipulation leading to fund theft. | 1 |
| SC-04 | High | CWE-285 | The onlyOwner modifier is incorrectly implemented, effectively making authorization checks bypassable. | 1 |
| SC-05 | High | CWE-284 | The withdrawal function has no access control, allowing any address to impersonate a user and drain their balance. | 1 |
| SC-06 | Medium | CWE-1164 | Dead code — contract contains functions that produce no side effects and will never execute as intended. | 1 |
| SC-07 | Medium | CWE-912 | A hidden transfer function allows the contract owner to retrieve all user funds at will. | 1 |
| SC-08 | Low | CWE-829 | Block timestamps used for time-critical logic are manipulable by miners within a ~30s window. | 1 |
| SC-09 | Low | CWE-682 | Division before multiplication causes precision loss in the interest calculation formula. | 1 |
| SC-10–11 | Low | CWE-664 | Floating pragma allows contracts to be compiled with compiler versions that may have known bugs. | 2 |
| SC-12–13 | Info | CWE-710 | State variable visibility not explicitly set; recommended to always declare access modifiers explicitly. | 2 |
| SC-14 | Info | CWE-1164 | Unused variables declared in contract scope — should be removed to reduce attack surface and gas cost. | 1 |
| SC-15 | Info | CWE-1006 | Use of multiple digits in function parameters is not a recognized Solidity coding standard. | 1 |
The methodology relied primarily on the Smart Contract Weakness Classification (SWC) database, which provided a structured taxonomy of known vulnerability patterns and associated test cases. Both automated tooling and manual review were applied.
Automated tools used during this assessment:
Severity definitions used in this report:
Due to missing or insufficient access controls, any external caller can invoke the EmergencyDestroy function. This triggers selfdestruct, which permanently removes the contract from the blockchain and forwards its entire balance to an attacker-supplied address — causing immediate and unrecoverable fund loss.
Deployed MyToken.sol to a local Ganache instance. Called EmergencyDestroy from a non-owner account with an attacker-controlled address as the argument. The contract was successfully destroyed and the entire balance was transferred to the attacker address. The transaction completed without reverting, confirming the vulnerability.
If the self-destruct capability is not required, remove it entirely. If it must exist, restrict access with the onlyOwner modifier and consider a multi-signature approval scheme to prevent any single party from triggering it unilaterally.
When an external contract is called, the owner of the remote contract can take control over the calling contract's execution flow. Using a recursive call technique, an attacker can re-enter the getRefund function before the first call finishes updating the internal state variable tracking purchased tickets — allowing the attacker to receive refunds far exceeding their actual balance.
ReentrancyGuard modifier to block recursive calls at the contract levelThe contract performs arithmetic subtraction inside an unchecked block. When the reentrancy attack (SC-02) causes the quantity argument to exceed the user's actual purchasedTicket balance, the subtraction underflows and wraps around to a very large number — granting the attacker an enormous virtual balance.
Fix the reentrancy issue in SC-02 first, as that is the root cause. Additionally, replace the unchecked block with vetted safe math libraries for all arithmetic that could overflow or underflow. In Solidity 0.8.x, arithmetic is checked by default — do not wrap balance-affecting operations in unchecked blocks.
The onlyOwner modifier contains a logic error — it checks whether the caller is not the owner and emits an event, but it does not revert the transaction or prevent execution. As a result, the modifier provides no actual access control: any caller can invoke functions protected by it.
Replace the event emission with a require or revert statement. Consider using OpenZeppelin's battle-tested Ownable contract rather than implementing custom access control.