Skip to content

bug: session-table poisoning via partial decode (string_table / key_table mutated before validation) #9

Description

@minagishl

Bug Description

State entries registered while decoding partially-failed messages are retained. Mutations to session tables happen before the surrounding readValue / readMessage returns successfully.

Concrete sites:

  • readValue.TAG_STRING / .Literal (src/protocol.zig:805-806): the string is registered into string_table before the surrounding readValue returns. If the parent message later fails, the string remains in the table and gets ID N. The legitimate sender's next message that expected ID N → its own value now decodes to the attacker's poisoned string.
  • readKeyRef mode 0 (src/protocol.zig:1033-1043): every literal key is permanently registered, even if the enclosing Map's later entries fail.
  • readControl.RegisterShape (src/protocol.zig:1307-1325): even if registerWithId returns false, the earlier per-key registrations into key_table have already happened.
  • putFieldEnum (src/protocol.zig:2012-2028) on PromoteStringFieldToEnum: writes happen before the surrounding parse completes.

Steps to Reproduce

  1. Two peers A (legit) and B (attacker) share a stateful SessionEncoder (server pool reusing codec instances, or attacker MITM).
  2. B sends a malformed message whose prefix contains a Literal string registration that would acquire id N, but whose tail bytes deliberately fail.
  3. A's subsequent message references id N (expecting its own previously-registered value). Decoder returns the attacker's string instead.

Expected Behavior

Stage all session-table mutations into a scratch buffer during decode. Commit the staged mutations only after decodeMessage returns successfully and reader.isEof() holds.

Actual Behavior

Mutations land in shared tables before the surrounding decode validates.

Environment

  • Project: recurram-zig
  • Files: src/protocol.zig:805, :1037, :1264, :2012-2028

Additional Context

Severity: High — semantic forgery; breaks any trust derived from decoded string content.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions