GHSA-x442-m7cc-hr92: kora-lib Unrecognized Instruction Types Create Empty Vulnerability

MODERATE
CWE-693
Published
Advisory Summary

GHSA-x442-m7cc-hr92 is a MODERATE unrecognized instruction types create empty vulnerability (CWE-693: Protection Mechanism Failure) affecting kora-lib libraries in the crates.io ecosystem. The issue involves unrecognized instruction types create empty stubs that bypass fee payer policy. Remediation is available by upgrading affected packages to version 2.0.5.

GHSA-x442-m7cc-hr92 at a Glance

CVE Identifier N/A
GHSA Identifier GHSA-x442-m7cc-hr92
Severity MODERATE
CVSS v3.1 Base Score N/A
CWE Classification CWE-693: Protection Mechanism Failure
Affected Product kora-lib
Package Ecosystem crates.io
Published Date
Last Updated

How to Fix GHSA-x442-m7cc-hr92

To remediate this vulnerability, upgrade all affected kora-lib dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

kora-lib fixed: 2.0.5
Upgrade kora-lib to 2.0.5
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for kora-lib

How to Check if You Are Affected

To determine whether your application is affected by GHSA-x442-m7cc-hr92, inspect your project dependencies for kora-lib:

inspect dependencies for kora-lib

Analyze the terminal output to locate any version of kora-lib in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 2.0.5), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-693: Protection Mechanism Failure, where the product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product. In kora-lib, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## 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 ```rust // 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: ```rust 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 ```rust // 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: | Extension | Instruction | Risk if Fee Payer is Authority | |-----------|------------|-------------------------------| | `TransferFeeExtension` | `WithdrawWithheldTokensFromMint` | Fee payer as withdraw authority can drain withheld fees | | `TransferFeeExtension` | `WithdrawWithheldTokensFromAccounts` | Same | | `TransferFeeExtension` | `HarvestWithheldTokensToMint` | Fee collection manipulation | | `ConfidentialTransfer` | `Transfer` | Hidden transfer amounts bypass fee tracking | | `ConfidentialTransfer` | `Withdraw` | Hidden withdrawals | | `InterestBearingMint` | `UpdateRate` | Fee payer as rate authority can manipulate interest | | `TransferHook` | `Execute` | Arbitrary hook execution | | `GroupMemberPointer` | `Update` | Metadata manipulation | | `MetadataPointer` | `Update` | Metadata manipulation | | `PermanentDelegate` | `Transfer` (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 ```rust #[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): ```rust // 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-319` — `build_default_compiled_instruction` - [SPL Token-2022 instruction types](https://github.com/solana-labs/solana-program-library/tree/master/token/program-2022/src/extension) — full list of extension instructions

GHSA-x442-m7cc-hr92 Affected kora-lib Versions

1 component(s)
Fixed Versions:
2.0.5
Product / Package Ecosystem Affected Versions Fixed Version
kora-lib
crates.io
< 2.0.5
2.0.5

References

Frequently Asked Questions

