One Shot: Reloaded

First Flight #47
Beginner FriendlyNFT
100 EXP
Submission Details
Impact: high
Likelihood: high

Single Authority Control Enables Complete Protocol Manipulation and User Asset Loss

Author Revealed upon completion

Root + Impact

Description

  • The RapBattle protocol is designed to operate as a decentralized gaming platform where users can safely stake valuable NFT assets, earn rewards through training, and engage in competitive battles with confidence that their assets are protected by smart contract guarantees. The protocol should implement robust access controls and asset custody mechanisms that prevent any single entity from manipulating core functionality or confiscating user assets, ensuring trustless operation and user sovereignty.

  • The protocol implements extreme centralization through @battle_addr which controls all critical functions including NFT minting authority, CRED token supply management, user asset custody, stats modification, and unstaking authorization. The custody model transfers actual NFT ownership (not just custody) to @battle_addr during staking and battles, meaning users cannot retrieve their assets without cooperation from the centralized authority. This architecture creates a complete single point of failure that contradicts decentralized protocol principles.


The vulnerability stems from centralized control patterns across all protocol modules:

// one_shot.move - NFT minting control
assert!(owner_addr == @battle_addr, 1 /* E_NOT_AUTHORIZED */); @> // Only @battle_addr can mint
// streets.move - Unstaking requires authority signature
public entry fun unstake(staker: &signer, module_owner: &signer, ...) @> // module_owner must be @battle_addr
// Custody transfers in staking/battles
object::transfer(staker, rapper_token, @battle_addr); @> // Users lose NFT ownership
one_shot::transfer_record_only(token_id, staker_addr, @battle_addr); @> // Internal records updated

Risk

Likelihood:

  • Single private key control over entire protocol makes compromise inevitable over time through various attack vectors including social engineering, technical exploits, insider threats, or simple operational security failures.

  • The high-value NFT custody model creates attractive targets for sophisticated attackers. Centralized control points are easily identified through public code analysis, making them obvious targets for exploitation.

Impact:

  • Complete protocol compromise enables the controlling entity to mint infinite NFTs (destroying collection value), mint infinite CRED tokens (causing hyperinflation), confiscate all staked user NFTs permanently, manipulate any user's NFT statistics, and block users from accessing their staked assets indefinitely. Unlike typical DeFi protocols where users retain custody, RapBattle users transfer full ownership, meaning asset recovery is impossible without authority cooperation.

Proof of Concept

The following analysis demonstrates the extent of centralized control:

#[test]
public fun test_centralization_analysis() {
// Critical control points under @battle_addr:
let control_points = vector[
"NFT collection minting authority", // one_shot::mint_rapper
"CRED token mint/burn capabilities", // cred_token::CredCapabilities
"All staked NFT custody", // streets.move transfers
"All battle NFT custody", // rap_battle.move transfers
"Unstaking authorization", // streets::unstake requires signer
"Stats modification authority", // one_shot::write_stats
"Battle arena management" // rap_battle::BattleArena
];
let total_control_points = vector::length(&control_points);
let decentralized_alternatives = 0;
let multi_sig_protection = 0;
let governance_mechanisms = 0;
assert!(total_control_points == 7, 1);
assert!(decentralized_alternatives == 0, 2);
assert!(multi_sig_protection == 0, 3);
// Single point of failure analysis:
// - If @battle_addr private key compromised → Total protocol compromise
// - No recovery mechanisms for users
// - No time delays or governance for critical operations
}

Custody Risk Analysis:

#[test]
public fun test_custody_risk_analysis() {
// High-risk custody model analysis:
// Staking flow:
// 1. User calls: object::transfer(staker, nft, @battle_addr)
// 2. User loses ownership, @battle_addr gains ownership
// 3. To unstake: Requires @battle_addr signer cooperation
// Battle flow:
// 1. Both players: object::transfer(player, nft, @battle_addr)
// 2. Winner gets BOTH NFTs, loser gets nothing
// 3. Users risk losing entire NFT collection, not just bet amount
let custody_risks = vector[
"Users cannot unstake without @battle_addr cooperation",
"Battle losers forfeit entire NFTs permanently",
"No trustless recovery mechanisms",
"Complete dependence on centralized authority honesty"
];
// Unlike typical custody (temporary control), this is ownership transfer
// Users have no recourse if @battle_addr refuses to cooperate
}

Recommended Mitigation

Implement proper decentralized architecture with multi-signature controls and trustless custody:

// 1. Multi-signature authority structure
struct MultiSigAuthority has key {
required_signatures: u64,
authorized_signers: vector<address>,
pending_operations: Table<u64, PendingOperation>
}
// 2. Escrow-based custody instead of ownership transfer
struct AssetEscrow has key {
escrowed_assets: Table<address, Object<Token>>,
escrow_terms: Table<address, EscrowTerms>,
automatic_release_conditions: vector<ReleaseCondition>
}
// 3. Time-locked operations for critical functions
struct TimelockOperation has key {
operation_hash: vector<u8>,
execution_time: u64,
required_delay: u64
}
-public entry fun mint_rapper(module_owner: &signer, to: address)
+public entry fun mint_rapper(multi_sig_proof: MultiSigProof, to: address)
-object::transfer(staker, rapper_token, @battle_addr);
+escrow::deposit_with_terms(staker, rapper_token, staking_terms);

Support

FAQs

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