Secret Vault on Aptos

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

UTF-8 Enforcement Causing Predictable Denial of Service Attacks

Root + Impact

Description

Normal Behavior

The set_secret function should gracefully handle various input formats or provide clear validation errors when input doesn't meet requirements, allowing users to understand and correct their input.

Issue

The set_secret function unconditionally calls string::utf8(secret) without any validation or error handling, causing the entire transaction to abort when users provide invalid UTF-8 byte sequences. This creates a predictable denial of service vector where attackers can cause any call to set_secret to fail by providing malformed UTF-8 data.

public entry fun set_secret(caller:&signer,secret:vector<u8>){
let secret_vault = Vault{secret: string::utf8(secret)}; // @> Aborts on invalid UTF-8
move_to(caller,secret_vault);
event::emit(SetNewSecret {});
}

Risk

Likelihood:

  • Any invalid UTF-8 input triggers the vulnerability

  • Attack vectors are numerous and easy to construct

  • Binary data, encrypted data, or corrupted input naturally triggers this

  • No validation occurs before the vulnerable conversion

Impact:

  • Predictable DoS: Attackers can reliably prevent users from setting secrets

  • Poor user experience: Users storing binary data get cryptic UTF-8 errors

  • No graceful degradation: Entire transaction fails instead of providing helpful feedback

  • Limits functionality: Prevents storing encrypted secrets, hashes, or binary data

  • Economic attack vector: Failed transactions still consume gas but provide no value

Proof of Concept

The following test demonstrates the UTF-8 enforcement vulnerability:

#[test(owner = @0xcc, attacker = @0x999)]
#[expected_failure] // Should fail with UTF-8 error
fun test_utf8_dos_vulnerability(owner: &signer, attacker: &signer) {
account::create_account_for_test(signer::address_of(owner));
account::create_account_for_test(signer::address_of(attacker));
// Normal UTF-8 works fine
set_secret(owner, b"valid_utf8_secret");
// Invalid UTF-8 causes predictable abort
let invalid_utf8 = vector[0xFF, 0xFE, 0xFD]; // Invalid UTF-8 bytes
// This will abort the entire transaction
set_secret(attacker, invalid_utf8); // ❌ ABORTS with UTF-8 error!
}

Recommended Mitigation

Input Validation with Clear Errors:

+ const INVALID_UTF8: u64 = 3;
public entry fun set_secret(caller:&signer,secret:vector<u8>){
+ // Validate UTF-8 before conversion
+ assert!(string::is_utf8(&secret), INVALID_UTF8);
let secret_vault = Vault{secret: string::utf8(secret)};
move_to(caller,secret_vault);
event::emit(SetNewSecret {});
}
Updates

Lead Judging Commences

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