Secret Vault on Aptos

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

[H-2]: Secret is Immutable Due to Improper Resource Creation

[H-2]: Secret is Immutable Due to Improper Resource Creation

Description

The owner should be able to set a secret and then update it later. But, the set_secret function uses move_to to create the Vault. In Move, move_to aborts if a resource of that type already exists at the address. This means the function works only once per address, making it impossible to update a secret.

public entry fun set_secret(caller:&signer, secret:vector<u8>){
let secret_vault = Vault{secret: string::utf8(secret)};
@>// Flaw: This will abort if a `Vault` already exists at the `caller`'s address.
move_to(caller, secret_vault);
event::emit(SetNewSecret {});
}

Risk

Likelihood: High

  • This vulnerability is triggered whenever the owner (or any user) attempts to call set_secret for a second time.

  • Secret rotation is a standard and expected practice, making a second call highly probable.

Impact: High

  • Denial of Service: The owner is prevented from managing their secret after the initial setup.

  • Security Risk: In a real-world scenario, the inability to rotate a compromised or stale secret is a significant security issue.

Proof of Concept

The vulnerability is a direct consequence of the Move language's rules for resource management.

  1. The owner calls set_secret for the first time. The move_to operation succeeds.

  2. The owner needs to update the secret and calls set_secret again.

  3. The move_to instruction is executed, but the Move VM detects an existing Vault resource at the owner's address.

  4. The transaction immediately aborts with an ERESOURCE_ALREADY_EXISTS error.

Recommended Mitigation

The following code can be a possible solution to fix this issue:

- 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 {});
- }
+ public entry fun set_secret(caller:&signer, secret:vector<u8>) acquires Vault {
+ let owner_address = signer::address_of(caller);
+ assert!(owner_address == @owner, NOT_OWNER);
+
+ // Check for existence to handle updates.
+ if (exists<Vault>(owner_address)) {
+ // If vault exists, borrow and modify it.
+ let vault = borrow_global_mut<Vault>(owner_address);
+ vault.secret = string::utf8(secret);
+ } else {
+ // If not, create it with move_to.
+ let secret_vault = Vault{secret: string::utf8(secret)};
+ move_to(caller, secret_vault);
+ }
+ event::emit(SetNewSecret {});
+ }
Updates

Lead Judging Commences

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