Secret Vault on Aptos

First Flight #46
Beginner FriendlyWallet
100 EXP
View results
Submission Details
Severity: high
Valid

Global Resource Exposure Leading to Confidential Data Leakage

Root + Impact

Sensitive data is stored in plaintext within Move’s global storage, making it publicly accessible despite function-level access control. This violates confidentiality principles and exposes secrets to unauthorized actors.

Description

  • In Move, resources stored using move_to are placed in global storage under the caller’s account. This allows any external observer to query the blockchain and inspect the stored data.

  • The module stores a secret string using move_to(caller, secret_vault);, but this secret is not encrypted. Although access to the get_secret function is restricted, the actual data remains readable via standard tooling, violating data confidentiality.

// Root cause in the codebase with @> marks to highlight the relevant section
public entry fun set_secret(caller: &signer, secret: vector<u8>) {
let secret_vault = Vault { secret: string::utf8(secret)};
@> move_to(caller, secret_vault); // Secret stored in plaintext under caller's account
}

Risk

Likelihood:

  • Any actor with access to a full node, indexer, or blockchain explorer can query global storage at any time.

  • The Move language does not provide native encryption or obfuscation for stored resources, making plaintext data trivially accessible.

Impact:

  • Secrets or private messages can be harvested by adversaries.

  • No authentication or authorization is required to access this data.

  • The get_secret function enforces access control, but it is irrelevant because the data is already exposed in global storage.

  • This violates OWASP A02:2021 – Cryptographic Failures and SWC-136 – Unencrypted Secrets, as sensitive data is stored without any form of encryption or obfuscation.

Proof of Concept

Below shown output is accessible without invoking get_secret, bypassing all access control logic with mentoned query.

aptos view-resource --address 0xcc --resource-type secret_vault::vault::Vault
Output
{
"secret": "i'm a secret"
}

Recommended Mitigation

  • Encrypt Secret off-chain and store it on chain

  • Use a Commit-Reveal Scheme,as shown in below code snippet

- move_to(caller, Vault { secret: string::utf8(secret) });
+ let commitment = hash::sha3_256(secret); // or blake2b, keccak256
+ move_to(caller, Vault { secret: string::utf8(commitment) });
Updates

Lead Judging Commences

bube Lead Judge 17 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Anyone can see the `secret` on chain

Support

FAQs

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