Skip to content

strkey.DecodeSignedPayload() panic on short P-addresses #5902

@karthikiyer56

Description

@karthikiyer56

strkey.DecodeSignedPayload() panics when given a P-address with a payload shorter than 32 bytes. The function slices raw[:32] without checking length first.

Root Cause

strkey/signed_payload.go:DecodeSignedPayload() assumes payload is ≥ 32 bytes:

func DecodeSignedPayload(address string) (*SignedPayload, error) {
    raw, err := Decode(VersionByteSignedPayload, address)
    if err != nil {
        return nil, errors.New("invalid signed payload")
    }
    const signerLen = 32
    rawSigner, raw := raw[:signerLen], raw[signerLen:]  // PANIC if len(raw) < 32
    // ...
}

Decode() only validates version byte and CRC — it returns payloads of any length.
Compare with DecodeMuxedAccount() which correctly validates: if len(raw) != 40 { return error }

Impact

  • Affects apps calling DecodeSignedPayload() directly on untrusted input
  • Also reachable via xdr.SignerKey.SetAddress() with P-addresses
    Note: Horizon/RPC are not affected — Horizon never calls DecodeSignedPayload()

Fix

func DecodeSignedPayload(address string) (*SignedPayload, error) {
    raw, err := Decode(VersionByteSignedPayload, address)
    if err != nil {
        return nil, errors.New("invalid signed payload")
    }
    const signerLen = 32
    if len(raw) < signerLen {
        return nil, errors.Errorf("signed payload too short: %d bytes", len(raw))
    }
    rawSigner, raw := raw[:signerLen], raw[signerLen:]
    // ...
}

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Status

To Do

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions