Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🦀 crates.io
Not in CISA KEV

GHSA-x442-m7cc-hr92 kora-lib

GHSA-x442-m7cc-hr92 is a remote code execution vulnerability in kora-lib. A fix is available for kora-lib — see the affected versions and patch details below.

kora-lib: Unrecognized Instruction Types Create Empty Stubs That Bypass Fee Payer Policy

Published
Mar 12, 2026
Updated
Mar 14, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Mar 14, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🦀kora-lib

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.

Description

Summary

When inner CPI instructions use instruction types not recognized by Kora's parser (including Token-2022 extension instructions like ConfidentialTransfer, TransferFeeExtension::WithdrawWithheldTokens, etc.), they are reconstructed as stub instructions with empty accounts and empty data. These stubs fail deserialization during fee payer policy validation and are silently skipped, meaning any fee payer usage within those instructions goes completely unchecked.

Severity

Medium

Affected Component

  • File: crates/lib/src/transaction/instruction_util.rs
  • Functions: reconstruct_system_instruction(), reconstruct_spl_token_instruction()
  • Lines: 750–753, 1187–1189

Root Cause

The instruction reconstruction functions have a catch-all _ => arm for unrecognized instruction types that creates a stub CompiledInstruction with the correct program_id_index but empty accounts and empty data. When this stub reaches the fee payer policy parsing (parse_system_instructions / parse_token_instructions), deserialization of empty data fails. The parsing functions also have a catch-all _ => {} that silently skips the failed instruction. The result: the instruction exists in all_instructions (so program allowlist checks pass), but fee payer policy is never enforced on it.

Vulnerable Code

Stub Creation

// crates/lib/src/transaction/instruction_util.rs:750-753
// System program — unrecognized instruction type:
_ => {
    log::error!("Unsupported system instruction type: {}", instruction_type);
    Ok(Self::build_default_compiled_instruction(program_id_index))
}

// crates/lib/src/transaction/instruction_util.rs:1187-1189
// SPL Token program — unrecognized instruction type:
_ => {
    log::error!("Unsupported token instruction type: {}", instruction_type);
    Ok(Self::build_default_compiled_instruction(program_id_index))
}

The stub builder:

pub fn build_default_compiled_instruction(program_id_index: u8) -> CompiledInstruction {
    CompiledInstruction {
        program_id_index,
        accounts: vec![],  // <-- No accounts
        data: vec![],       // <-- No data
    }
}

Silent Skip During Policy Parsing

// In parse_system_instructions:
if let Ok(system_instruction) = bincode::deserialize::<SystemInstruction>(&instruction.data) {
    match system_instruction {
        // ... known types handled ...
        _ => {}  // <-- Unrecognized: silently skipped
    }
}
// If deserialize fails (empty data), the entire `if let Ok` block is skipped.
// The instruction is not added to any policy check map.

// In parse_token_instructions:
if let Ok(token_instruction) = TokenInstruction::unpack(&instruction.data) {
    match token_instruction {
        // ... known types handled ...
        _ => {}  // <-- Unrecognized: silently skipped
    }
}
// Same: empty data causes unpack to fail, instruction completely invisible to policy.

Proof of Concept

Affected Token-2022 Extension Instructions

The following Token-2022 extension instruction types are NOT handled by Kora's parser and would produce empty stubs:

ExtensionInstructionRisk if Fee Payer is Authority
TransferFeeExtensionWithdrawWithheldTokensFromMintFee payer as withdraw authority can drain withheld fees
TransferFeeExtensionWithdrawWithheldTokensFromAccountsSame
TransferFeeExtensionHarvestWithheldTokensToMintFee collection manipulation
ConfidentialTransferTransferHidden transfer amounts bypass fee tracking
ConfidentialTransferWithdrawHidden withdrawals
InterestBearingMintUpdateRateFee payer as rate authority can manipulate interest
TransferHookExecuteArbitrary hook execution
GroupMemberPointerUpdateMetadata manipulation
MetadataPointerUpdateMetadata manipulation
PermanentDelegateTransfer (via delegate)Delegate-based unauthorized transfers

Code Path Trace

1. Transaction contains an inner CPI instruction:
   Program: Token-2022
   Type: "withdrawWithheldTokensFromMint" (TransferFeeExtension)
   Accounts: [fee_payer (as withdraw_withheld_authority), mint, destination]

2. RPC returns this as a Parsed inner instruction

