Skip to content

fix(interface): validate Borsh string lengths in unpack() to prevent SBF heap abort#87

Open
bit2swaz wants to merge 1 commit into
solana-program:mainfrom
bit2swaz:fix/borsh-length-panic
Open

fix(interface): validate Borsh string lengths in unpack() to prevent SBF heap abort#87
bit2swaz wants to merge 1 commit into
solana-program:mainfrom
bit2swaz:fix/borsh-length-panic

Conversation

@bit2swaz

@bit2swaz bit2swaz commented Jun 12, 2026

Copy link
Copy Markdown

Problem

TokenMetadataInstruction::unpack() calls try_from_slice(rest)? directly on attacker-controlled instruction data. A Borsh String is a little-endian u32 length prefix followed by that many bytes, so a forged prefix like u32::MAX makes Borsh try to allocate ~1 MiB before the ? error path runs and discovers the buffer is too short. On the 32 KiB SBF heap that allocation aborts the program instead of returning a clean error.

Only the variants that carry Borsh strings are affected: Initialize (name, symbol, uri), UpdateField (the value string, plus the nested string in Field::Key, tag 3), and RemoveKey (the key string after the idempotent bool). UpdateAuthority and Emit have no strings and are left alone.

Fix

A new check_borsh_string helper reads each string's declared length and checks it against the remaining buffer before try_from_slice runs, returning InvalidInstructionData when it doesn't fit. The three affected match arms walk a cursor through their fields and validate each string first. The length arithmetic is checked so it can't overflow.

Tests

Three tests feed a forged u32::MAX length prefix through unpack() for Initialize, UpdateField, and RemoveKey and assert InvalidInstructionData. They run natively, no SBF build needed. They also work as real regression guards: before the fix Borsh returns a different (IO) error, so the assertion would fail.

Context

This puts the validation in spl-token-metadata-interface, where the data is deserialized, rather than in the token-2022 caller. It follows the discussion on solana-program/token-2022#1194 (now closed), where @joncinque suggested the fix should live here. References solana-program/token-2022#1152. The token-2022 side is then just a dependency bump once this releases.

🤖 Generated with Claude Code

…SBF heap abort

Forged u32 length prefixes in Initialize/UpdateField/RemoveKey payloads could
trigger an oversized allocation in try_from_slice that aborts on the 32 KiB SBF
heap. Validate each string length against the remaining buffer before
deserializing, returning InvalidInstructionData for malformed payloads.

Closes solana-program/token-2022#1152

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant