Secret Vault on Aptos

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

Missing access control inside set_secret() allows for unauthorized secret storage

Root + Impact

Description

  • Only the designated @owner should be able to store secrets in the module. Other users should not be able to create, modify secrets or read secrets.

    Only the owner should be able to store a secret and then retrieve it later. Others should not be able to access the secret.

  • However, the set_secret function does not verify that the caller is the owner. Any signer can invoke this function and store a secret under their account, bypassing intended access control.

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

Risk

Likelihood:

  • High — any account can call set_secret at any time.

  • Exploitation requires no special conditions; standard transaction is sufficient.

Impact:

  • Unauthorized users can store secrets in the system.

  • Violates the contract’s security assumptions, potentially exposing sensitive data.

Proof of Concept

Add the following test to the secret_vault.move module which demonstrates how user != module owner can set a secret.

#[test(owner = @0xcc, user = @0x123)]
fun test_unauthorized_secret_storage(user: &signer) {
// Create a secret
let secret = b"i'm a secret";
set_secret(user, secret);
debug::print(&b"Secret stored by user != owner");
}

Result:

Running Move unit tests
[debug] 0x5365637265742073746f726564206279207573657220213d206f776e6572
[ PASS ] 0x234::vault::test_unauthorized_secret_storage
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
"Result": "Success"
}

Recommended Mitigation

Ensure that only the designated module owner can store a secret in the vault.

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

If we try to run thew test again it fails because now set_secret has access control:

Running Move unit tests
[ FAIL ] 0x234::vault::test_unauthorized_secret_storage
Test failures:
Failures in 0x234::vault:
┌── test_unauthorized_secret_storage ──────
error[E11001]: test failure
│ ┌─ /mnt/c/Users/George/Desktop/Blockchain/2025-07-secret-vault/sources/secret_vault.move:38:9
│ │
37public entry fun set_secret(caller:&signer,secret:vector<u8>){
│ │ ---------- In this function in 0x234::vault
38assert!(signer::address_of(caller) == @owner, NOT_OWNER);
│ │ ^^^^^^ Test was not expected to error, but it aborted with code 1 originating in the module 0000000000000000000000000000000000000000000000000000000000000234::vault rooted here
│ stack trace
│ vault::test_unauthorized_secret_storage(/mnt/c/Users/George/Desktop/Blockchain/2025-07-secret-vault/sources/secret_vault.move:76)
└──────────────────
Test result: FAILED. Total tests: 1; passed: 0; failed: 1
{
"Error": "Move unit tests failed"
}
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.