What is GHSA-x442-m7cc-hr92?
GHSA-x442-m7cc-hr92 is a security vulnerability in kora-lib involving Unrecognized Instruction Types Create Empty Stubs That Bypass Fee Payer Policy under CWE-693: Protection Mechanism Failure.
Which kora-lib versions are affected?
Affected versions include releases prior to 2.0.5 across affected packages: kora-lib.
What version fixes GHSA-x442-m7cc-hr92?
Upgrading to 2.0.5 (or the latest patched release for your respective branch) resolves the vulnerability.
Is kora-lib affected?
Yes, kora-lib is affected in releases prior to 2.0.5. Upgrade your dependency to 2.0.5 or later.
What CWE is associated with GHSA-x442-m7cc-hr92?
GHSA-x442-m7cc-hr92 is classified under CWE-693: Protection Mechanism Failure (The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product.).
How can I check crates.io dependencies for GHSA-x442-m7cc-hr92?
Run the dependency tree command: 'inspect dependencies for kora-lib'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-x442-m7cc-hr92",
  "modified" : "2026-03-12T14:50:39Z",
  "published" : "2026-03-12T14:50:39Z",
  "aliases" : [ ],
  "summary" : "kora-lib: Unrecognized Instruction Types Create Empty Stubs That Bypass Fee Payer Policy",
  "details" : "## Summary\n\nWhen 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.\n\n## Severity\n\n**Medium**\n\n## Affected Component\n\n- **File:** `crates/lib/src/transaction/instruction_util.rs`\n- **Functions:** `reconstruct_system_instruction()`, `reconstruct_spl_token_instruction()`\n- **Lines:** 750–753, 1187–1189\n\n## Root Cause\n\nThe 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.\n\n## Vulnerable Code\n\n### Stub Creation\n\n```rust\n// crates/lib/src/transaction/instruction_util.rs:750-753\n// System program — unrecognized instruction type:\n_ => {\n    log::error!(\"Unsupported system instruction type: {}\", instruction_type);\n    Ok(Self::build_default_compiled_instruction(program_id_index))\n}\n\n// crates/lib/src/transaction/instruction_util.rs:1187-1189\n// SPL Token program — unrecognized instruction type:\n_ => {\n    log::error!(\"Unsupported token instruction type: {}\", instruction_type);\n    Ok(Self::build_default_compiled_instruction(program_id_index))\n}\n```\n\nThe stub builder:\n```rust\npub fn build_default_compiled_instruction(program_id_index: u8) -> CompiledInstruction {\n    CompiledInstruction {\n        program_id_index,\n        accounts: vec![],  // <-- No accounts\n        data: vec![],       // <-- No data\n    }\n}\n```\n\n### Silent Skip During Policy Parsing\n\n```rust\n// In parse_system_instructions:\nif let Ok(system_instruction) = bincode::deserialize::<SystemInstruction>(&instruction.data) {\n    match system_instruction {\n        // ... known types handled ...\n        _ => {}  // <-- Unrecognized: silently skipped\n    }\n}\n// If deserialize fails (empty data), the entire `if let Ok` block is skipped.\n// The instruction is not added to any policy check map.\n\n// In parse_token_instructions:\nif let Ok(token_instruction) = TokenInstruction::unpack(&instruction.data) {\n    match token_instruction {\n        // ... known types handled ...\n        _ => {}  // <-- Unrecognized: silently skipped\n    }\n}\n// Same: empty data causes unpack to fail, instruction completely invisible to policy.\n```\n\n## Proof of Concept\n\n### Affected Token-2022 Extension Instructions\n\nThe following Token-2022 extension instruction types are NOT handled by Kora's parser and would produce empty stubs:\n\n| Extension | Instruction | Risk if Fee Payer is Authority |\n|-----------|------------|-------------------------------|\n| `TransferFeeExtension` | `WithdrawWithheldTokensFromMint` | Fee payer as withdraw authority can drain withheld fees |\n| `TransferFeeExtension` | `WithdrawWithheldTokensFromAccounts` | Same |\n| `TransferFeeExtension` | `HarvestWithheldTokensToMint` | Fee collection manipulation |\n| `ConfidentialTransfer` | `Transfer` | Hidden transfer amounts bypass fee tracking |\n| `ConfidentialTransfer` | `Withdraw` | Hidden withdrawals |\n| `InterestBearingMint` | `UpdateRate` | Fee payer as rate authority can manipulate interest |\n| `TransferHook` | `Execute` | Arbitrary hook execution |\n| `GroupMemberPointer` | `Update` | Metadata manipulation |\n| `MetadataPointer` | `Update` | Metadata manipulation |\n| `PermanentDelegate` | `Transfer` (via delegate) | Delegate-based unauthorized transfers |\n\n### Code Path Trace\n\n```\n1. Transaction contains an inner CPI instruction:\n   Program: Token-2022\n   Type: \"withdrawWithheldTokensFromMint\" (TransferFeeExtension)\n   Accounts: [fee_payer (as withdraw_withheld_authority), mint, destination]\n\n2. RPC returns this as a Parsed inner instruction\n\n3. reconstruct_spl_token_instruction() is called:\n   - instruction_type = \"withdrawWithheldTokensFromMint\"\n   - No match in the known types (transfer, transferChecked, burn, etc.)\n   - Falls through to _ => arm\n   - Returns: CompiledInstruction { program_id_index, accounts: [], data: [] }\n\n4. Stub is added to all_instructions\n   → validate_programs() sees Token-2022 program ID → PASS (allowed)\n   → validate_disallowed_accounts() sees no accounts in the stub → PASS\n\n5. parse_token_instructions() processes the stub:\n   - TokenInstruction::unpack(&[]) → Err (empty data)\n   - if let Ok(...) block skipped entirely\n   - Instruction not added to any ParsedSPLInstructionType map\n\n6. validate_fee_payer_usage() iterates parsed SPL instructions:\n   - No entry for \"withdrawWithheldTokensFromMint\"\n   - Fee payer's usage as withdraw_withheld_authority is NEVER checked\n\n7. Transaction is signed by Kora\n\n8. On-chain: fee_payer (as withdraw authority) withdraws withheld\n   transfer fees from the mint to attacker's account\n```\n\n### Verifiable Test\n\n```rust\n#[test]\nfn test_unrecognized_instruction_produces_empty_stub() {\n    // Simulate what happens for an unrecognized Token-2022 instruction\n    let program_id_index: u8 = 3; // Token-2022 at index 3\n\n    // This is what the catch-all arm produces:\n    let stub = IxUtils::build_default_compiled_instruction(program_id_index);\n\n    assert_eq!(stub.accounts.len(), 0);  // No accounts\n    assert_eq!(stub.data.len(), 0);      // No data\n\n    // Attempt to parse it:\n    let result = TokenInstruction::unpack(&stub.data);\n    assert!(result.is_err());  // Cannot parse empty data\n\n    // Therefore: fee payer policy is never applied to this instruction\n    // The fee payer could be the withdraw_withheld_authority in the\n    // REAL instruction, but the stub has zero accounts — invisible.\n}\n```\n\n## Impact\n\n- **Fee Payer Policy Bypass:** Token-2022 extension instructions that use the fee payer as an authority are invisible to policy enforcement.\n- **Forward-Looking Risk:** As Solana and SPL Token-2022 add new instruction types, they will automatically bypass all fee payer policy checks in Kora.\n- **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.\n\n## Recommendation\n\nReject transactions containing inner instructions with unrecognized types (fail-secure):\n\n```rust\n// In reconstruct_system_instruction:\n_ => {\n    return Err(KoraError::InvalidTransaction(format!(\n        \"Unrecognized system instruction type '{}' in CPI — \\\n         cannot validate fee payer policy. Transaction rejected.\",\n        instruction_type\n    )));\n}\n\n// In reconstruct_spl_token_instruction:\n_ => {\n    return Err(KoraError::InvalidTransaction(format!(\n        \"Unrecognized SPL Token instruction type '{}' in CPI — \\\n         cannot validate fee payer policy. Transaction rejected.\",\n        instruction_type\n    )));\n}\n```\n\nAlternatively, maintain a list of known-safe instruction types that don't involve authority checks, and only reject truly unknown types.\n\n## References\n\n- `crates/lib/src/transaction/instruction_util.rs:750-753` — system instruction catch-all\n- `crates/lib/src/transaction/instruction_util.rs:1187-1189` — SPL token instruction catch-all\n- `crates/lib/src/transaction/instruction_util.rs:316-319` — `build_default_compiled_instruction`\n- [SPL Token-2022 instruction types](https://github.com/solana-labs/solana-program-library/tree/master/token/program-2022/src/extension) — full list of extension instructions",
  "severity" : [ {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "crates.io",
      "name" : "kora-lib"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "fixed" : "2.0.5"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/solana-foundation/kora/security/advisories/GHSA-x442-m7cc-hr92"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/solana-foundation/kora"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-693" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-03-12T14:50:39Z",
    "nvd_published_at" : null
  }
}