Secret Vault

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

Lack of access control in set_secret lets arbitrary accounts create secrets

Description

The set_secret function allows any signer to call it and create a new Vault resource under their own account. This directly conflicts with the project specification, which states that only the owner should be able to store a secret. Because there is no restriction, any account on the network can publish a Vault for themselves. In practice, this means the contract does not enforce a single trusted owner and deviates from the intended access model. If the expected design is that only one predefined account (@owner) manages secrets, the current implementation fails completely at enforcing this role.

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

Root Cause

  • set_secret does not restrict the caller’s address.

Risk

Likelihood:

  • Every time a non-owner user calls set_secret, the function succeeds in creating their own Vault.

  • This action requires no special conditions—any account with a signer can exploit it, making it trivial and routine

Impact:

  • Authorization violation: Any account can set secrets, which contradicts the role-based description of the system.

  • Security guarantees broken: Attackers can spam arbitrary secrets or impersonate the concept of an “owner.”

  • Spec non-compliance: The contract does not match the stated requirement that only the owner may set secrets.


Recommended Mitigation

If the intended design is single-owner only (restricted to @owner):

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

Lead Judging Commences

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