CIDv0.__init__() accepts any multihash without validation. Per the CID specification, CIDv0 must use sha2-256 with a 32-byte digest. Go's tryNewCidV0() enforces this constraint; Python does not.
Problem
In cid/cid.py:
class CIDv0(BaseCID):
CODEC = "dag-pb"
def __init__(self, multihash: str | bytes) -> None:
super().__init__(0, self.CODEC, multihash)
# ← No validation of the multihash!
This allows creating invalid CIDv0 objects:
import hashlib
import multihash
# Using sha3-512 instead of sha2-256 — invalid for CIDv0!
digest = hashlib.sha3_512(b"hello").digest()
mh = multihash.encode(digest, "sha3-512")
cid = CIDv0(mh) # ← Succeeds, but produces invalid CIDv0
# Using sha2-256 with truncated digest — also invalid!
digest = hashlib.sha256(b"hello").digest()[:16]
mh = multihash.encode(digest, "sha2-256", 16)
cid = CIDv0(mh) # ← Succeeds, but digest is only 16 bytes
Go's implementation validates:
func tryNewCidV0(mhash mh.Multihash) (Cid, error) {
dec, err := mh.Decode(mhash)
if err != nil {
return Undef, ErrInvalidCid{err}
}
if dec.Code != mh.SHA2_256 || dec.Length != 32 {
return Undef, ErrInvalidCid{
fmt.Errorf("invalid hash for cidv0 %d-%d", dec.Code, dec.Length)}
}
return Cid{string(mhash)}, nil
}
Proposed Solution
Add validation to CIDv0.__init__():
class CIDv0(BaseCID):
CODEC = "dag-pb"
def __init__(self, multihash: str | bytes) -> None:
multihash = ensure_bytes(multihash)
# Validate multihash is sha2-256 with 32-byte digest
try:
mh_info = mh.decode(multihash)
except Exception as e:
raise ValueError(f"invalid multihash for CIDv0: {e}") from e
if mh_info.code != 0x12 or mh_info.length != 32:
raise ValueError(
f"invalid hash for CIDv0: must be sha2-256 with 32-byte digest, "
f"got {mh_info.name} with {mh_info.length}-byte digest"
)
super().__init__(0, self.CODEC, multihash)
Add tests:
def test_cidv0_rejects_non_sha256():
digest = hashlib.sha3_512(b"hello").digest()
mh_bytes = multihash.encode(digest, "sha3-512")
with pytest.raises(ValueError, match="must be sha2-256"):
CIDv0(mh_bytes)
def test_cidv0_rejects_truncated_digest():
digest = hashlib.sha256(b"hello").digest()[:16]
mh_bytes = multihash.encode(digest, "sha2-256", 16)
with pytest.raises(ValueError, match="32-byte digest"):
CIDv0(mh_bytes)
Related
CIDv0.__init__()accepts any multihash without validation. Per the CID specification, CIDv0 must use sha2-256 with a 32-byte digest. Go'stryNewCidV0()enforces this constraint; Python does not.Problem
In
cid/cid.py:This allows creating invalid CIDv0 objects:
Go's implementation validates:
Proposed Solution
Add validation to
CIDv0.__init__():Add tests:
Related
cid.gotryNewCidV0()cid/cid.py