Skip to content

_from_bytes() doesn't validate binary input — invalid bytes accepted silently #110

Description

@sumanjeet0012

Multiaddr._from_bytes() stores raw bytes without any validation. Invalid binary multiaddrs are accepted silently and only fail later when __str__() or other methods try to parse them. This makes debugging difficult and violates the principle of fail-fast.

Problem

In multiaddr/multiaddr.py:

def _from_bytes(self, addr: bytes) -> None:
    if not addr:
        self._bytes = b""
        return
    self._bytes = addr    # ← No validation at all!

This means:

# These all succeed without error:
Multiaddr(b'\xff\xff\xff')           # Invalid varint
Multiaddr(b'\x99\x01\x00')          # Unknown protocol code 0x99
Multiaddr(b'\x04\x04\x01\x02')      # ip4 with only 3 bytes of address (needs 4)

# They only fail later:
str(Multiaddr(b'\xff\xff\xff'))      # BinaryParseError
str(Multiaddr(b'\x99\x01\x00'))      # BinaryParseError: Unknown Protocol

Go's NewMultiaddrBytes() validates immediately:

func NewMultiaddrBytes(b []byte) (a Multiaddr, err error) {
    bytesRead, m, err := readMultiaddr(b)
    if err != nil { return nil, err }
    if bytesRead != len(b) {
        return nil, fmt.Errorf("unexpected extra data. %v bytes leftover", len(b)-bytesRead)
    }
    return m, nil
}

Proposed Solution

Add validation in _from_bytes():

def _from_bytes(self, addr: bytes) -> None:
    if not addr:
        self._bytes = b""
        return

    # Validate by iterating all components
    consumed = 0
    for offset, proto, codec, part_value in bytes_iter(addr):
        consumed = offset + len(proto.vcode)
        if codec.SIZE < 0:
            consumed += len(varint.encode(len(part_value)))
        consumed += len(part_value)

    if consumed != len(addr):
        raise exceptions.BinaryParseError(
            f"unexpected extra data: {len(addr) - consumed} bytes leftover",
            addr,
            0,
        )

    self._bytes = addr

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions