Secret Vault on Aptos

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

H02. Account resources are readable on Aptos

Root + Impact

Description

Normal behavior:
The module secret_vault::vault stores a Vault resource under the caller’s account when set_secret(&signer, secret: vector<u8>) is called. The Vault struct contains a String secret field. The get_secret view function was intended to control who can read this secret.

Specific issue:
On Aptos, all on-chain resources are publicly readable using standard node APIs or CLI commands such as aptos account list --account <address>. This means that anyone can directly query the Vault resource of an account and read the secret field in plaintext — completely bypassing get_secret and its intended access control.

// Root cause in the codebase with @> marks to highlight the relevant section
module secret_vault::vault {
struct Vault has key {
// @> Stored directly in account resource
// @> Publicly visible via any node or explorer
secret: String
}
public entry fun set_secret(caller: &signer, secret: vector<u8>) {
let secret_vault = Vault { secret: string::utf8(secret) };
move_to(caller, secret_vault); // @> Creates public resource on-chain
}
#[view]
public fun get_secret(caller: address): String acquires Vault {
// @> Intended to restrict access
let vault = borrow_global<Vault>(caller);
vault.secret
}
}

Risk

Likelihood: Certain

  • Any user can run aptos account list --account <target> and retrieve all resources, including Vault.

  • This is a guaranteed behavior of the Aptos blockchain; all resources are globally readable by design.

Impact: Severe

  • The secret is exposed to anyone without needing to call get_secret.

  • The module’s intended access control is ineffective — private data is irreversibly public.

  • Any sensitive information (passwords, keys, personal data) stored in the vault is compromised immediately.

Proof of Concept

Here the command line to set a secret and then query the explorer to retrieve it

// 1) Victim sets a secret, here password
aptos move run --function-id <program address>::vault::set_secret --args string:passowrd
// 2) Attacker queries victim's account resources
aptos account list --account <victim_address>
// 3) Output reveals the stored secret directly:
{
"Result": [
{
"<program_address>::vault::Vault": {
"secret": "password"
}
}
]
}
// No call to get_secret() was needed.
// The "secret" is fully exposed as part of the account's resource state.


Reference: https://aptos.dev/build/cli/trying-things-on-chain/looking-up-account-info\



Recommended Mitigation

- struct Vault has key { secret: String }
- public entry fun set_secret(caller: &signer, secret: vector<u8>) {
- let secret_vault = Vault { secret: string::utf8(secret) };
- move_to(caller, secret_vault);
- }
+ /// Do not store plaintext secrets on-chain. All Move resources are public by design.
+ /// Option A: store only a cryptographic commitment (hash).
+ struct Vault has key { secret_hash: vector<u8> }
+ public entry fun set_secret_commitment(caller: &signer, secret_hash: vector<u8>) {
+ let vault = Vault { secret_hash };
+ move_to(caller, vault);
+ }
+
+ /// Option B: store ciphertext generated off-chain with the owner's key.
+ struct EncVault has key { ciphertext: vector<u8> }
+ public entry fun set_secret_ciphertext(caller: &signer, ciphertext: vector<u8>) {
+ let vault = EncVault { ciphertext };
+ move_to(caller, vault);
+ }
+
+ /// Additional recommendations:
+ /// - Avoid implying confidentiality in on-chain data structures.
+ /// - If true secrecy is required, keep the data off-chain entirely.

Design guidance:

  • On Aptos (and most blockchains), anyone can read any resource; Move’s type system does not provide data confidentiality.

  • Store only non-reversible commitments (hashes, salted hashes) or encrypted data prepared off-chain.

  • If privacy is critical, keep sensitive material off-chain and use the blockchain only as a verifier or reference.

Updates

Lead Judging Commences

bube Lead Judge 16 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.