<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged cyfrin</title>
<link>https://coderlegion.com/tag/cyfrin</link>
<description>Powered by Question2Answer</description>
<item>
<title>How To Audit A Smart Contract</title>
<link>https://coderlegion.com/14218/how-to-audit-a-smart-contract</link>
<description>&lt;p&gt;I was going through the &lt;a rel=&quot;nofollow&quot; href=&quot;https://updraft.cyfrin.io/courses/security&quot;&gt;Updraft Smart Contract Security course&lt;/a&gt;, and I realized I had been doing some things the wrong way.&lt;br&gt;
Here are a couple of things I started doing differently.&lt;/p&gt;
&lt;p&gt;I am basing this article on the &lt;code&gt;PasswordStore&lt;/code&gt; repo here: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Cyfrin/3-passwordstore-audit&quot;&gt;3-passwordstore-audit&lt;/a&gt;.&lt;br&gt;
Definitely check it out. It is only about 20 lines of contract code, and that is where &lt;code&gt;nSLOC/CLOC&lt;/code&gt; comes in. It tells you how much actual code is in the codebase.&lt;/p&gt;
&lt;h3 id=&quot;step-1-trace-trust-boundaries&quot;&gt;Step 1: Trace Trust Boundaries&lt;/h3&gt;
&lt;p&gt;Ask these questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Who can &lt;strong&gt;write&lt;/strong&gt; the value?&lt;/li&gt;
&lt;li&gt;Who can &lt;strong&gt;read&lt;/strong&gt; the value?&lt;/li&gt;
&lt;li&gt;What does the constructor assume?&lt;/li&gt;
&lt;li&gt;What does the contract pretend is hidden?&lt;/li&gt;
&lt;li&gt;What breaks if the value is public?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Cyfrin/3-passwordstore-audit/blob/main/src/PasswordStore.sol&quot;&gt;PasswordStore.sol&lt;/a&gt;, the owner is set in the constructor, and the setter check &lt;code&gt;msg.sender&lt;/code&gt;.&lt;br&gt;
That gives the shape of the access control.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function setPassword(string memory newPassword) external {
    if (msg.sender != s_owner) {
        revert PasswordStore__NotOwner();
    }
    s_password = newPassword;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The guard is there. The function is protected. So far so good.&lt;/p&gt;
&lt;h3 id=&quot;step-2-what-the-repo-shows&quot;&gt;Step 2: What the repo shows&lt;/h3&gt;
&lt;p&gt;The repo points to two separate issues:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Issue 1: Missing access control&lt;/strong&gt; on &lt;code&gt;getPassword&lt;/code&gt;.&lt;br&gt;
The getter has no &lt;code&gt;msg.sender&lt;/code&gt; check, so anyone can call it and retrieve the password directly through the ABI.&lt;br&gt;
&lt;strong&gt;Issue 2: The password is exposed&lt;/strong&gt; in storage regardless.&lt;br&gt;
 Here is why.&lt;/p&gt;
&lt;p&gt;Every state variable in a Solidity contract occupies a storage slot. &lt;code&gt;s_password&lt;/code&gt; sits at slot 1. The &lt;code&gt;private&lt;/code&gt; keyword only prevents other contracts from reading it through the ABI. It does nothing to stop an off-chain read.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;# the 'private' variable
string private s_password;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can retrieve the saved password with a single Foundry cast command:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;cast parse-bytes32-string $(cast storage  &amp;lt;CONTRACT_ADDRESS&amp;gt; 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We fetched the raw bytes at storage slot 1 and decoded it to get the plaintext password.&lt;br&gt;
This is not a bug in Solidity. It is how blockchains work. Every transaction, every storage write, is public by design. Marking a variable private is a visibility modifier for the compiler, not a confidentiality guarantee for your users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The lesson:&lt;/strong&gt; you can protect a function and still leak the data. Access control and data confidentiality are two different problems that need two different solutions.&lt;/p&gt;
&lt;h3 id=&quot;step-3-simple-audit-flow&quot;&gt;Step 3: Simple audit flow&lt;/h3&gt;
&lt;p&gt;Small contracts are not easier to audit, they are easier to audit shallowly. For any contract under 100 nSLOC, I now run four checks before calling it done:&lt;br&gt;
&lt;strong&gt;1. Read the code and map the intended trust boundary.&lt;/strong&gt;&lt;br&gt;
What is the contract supposed to do, and who is supposed to be able to do it? Write it down in plain English before touching the code.&lt;br&gt;
&lt;strong&gt;2. Check who can actually call each function.&lt;/strong&gt;&lt;br&gt;
Does every sensitive function have a guard? Does that guard cover all entry points, including any inherited or fallback functions?&lt;br&gt;
&lt;strong&gt;3. Check whether storage or calldata exposes the value anyway.&lt;/strong&gt;&lt;br&gt;
A &lt;code&gt;private&lt;/code&gt; variable is not private on-chain. Ask: if someone ran &lt;code&gt;cast storage&lt;/code&gt; against every slot, what would they find? Think about variables that leak information they are not supposed to.&lt;br&gt;
&lt;strong&gt;4. Write a test for the failure mode.&lt;/strong&gt;&lt;br&gt;
For the storage issue, a simple Foundry test proves it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-solidity&quot;&gt;function test_anyone_can_read_password() public {
    vm.startPrank(owner);
    passwordStore.setPassword(&quot;supersecret&quot;);
    vm.stopPrank();

    // Read slot 1 directly, bypassing the getter entirely
    bytes32 storedPassword = vm.load(
        address(passwordStore),
        bytes32(uint256(1))
    );

    assertEq(
        string(abi.encodePacked(storedPassword)),
        &quot;supersecret&quot;
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If the test passes, the contract has a confidentiality problem regardless of what the getter says.&lt;/p&gt;
&lt;h3 id=&quot;takeaway&quot;&gt;Takeaway&lt;/h3&gt;
&lt;p&gt;Contracts with few functions should not trick you into shallow reviews.&lt;/p&gt;
&lt;p&gt;The real question is not, “Does the function have a guard?”&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;“Does the contract actually meet the expected business logic and keep the data safe?”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How would you write this contract differently?&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/14218/how-to-audit-a-smart-contract</guid>
<pubDate>Wed, 08 Apr 2026 08:57:34 +0000</pubDate>
</item>
</channel>
</rss>