Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Exposure of 'Private' Data: Confidential Passwords Readable from Contract Storage

Summary

During the audit of the "PasswordStore" smart contract, a significant design flaw was identified. The contract is intended to provide a mechanism for storing a private password securely, visible only to the owner of the contract. However, due to the transparency and immutable nature of blockchain technology, the s_password variable, despite being marked as private, is not hidden from the public. Anyone with access to the blockchain can read this data using various methods, rendering the primary functionality of this contract ineffective.

Vulnerability Details

The vulnerability stems from a misunderstanding of the data privacy model on a blockchain. In Ethereum and similar blockchains, all data stored is visible to all participants in the network. The keyword private in Solidity only prevents other contracts from reading this data directly through internal transactions; it doesn't make the data invisible to blockchain participants.

The s_password variable in the contract is declared as private, meaning it's not directly accessible from outside the contract. However, once a transaction is made, the data being written to s_password is stored on the blockchain and can be seen by analyzing the transaction details or the contract’s state.

POC

add this code to: PasswordStore.t.sol

function testGetStore() public {
// Start a prank (simulated transaction) with the owner's address.
// This simulates actions as if they are performed by the owner.
vm.startPrank(owner);
// Define the password that we expect to set.
string memory expectedPassword = "myNewPassword";
// Call the setPassword function of the passwordStore contract instance,
// setting the password to the value of expectedPassword.
passwordStore.setPassword(expectedPassword);
// Stop the current prank (simulated transaction).
// This concludes the transaction started by the owner.
vm.stopPrank();
// Start a new prank as a different address (address(1) in this case).
// This simulates actions from an address that is not the owner.
vm.startPrank(address(1));
// Directly read the data stored in the passwordStore contract's storage.
// The 'load' function retrieves the data at a specific storage slot.
// Here, '1' refers to the storage slot index (the second slot, as it's 0-indexed)
// which is expected to hold the password, based on the contract's storage layout.
bytes32 data = vm.load(address(passwordStore), bytes32(uint256(1)));
// Convert the bytes32 data to a string.
// The data read from the storage is in bytes32 format, and we use abi.encodePacked
// to convert it into a dynamic bytes array, which is then cast to a string.
string memory converted = string(abi.encodePacked(data));
// Stop the prank started by address(1).
vm.stopPrank();
// Log a message to the console for context.
console.logString("Secret password:");
// Log the "secret" password retrieved directly from contract storage.
// This demonstrates that the password, although meant to be private,
// can be read directly from storage by anyone, underscoring the transparency
// of data on the blockchain.
console.logString(converted);
}

Impact

The impact of this vulnerability is critical. The contract's main purpose is to safeguard a piece of sensitive information, the password, and ensure its visibility only to the owner. However, due to the transparent nature of data stored on the blockchain, the sensitive data the contract aims to protect is exposed to anyone who can read the blockchain. This completely nullifies the confidentiality aspect of the contract, as the password isn't private at all.

Tools Used

The audit was conducted manually by analyzing the Solidity contract code and understanding the blockchain's data transparency principles. No automated tools were required or used to identify this issue, as it's a fundamental design flaw rather than a coding error.

Recommendations

Given the immutable and transparent nature of data stored on the blockchain, we recommend the following:

  1. Avoid Storing Sensitive Data: Never store plain-text sensitive information on the blockchain, considering its public visibility. Passwords, personal user information, and private keys should not be stored on-chain.

  2. Use Encryption: If you must store sensitive data on the blockchain, ensure it is securely encrypted off-chain. The owner can then store the encrypted data on-chain. However, the decryption key should be kept private and off-chain, ensuring data is readable only by parties possessing the key.

  3. Off-Chain Storage: Consider off-chain solutions for data that must remain confidential. Use blockchain for proof of integrity and other non-sensitive data aspects.

  4. Access Control Updates: While it doesn't solve the data visibility issue, ensuring proper access control (like fixing the earlier noted issue in setPassword) is crucial. Only authorized addresses should interact with the functions modifying important contract states.

  5. Educate and Inform: Stakeholders, both developers, and users should be informed about the data privacy model in blockchain and the risks associated with storing sensitive data on-chain.

  6. Contract Update: Since blockchain contracts are immutable once deployed, consider creating and migrating to a new contract that addresses these concerns. The current contract's design fundamentally conflicts with the principles of data privacy on the blockchain.

Updates

Lead Judging Commences

inallhonesty Lead Judge
almost 2 years ago
inallhonesty Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-anyone-can-read-storage

Private functions and state variables are only visible for the contract they are defined in and not in derived contracts. In this case private doesn't mean secret/confidential

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.