Secret Vault on Aptos

First Flight #46
Beginner FriendlyWallet
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

No Size Limits on Secrets Enabling State Bloat Attacks

Root + Impact

Description

Normal Behavior

The set_secret function should enforce reasonable size limits on secret data to prevent abuse, state bloat, and excessive gas costs while still accommodating legitimate use cases.

Issue

The set_secret function accepts vector<u8> input of any size without validation, allowing users to store arbitrarily large data on-chain. This enables state bloat attacks where malicious actors can consume excessive blockchain storage, increase gas costs for all users, and potentially cause network congestion.

public entry fun set_secret(caller:&signer,secret:vector<u8>){
let secret_vault = Vault{secret: string::utf8(secret)}; // @> No size validation
move_to(caller,secret_vault);
event::emit(SetNewSecret {});
}

Risk

Likelihood:

  • Easy to exploit - just provide large input data

  • No technical barriers prevent abuse

  • Economic incentive may limit some attacks (gas costs)

  • Could be used by legitimate users accidentally

Impact:

  • State bloat: Large secrets consume permanent blockchain storage

  • High gas costs: Users pay excessive fees for large data storage

  • Network congestion: Large transactions slow down block processing

  • Economic griefing: Attackers can force high storage costs on users

  • Resource exhaustion: Unlimited storage per user scales poorly

Proof of Concept

The following test demonstrates the unbounded size vulnerability:

#[test(attacker = @0x888)]
fun test_unbounded_size_vulnerability(attacker: &signer) {
account::create_account_for_test(signer::address_of(attacker));
// Small secret (5 bytes) - normal use case
set_secret(attacker, b"small");
// Medium secret (~100 bytes) - still reasonable
let medium_secret = b"This is a medium sized secret that might be reasonable for normal use cases but shows no size validation exists";
let attacker2 = account::create_account_for_test(@0x889);
set_secret(&attacker2, medium_secret);
// Large secret (~500 bytes) - problematic for blockchain storage
let large_secret = b"This is a very large secret that demonstrates the lack of size validation...";
// [Additional data appended to reach ~500 bytes]
let attacker3 = account::create_account_for_test(@0x88A);
set_secret(&attacker3, large_secret); // ✅ Succeeds but wastes storage!
}

Recommended Mitigation

Add size validation with reasonable limits:

+ const SECRET_TOO_LARGE: u64 = 4;
+ const MAX_SECRET_SIZE: u64 = 1024; // 1KB limit
public entry fun set_secret(caller:&signer,secret:vector<u8>){
+ use std::vector;
+
+ // Validate secret size
+ assert!(vector::length(&secret) <= MAX_SECRET_SIZE, SECRET_TOO_LARGE);
+ assert!(vector::length(&secret) > 0, 5); // No empty secrets
+
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
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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