Secret Vault on Aptos

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

Access Control Bypass in get_secret Function

Description

The get_secret function is designed to only allow the owner (@owner) to access vault secrets by checking if the caller parameter matches the hardcoded owner address.
However, the function contains a critical flaw where it always retrieves the vault from the hardcoded @owner address regardless of the caller parameter, while only using the caller parameter for access control validation. This creates an access control bypass where any address can be passed as the caller parameter, and as long as it equals @owner, the function will return the owner's secret.
for this one we can pass @0xcc as paremeter and retreive the secret

#[view]
public fun get_secret (caller: address):String acquires Vault {
assert!(caller == @owner,NOT_OWNER); // @> Only validates caller equals @owner
let vault = borrow_global<Vault >(@owner); // @> Always fetches @owner's vault
vault.secret
}

Risk

Likelihood:

  • Anyone can call this view function since it's public and pass @owner as the caller parameter

Impact:

  • Complete exposure of the owner's secret to any external caller

Proof of Concept

#[test(attacker = @0x999, owner_addr = @owner)]
fun test_access_control_bypass(attacker: &signer, owner_addr: &signer) acquires Vault {
use aptos_framework::account;
account::create_account_for_test(signer::address_of(attacker));
account::create_account_for_test(signer::address_of(owner_addr));
let secret = b"poc";
set_secret(owner_addr, secret);
// This should fail but it doesn't due to the bug
let stolen_secret = get_secret(@owner); // @> Attacker passes @owner address
// Verify that attacker successfully retrieved owner's secret
assert!(stolen_secret == string::utf8(secret), 5);
}

Recommended Mitigation

#[view]
- public fun get_secret (caller: address):String acquires Vault {
- assert!(caller == @owner,NOT_OWNER);
- let vault = borrow_global<Vault >(@owner);
+ public fun get_secret(caller: address):String acquires Vault {
+ let vault = borrow_global<Vault>(caller);
vault.secret
}
Updates

Lead Judging Commences

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

Lack of signer check in `get_secret`

Support

FAQs

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