Default Visibility Exploit Generator
Sigvex exploit generator that validates default visibility vulnerabilities in Solidity contracts where missing visibility modifiers default to public, exposing sensitive initialization and admin functions.
Default Visibility Exploit Generator
Overview
The default visibility exploit generator validates findings from the default_visibility, visibility_missing, and related detectors by classifying the type of exposed function from the finding description and producing a targeted proof of concept. This vulnerability is specific to Solidity contracts compiled with versions before 0.5.0, where omitting a visibility modifier caused functions to default to public.
Two canonical historical exploits demonstrate the impact. Rubixi (2016): A contract was renamed from DynamicPyramid to Rubixi but the constructor function name was not updated, causing the old DynamicPyramid() function to become a regular public function (Solidity 0.4.x used function-name constructors). Attackers called it to claim ownership. The Parity Wallet hack also involved an initialization function (initWallet) that was publicly accessible due to insufficient visibility controls.
Note: Exploit generation in Sigvex is for vulnerability validation purposes only.
Attack Scenario
Public initialization function:
- A contract has
function initOwner(address _owner)without a visibility modifier. - In Solidity 0.4.x, this defaults to
public. Attackers can call it at any time. - The attacker calls
initOwner(attackerAddress)after deployment. - Owner is now the attacker. All
onlyOwnerfunctions are accessible to the attacker. - The attacker calls
withdraw()to drain all contract ETH.
Public destructor:
- A contract has
function kill()without visibility, defaulting topublic. - Any address can call
kill(), triggeringselfdestruct(owner). - The contract is permanently destroyed and its bytecode erased.
Public admin functions:
- Internal helper functions (
resetOwner(),updateThreshold()) lack visibility. - Attackers call them directly to modify critical state variables.
- Combined with ownership reset and threshold manipulation, full fund extraction follows.
Exploit Mechanics
The generator classifies the vulnerability type from the finding description:
| Description contains | Vulnerability type | Severity |
|---|---|---|
| ”constructor”, “init”, “setup” | public_initialization | Critical: anyone can become owner |
| ”owner”, “admin” | public_admin_function | High: unauthorized admin access |
| ”destroy”, “kill” | public_destructor | Critical: anyone can destroy contract |
| (other) | unspecified_visibility | Medium: unintended exposure |
Evidence collected includes: original owner address, attacker address, contract balance, and vulnerability type. Estimated gas: 40,000.
The PoC covers four vulnerability patterns using Solidity 0.4.24 syntax:
// VULNERABLE (Solidity 0.4.x): No visibility — defaults to PUBLIC
contract VulnerableInit {
address owner;
function initOwner(address _owner) { // Public by default!
owner = _owner;
}
}
// EXPLOIT
contract InitExploit {
function attack(VulnerableInit target) public {
target.initOwner(address(this)); // Become owner
target.withdraw(); // Drain funds
}
}
Remediation
- Detector: Default Visibility Detector
- Remediation Guide: Default Visibility Remediation
The simplest fix is to upgrade to Solidity 0.5.0 or later, which requires explicit visibility on all functions at compile time:
// Solidity 0.5.0+: Compiler requires explicit visibility
// This fails to compile without a modifier:
// function initOwner(address _owner) { ... } // Error!
// Correct: Use internal for setup-only functions
function _initOwner(address _owner) internal { ... }
// Correct: Use private for helpers
function _computeReward() private returns (uint256) { ... }
// Correct: Use external for public API
function withdraw() external onlyOwner { ... }
For contracts that cannot be recompiled, deploy a new contract with corrected visibility. For upgradeable proxies, update the implementation to Solidity 0.5.0+.
Naming conventions help prevent accidental exposure: prefix _internal or __private functions accordingly, and use static analysis tools (Slither, Solhint) that flag missing visibility.
References
- SWC-100: Function Default Visibility
- SWC-118: Incorrect Constructor Name
- Solidity 0.5.0 Breaking Changes
- Rubixi Contract Exploit (2016)