I revisited my first Solidity contract and found a simple access control bug — and learned why Solidity's address(0) default behavior mattered to the fix.
I found an access control bug hiding in plain sight.
SimpleStorage lets users save data by ID. Here's the version I originally wrote:
function AddData(uint256 _ItemID, string memory _StringData) public {
DataIdToData[_ItemID] = EntryData(_StringData, msg.sender);
}
At a glance, it looks harmless.
It isn't.
There was no check for who already owned _ItemID.
That meant anyone could call AddData() with an ID that belonged to someone else and overwrite their entry.
The caller would then become the new owner.
No error.
No revert.
No access control.
Just a successful transaction.
The fix
The fix was a simple ownership check:
require(
DataIdToData[_ItemID].Owner == msg.sender ||
DataIdToData[_ItemID].Owner == address(0),
"this ID is assigned to someone else!"
);
Now a write is only allowed when:
- The caller already owns the ID, or
- The ID hasn't been claimed yet.
The second condition is where something I previously found confusing in Solidity suddenly became useful.
address(0) isn't just a default
An address field that hasn't been explicitly initialized returns Solidity's zero address:
address(0)
So an untouched entry can effectively act as:
Owner = address(0)
↓
Nobody owns this ID yet
And that gives the contract a simple way to distinguish an unclaimed ID from an owned one.
A few days ago, I wrote about how confusing Solidity's default storage values were when I was first learning.
Now I'm using that exact behavior to implement an ownership check.
That's probably the part I find most interesting about learning Solidity:
The thing that confused me as a beginner can eventually become part of the security model.
I'm still early in this.
But I'm starting to find the gaps in my own contracts before someone else has to point them out.
Top comments (0)