Skip to content

3.3.4

Latest

Choose a tag to compare

@Spomky Spomky released this 31 Aug 19:21
3.3.4
1cac24e

Security

This release fixes three vulnerabilities in the decoding of untrusted CBOR documents. Every version up to and including 3.3.3 is affected. Applications that decode CBOR coming from a network peer, a file or any other untrusted source should upgrade.

GHSA-pf28-pvhp-7mm5 — Unbounded exponent in the BigFloat and DecimalFraction tags (High)

BigFloatTag::normalize() and DecimalFractionTag::normalize() raised 2 (resp. 10) to an exponent read straight from the document, with no upper bound. An eleven byte payload made bcpow() request 103 GB in a single allocation, which kills the process with a fatal error that no try/catch can intercept; under memory_limit=-1 the process instead grinds until the OOM killer stops it. The tag only had to be embedded anywhere in the document, since normalize() recurses into children.

The exponent is now rejected when its absolute value exceeds MAX_ABSOLUTE_EXPONENT (8192), before bcpow() is reached. The bound is far above any legitimate use: 2^8192 already has more than 2400 digits.

GHSA-388j-mw2g-rx5f — Map keys stored as native PHP array offsets (Medium)

Map entries were keyed by $key->normalize() in a native PHP array. A key normalizing to an array — a CBOR list or map, which RFC 8949 permits — raised a TypeError, so a three byte document crashed the decoder. And because PHP casts numeric-string offsets to int, structurally distinct keys silently overwrote one another: the integer 1, the text string "1", the byte string h'31' and the half-precision float 1.0 all landed on the same slot. {1:"A", "1":"B"} decoded to a single entry and get(1) returned the text key's value.

Keys are now tracked with the major type they came from, which separates a genuine duplicate from two distinct keys colliding on one offset. Both are rejected, as are keys that do not normalize to an integer or a string.

GHSA-pjwm-422x-vvh5 — Exceptions outside the documented contract (Medium)

Eight byte length, count and tag headers surfaced a Brick\Math\IntegerOverflowException, and empty bignum payloads a NumberFormatException — the latter because the guard was an assert(), compiled out under the production default zend.assertions=-1 and therefore protecting nothing. Both now raise InvalidArgumentException, like the rest of the library.

Upgrading

The decoder is stricter about maps, which is what closes the second advisory. Documents that are now rejected with an InvalidArgumentException were previously either crashing the parser or being silently mangled, so nothing that genuinely worked before stops working:

  • maps whose keys do not normalize to an integer or a string (lists, maps, floats, booleans, null);
  • maps where two keys of different major types resolve to the same offset;
  • maps carrying the same key twice, per RFC 8949 §5.6.

Building a map programmatically is unaffected: set() and ArrayAccess still replace the value of an existing key.


Release Notes for 3.3.4

3.3.x bugfix release (patch)

3.3.4

  • Total issues resolved: 0
  • Total pull requests resolved: 0
  • Total contributors: 0