Secret Vault on Aptos

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

User is not able to update secret after initial set

Summary

Once a user sets their vault secret, they are unable to update or reset it. Any subsequent call to set_secret results in a RESOURCE_ALREADY_EXISTS (code 4004) error, preventing the user from changing their secret and leaving no opportunity to update it if the secret has been compromised.

Description

User is unable to reset the vault secret. Calling the set_secret again to set a new secret will result RESOURCE_ALREADY_EXISTS (code 4004) error, causing the user has no second chance to set another new secret for their vault.

public entry fun set_secret(caller:&signer,secret:vector<u8>){
// there's no check if vault secret exits, every call to this function only does an initial set for the vault secret !
<@@>! let secret_vault = Vault{secret: string::utf8(secret)};
move_to(caller,secret_vault);
event::emit(SetNewSecret {});
}

Risk

Likelihood:

  • This occurs every time a user who has already set a vault secret calls the set_secret function in an attempt to update or reset their secret.

Impact:

  • Users are permanently unable to change or update their vault secret once it is set. If the secret is ever compromised, the user has no recovery path, potentially exposing them to long-term security risks.

Proof of Concept

Add the following test in secret_vault.move:

#[test(owner = @0xcc)]
fun test_owner_unable_to_update_secret(owner: &signer) acquires Vault{
use aptos_framework::account;
// Set up owner test environment
account::create_account_for_test(signer::address_of(owner));
// Owner sets vault secret
let secret = b"chocolate";
set_secret(owner, secret);
// Owner wants to change another secret
let new_secret = b"muffin";
set_secret(owner, new_secret);
// trying to check if owner's new secret is updated
let owner_add = signer::address_of(owner);
let owner_vault = borrow_global<Vault>(owner_add);
assert!(owner_vault.secret == string::utf8(new_secret), 2);
}}

In terminal run aptos move test -f test_owner_unable_to_update_secret :

$ aptos move test -f test_owner_unable_to_update_secret [17:51:55]
...
Running Move unit tests
[ FAIL ] 0x234::vault::test_owner_unable_to_update_secret
Test failures:
Failures in 0x234::vault:
┌── test_owner_unable_to_update_secret ──────
│ error[E11001]: test failure
│ ┌─ /Users/soupy/Documents/codehawks/first-flight/2025-07-secret-vault/sources/secret_vault.move:25:6
│ │
22 │ public entry fun set_secret(caller:&signer,secret:vector<u8>){
│ │ ---------- In this function in 0x234::vault
│ ·
25move_to(caller,secret_vault);
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Test was not expected to error, but it gave a RESOURCE_ALREADY_EXISTS (code 4004) error with error message: "Failed to move resource into 0000000000000000000000000000000000000000000000000000000000000123". Error originating in the module 0000000000000000000000000000000000000000000000000000000000000234::vault rooted here
│ stack trace
│ vault::test_owner_unable_to_update_secret(/Users/soupy/Documents/codehawks/first-flight/2025-07-secret-vault/sources/secret_vault.move:53)
└──────────────────
Test result: FAILED. Total tests: 1; passed: 0; failed: 1
{
"Error": "Move unit tests failed"
}
FAIL

The test failed indicating that the owner can't update their secret via set_secret function after the initial set.

Recommended Mitigation

To amend the set_secret function so it can cater for the user's need to update secret if they need to

public entry fun set_secret(caller:&signer,secret:vector<u8>) acquires Vault{
// ensure caller is authorized owner to set secret
let caller_add = signer::address_of(caller);
assert!(caller_add == @owner, NOT_OWNER);
// enable reset/update of secret if it has been setup earlier
// prerequisite: to update data type of vault.secret from String to vector<u8>
if (exists<Vault>(caller_add)) {
let vault = borrow_global_mut<Vault>(caller_add);
vault.secret = secret;
} else {
move_to(caller, Vault{secret: secret});
};
// make amendment also to event `SetNewSecret` to include data field `account`
event::emit(SetNewSecret{account: caller_add});
}
Updates

Lead Judging Commences

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

The `secret` can not be updated

Support

FAQs

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