Secret Vault

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

Unauthorized retrieve, anyone can read an owner secret

Root + Impact

Description

  • Normal behavior is that only the owner may set and retrieve their secret.

  • Current behavior is that anyone can read the owner’s secret by simply passing @owner into the view function. The function authorizes based on a user-provided address parameter, not the transaction signer.

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

Risk

Likelihood: High

  • trivial call with @owner as parameter

  • no signer-based auth, anyone can call the function

  • attack path is straightforward

Impact: High

  • Breaks core confidentiality and main functionality.

  • The protocols that trusted their users' secrets to be stored using this contract are at risk of a security breach.

  • Users may potentially lose data or funds.

Proof of Concept

The test shows that a non-owner can read the owner’s secret by calling the view function with @owner as the argument. There’s no signer-based auth; the function authorizes purely on the caller-supplied parameter.

#[test(owner = @0xcc, attacker = @0x456)]
public fun test_anyone_can_read_owner_secret(owner: &signer, attacker: &signer) {
account::create_account_for_test(signer::address_of(owner));
account::create_account_for_test(signer::address_of(attacker));
let secret = b"top secret";
vault::set_secret(owner, secret);
let leaked: String = vault::get_secret(@owner);
assert!(leaked == string::utf8(secret), 100);
}

Recommended Mitigation

Enforce signer-based authentication for secrets to be read only by actual owner.

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

Lead Judging Commences

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