Secret Vault on Aptos

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

Anyone can create a secret vault

Anyone can store the secret in vault

Description

The Vault module is intended to store a secret string that should be controlled only by the owner account defined during deployment by @owner. However, the set_secret entry function allows any signer to create a Vault resource under their own address without any ownership check.

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: High

Any user with a valid signer can call set_secret to publish a new Vault resource with the provided secret under their account.

Impact: High

It breaks the key invariant of the protocol in which only the owner should be able to write/read the secret

Proof of Concept

#[test(owner = @0xcc, user = @0x123)]
fun test_random_user_can_create_vault(owner: &signer, user: &signer) acquires Vault {
use aptos_framework::account;
// Set up test environment
account::create_account_for_test(signer::address_of(owner));
account::create_account_for_test(signer::address_of(user));
// Create a secret for the owner
let secret1 = b"i'm a secret";
set_secret(owner, secret1);
// Verify the owner secret
let owner_address = signer::address_of(owner);
let valut = borrow_global<Vault>(owner_address);
assert!(valut.secret == string::utf8(secret1), 4);
// Create a secret for the user
let secret2 = b"i'm a secret that should not be stored";
set_secret(user, secret2);
// Verify the user secret
let user_address = signer::address_of(user);
let valut2 = borrow_global<Vault>(user_address);
assert!(valut2.secret == string::utf8(secret2), 4);
debug::print(&b"All tests passed!");
}

Recommended Mitigation

- public entry fun set_secret(caller: &signer, secret: vector<u8>) {
+ public entry fun set_secret(caller: &signer, secret: vector<u8>) acquires Vault {
- let secret_vault = Vault { secret: string::utf8(secret) };
+ assert!(signer::address_of(caller) == @owner, NOT_OWNER);
- move_to(caller, secret_vault);
+ if(!exists<Vault>(@owner)) {
+ let vault = Vault { secret: string::utf8(secret) };
+ move_to(caller, vault);
+ } else {
+ let vault = borrow_global_mut<Vault>(@owner);
+ vault.secret = string::utf8(secret);
+ }
event::emit(SetNewSecret {});
}
Updates

Lead Judging Commences

bube Lead Judge 17 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

Anyone can call `set_secret` function

In Move for Aptos, the term "owner" refers to a signer, which is a verified account that owns a given resource, has permission to add resources and the ability to grant access or modify digital assets. Following this logic in this contest, the owner is the account that owns `Vault`. This means that anyone has right to call `set_secret` and then to own the `Vault` and to retrieve the secret from the `Vault` in `get_secret` function. Therefore, this group is invalid, because the expected behavior is anyone to call the `set_secret` function.

Support

FAQs

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