Secret Vault

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

Invalid UTF-8 Input Causes set_secret to Abort, Restricting Secret Types

Root + Impact

Description

  • The set_secret function accepts a secret as a vector<u8>, which implies it can handle any sequence of bytes.

  • However, the function immediately attempts to convert this input into a String using string::utf8(secret). The string::utf8 function will abort the transaction if the provided byte vector is not valid UTF-8. This restricts the types of secrets that can be stored and can cause the function to fail unexpectedly. Secrets are often raw binary data (like private keys or hashes) which are not guaranteed to be valid UTF-8 strings.

// Root cause in the codebase with @> marks to highlight the relevant section
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:

  • A user attempts to store a valid secret (e.g., a 32-byte hash or an encryption key) that happens to contain byte sequences that are not valid UTF-8.

  • The function signature secret:vector<u8> is misleading, as it suggests any byte vector is acceptable input.

Impact:

  • The utility of the contract is limited, as it cannot be used to store arbitrary binary data, which is a common use case for a "secret vault".

  • Users will experience unexpected transaction aborts if their secret data is not valid UTF-8.

Proof of Concept

The following test demonstrates that providing a non-UTF-8 byte sequence to set_secret will cause the transaction to abort.

  1. A byte vector b"\x80" is created. This is an invalid start for a UTF-8 character.

  2. set_secret is called with this invalid byte vector.

  3. The test is marked with expected_failure_code, anticipating that the transaction will abort due to the failed string::utf8 conversion. The Aptos framework aborts with a specific error code for invalid UTF-8, which is 131073 in this context.

#[test(owner = @0xcc, expected_failure_code = 131073)] // EINVALID_UTF8 in the String module
fun test_invalid_utf8_fails(owner: &signer) {
use aptos_framework::account;
// Set up test environment
account::create_account_for_test(signer::address_of(owner));
// Create a byte vector that is not valid UTF-8
let invalid_secret = b"\x80"; // An invalid UTF-8 sequence
// This call is expected to abort because string::utf8 will fail
set_secret(owner, invalid_secret);
}

Recommended Mitigation

To allow for arbitrary data to be stored as a secret, the Vault struct should store the secret as vector<u8> instead of String. This avoids the unnecessary and restrictive conversion.

This change involves modifying the Vault struct definition and removing the string::utf8 call in set_secret. The get_secret function should also be updated to return a vector<u8>. This makes the contract more robust and aligned with its purpose of storing any type of secret data.

- struct Vault has key {
- secret: String
- }
+ struct Vault has key {
+ secret: vector<u8>
+ }
- 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>){
+ let secret_vault = Vault{secret: secret};
+ move_to(caller,secret_vault);
+ event::emit(SetNewSecret {});
+ }
Updates

Lead Judging Commences

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

Invalid UTF-8 Input Causes set_secret to Abort

Support

FAQs

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