Root
The flow in the set_secret
prevent any update on the secret
.
Impact
Secret can only be set Once, meaning that new contract need to be deployed in scenario of wanting to have a different Secret.
Description
The contract main feature for Owner
is to have its' Secret. However, the logic in the set_secret
only allow Owner
to set the secret once with no option to update it, making the need of a new smart contract to be deployed in order to having a different Secret value.
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:
Impact:
Proof of Concept
Add this code to secret_vault.move
#[test(owner = @0xcc)]
fun test_inputing_secret(owner: &signer) {
use aptos_framework::account;
account::create_account_for_test(signer::address_of(owner));
let secret_1 = b"First Secret";
let secret_2 = b"Second Secret";
set_secret(owner, secret_1);
set_secret(owner, secret_2);
}
Running the test will have this result
$ aptos move test 1 ↵
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING aptos-secret-vault
Running Move unit tests
[ FAIL ] 0x234::vault::test_inputing_secret
Test failures:
Failures in 0x234::vault:
┌── test_inputing_secret ──────
│ error[E11001]: test failure
│ ┌─ /Users/sanada/Documents/blockchain/2025-07-secret-vault/sources/secret_vault.move:188:5
│ │
│ 184 │ public entry fun set_secret(caller:&signer,secret:vector<u8>){
│ │ ---------- In this function in 0x234::vault
│ ·
│ 188 │ move_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 00000000000000000000000000000000000000000000000000000000000000cc". Error originating in the module 0000000000000000000000000000000000000000000000000000000000000234::vault rooted here
│
│
│ stack trace
│ vault::test_inputing_secret(/Users/sanada/Documents/blockchain/2025-07-secret-vault/sources/secret_vault.move:239)
│
└──────────────────
Test result: FAILED. Total tests: 1; passed: 0; failed: 1
{
"Error": "Move unit tests failed"
}
Recommended Mitigation
asdasd
To enhance the contract and preventing unecessary cost of deploying another contract, upsert (update + insert) can be implemented for the set_secret
function.
public entry fun set_secret(caller:&signer,secret:vector<u8>) acquires Vault{
- let secret_vault = Vault{secret: string::utf8(secret)};
- move_to(caller,secret_vault);
+ let addr = signer::address_of(caller);
+ // If vault exist
+ if (exists<Vault>(addr)) {
+ // Update existing Vault
+ let vault = borrow_global_mut<Vault>(addr);
+ vault.secret = string::utf8(secret);
+ } else { // If vault not exist, create one
+ // Create a new Vault
+ let vault = Vault { secret: string::utf8(secret) };
+ move_to(caller, vault);
+ };
event::emit(SetNewSecret {});
}
Below is the test created to check whether we can continuously update the Secret
#[test(owner = @0xcc)]
fun test_inputing_secret_after_patching(owner: &signer) acquires Vault {
use aptos_framework::account;
account::create_account_for_test(signer::address_of(owner));
let secret_1 = b"First Secret";
set_secret(owner, secret_1);
let secret_1_set = get_secret(signer::address_of(owner));
debug::print(&secret_1_set);
let secret_2 = b"Second Secret";
set_secret(owner, secret_2);
let secret_2_set = get_secret(signer::address_of(owner));
debug::print(&secret_2_set);
let secret_3 = b"Last Secret";
set_secret(owner, secret_3);
let secret_3_set = get_secret(signer::address_of(owner));
debug::print(&secret_3_set);
}
Running the test above will give the result below
$ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING aptos-secret-vault
Running Move unit tests
[debug] "First Secret"
[debug] "Second Secret"
[debug] "Last Secret"
[ PASS ] 0x234::vault::test_inputing_secret_after_patching
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
"Result": "Success"
}