Secret Vault on Aptos

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

set_secret() can only be called once leading to denial of service

set_secret() only publishes the secret with move_to() + set_secret() can only be called once.

Description

  • set_secret() should be able to be called multiple times. For example when the owner wants to change their secret.

  • set_secret() only publishes the secret with move_to(). It does not handle the case when the Vault resource exists already for the owner

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:

  • The owner calls set_secret() more than one times.

Impact:

  • set_secret() will fail on being called more than one time. This leads to denail of service.

Proof of Concept

#[test(owner = @0xcc, user = @0x123)]
#[expected_failure()]
fun test_set_secret_multiple_failure(owner: &signer, user: &signer) {
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));
let owner_secret_00 = b"owner secret 00";
set_secret(owner, owner_secret_00);
let owner_secret_01 = b"owner secret 01";
// this aborts with error RESOURCE_ALREADY_EXISTS=4004
set_secret(owner, owner_secret_01);
}

Run with

aptos move test --filter test_set_secret_multiple_failure

Output

INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING aptos-secret-vault
Running Move unit tests
[ PASS ] 0x234::vault::test_set_secret_multiple_failure
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
"Result": "Success"
}

Recommended Mitigation

Add an update handler for the use case when the Vault resource already exists in the owners account.

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

Lead Judging Commences

bube Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

The `secret` can not be updated

Support

FAQs

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

Give us feedback!