Secret Vault on Aptos

First Flight #46
Beginner FriendlyWallet
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Silent Overwrite of Vault Resource

Root + Impact

Description

  • TThe set_secret function stores a user-provided secret string inside a Vault resource under the caller's account.

  • It is replacing any existing vault without warning. It then emits a SetNewSecret event, but doesn't include any event data or check for overwrites, risking silent data loss.

public entry fun set_secret(caller: &signer, secret: vector<u8>) {
let secret_vault = Vault{ secret: string::utf8(secret) };
@> move_to(caller, secret_vault);
event::emit(SetNewSecret {});
}

Risk

Likelihood:

  • There is no overwrite protection so user might call it multiple times overwriting the data.

Impact:

  • Users may accidentally overwrite their own secret (e.g., by re-calling set_secret() with incorrect or blank data).

Proof of Concept

Add the following test. This test will:

  1. Set an initial secret.

  2. Set a second (different) secret.

  3. Assert that the first secret is gone and the second one has silently replaced it — proving the vulnerability.

#[test(user = @0xabc)]
fun test_secret_overwrite(user: &signer) acquires Vault {
use aptos_framework::account;
use std::string;
// Setup victim's account
account::create_account_for_test(signer::address_of(user));
// First secret
let first_secret = b"my original secret";
set_secret(user, first_secret);
// Overwrite with a second secret
let second_secret = b"overwritten secret";
set_secret(victim, second_secret); // This silently replaces the first one
// Read back the Vault
let addr = signer::address_of(victim);
let vault = borrow_global<Vault>(addr);
// Assert the first secret is gone
assert!(vault.secret != string::utf8(first_secret), 100);
// Assert the second secret is now stored
assert!(vault.secret == string::utf8(second_secret), 101);
debug::print(&b"Overwrite vulnerability confirmed");
}

Recommended Mitigation

Added new error code and added a check for overwriting by checking if vault already exist

+ const EALREADY_EXISTS: u64 = 2;
public entry fun set_secret(caller:&signer,secret:vector<u8>){
+ let addr = signer::address_of(caller);
+ assert!(!exists<Vault>(addr), EALREADY_EXISTS);
let secret_vault = Vault{secret: string::utf8(secret)};
move_to(caller,secret_vault);
event::emit(SetNewSecret {});
}
Updates

Lead Judging Commences

bube Lead Judge 19 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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