3. reconstruct_spl_token_instruction() is called:
   - instruction_type = "withdrawWithheldTokensFromMint"
   - No match in the known types (transfer, transferChecked, burn, etc.)
   - Falls through to _ => arm
   - Returns: CompiledInstruction { program_id_index, accounts: [], data: [] }

4. Stub is added to all_instructions
   → validate_programs() sees Token-2022 program ID → PASS (allowed)
   → validate_disallowed_accounts() sees no accounts in the stub → PASS

5. parse_token_instructions() processes the stub:
   - TokenInstruction::unpack(&[]) → Err (empty data)
   - if let Ok(...) block skipped entirely
   - Instruction not added to any ParsedSPLInstructionType map

6. validate_fee_payer_usage() iterates parsed SPL instructions:
   - No entry for "withdrawWithheldTokensFromMint"
   - Fee payer's usage as withdraw_withheld_authority is NEVER checked

7. Transaction is signed by Kora

8. On-chain: fee_payer (as withdraw authority) withdraws withheld
   transfer fees from the mint to attacker's account

Verifiable Test

#[test]
fn test_unrecognized_instruction_produces_empty_stub() {
    // Simulate what happens for an unrecognized Token-2022 instruction
    let program_id_index: u8 = 3; // Token-2022 at index 3

    // This is what the catch-all arm produces:
    let stub = IxUtils::build_default_compiled_instruction(program_id_index);

    assert_eq!(stub.accounts.len(), 0);  // No accounts
    assert_eq!(stub.data.len(), 0);      // No data

    // Attempt to parse it:
    let result = TokenInstruction::unpack(&stub.data);
    assert!(result.is_err());  // Cannot parse empty data

    // Therefore: fee payer policy is never applied to this instruction
    // The fee payer could be the withdraw_withheld_authority in the
    // REAL instruction, but the stub has zero accounts — invisible.
}

Impact

  • Fee Payer Policy Bypass: Token-2022 extension instructions that use the fee payer as an authority are invisible to policy enforcement.
  • Forward-Looking Risk: As Solana and SPL Token-2022 add new instruction types, they will automatically bypass all fee payer policy checks in Kora.
  • Precondition: Requires the fee payer to hold some authority role (e.g., withdraw_withheld_authority, permanent_delegate) for Token-2022 accounts. This is unlikely in typical deployments but possible in misconfigured setups.

Recommendation

Reject transactions containing inner instructions with unrecognized types (fail-secure):

// In reconstruct_system_instruction:
_ => {
    return Err(KoraError::InvalidTransaction(format!(
        "Unrecognized system instruction type '{}' in CPI — \
         cannot validate fee payer policy. Transaction rejected.",
        instruction_type
    )));
}

// In reconstruct_spl_token_instruction:
_ => {
    return Err(KoraError::InvalidTransaction(format!(
        "Unrecognized SPL Token instruction type '{}' in CPI — \
         cannot validate fee payer policy. Transaction rejected.",
        instruction_type
    )));
}

Alternatively, maintain a list of known-safe instruction types that don't involve authority checks, and only reject truly unknown types.

References

  • crates/lib/src/transaction/instruction_util.rs:750-753 — system instruction catch-all
  • crates/lib/src/transaction/instruction_util.rs:1187-1189 — SPL token instruction catch-all
  • crates/lib/src/transaction/instruction_util.rs:316-319build_default_compiled_instruction
  • SPL Token-2022 instruction types — full list of extension instructions

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🦀crates.iokora-liball versions2.0.5cargo update -p kora-lib --precise 2.0.5

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for kora-lib, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update kora-lib to 2.0.5 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-x442-m7cc-hr92 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-x442-m7cc-hr92 can be triaged on real exposure rather than presence alone.

Tailored to GHSA-x442-m7cc-hr92. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## Summary When inner CPI instructions use instruction types not recognized by Kora's parser (including Token-2022 extension instructions like `ConfidentialTransfer`, `TransferFeeExtension::WithdrawWithheldTokens`, etc.), they are reconstructed as stub instructions with empty accounts and empty data. These stubs fail deserialization during fee payer policy validation and are silently skipped, meaning any fee payer usage within those instructions goes completely unchecked. ## Severity **Medium** ## Affected Component - **File:** `crates/lib/src/transaction/instruction_util.rs` - **Function
O3 Security · Impact-Aware SCA

Is GHSA-x442-m7cc-hr92 in your dependencies?

O3 Security finds GHSA-x442-m7cc-hr92 across crates.io dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

GHSA-x442-m7cc-hr92: kora-lib | O3 Security