Skip to content

v2 to master - #2295

Merged
AArnott merged 32 commits into
masterfrom
v2-to-master
Sep 3, 2026
Merged

AArnott merged 32 commits into
masterfrom
v2-to-master

Conversation

@AArnott

@AArnott AArnott commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

This is a deliberate no-op merge to resolve conflicts going forward, since master already has the same semantic commits as v2.x

AArnott and others added 30 commits April 9, 2025 14:32
Update DynamicAssembly usage to honor different AssemblyLoadContext's
…zation

Add more types to the default disallow list of named types to be deserialized
The LZ4 block decoder accepted only the destination length and advanced through the compressed input without knowing where the source buffer ended. Malformed compressed payloads could therefore drive unchecked native reads before the existing post-decode length check ran.

Pass the compressed input length into the 32-bit and 64-bit decoders and reject malformed blocks before token, literal, offset, and match-length reads would move past the source buffer. Add a regression test that verifies malformed LZ4 data fails as a normal serialization exception.
InterfaceLookupFormatter created its intermediate Dictionary with the default comparer, so ILookup<TKey,TElement> deserialization did not honor MessagePackSecurity.UntrustedData hash-collision resistance.

Pass the security-provided equality comparer into the intermediate dictionary and add regression coverage that verifies colliding long keys use the hardened comparer.
Multidimensional array deserialization trusted dimension values and allocated arrays before confirming that the flattened element count matched the serialized element array header. This could let malformed data request disproportionate allocations before validation.

Validate non-negative dimensions and checked flattened lengths for 2D, 3D, and 4D array formatters before allocation, and add regression coverage for mismatched element counts under untrusted data options.
ConvertFromJson now applies the configured MessagePackSecurity maximum object graph depth while translating nested JSON objects and arrays, preventing deeply nested input from recursing until stack exhaustion.

Added a bounded regression test that verifies over-depth JSON is rejected for both compressed and uncompressed conversion paths.
UnsafeBlitFormatter trusted the nested byte count from extension payloads when allocating arrays, even though the surrounding extension length had already bounded the body. Malformed inputs could request allocations that were not supported by the declared extension data.

Parse the extension body through a bounded reader and reject negative, unaligned, or mismatched byte counts before allocating. Add a regression test for the malformed length case.
DynamicUnionResolver emitted deserializers did not count the union formatter frame against MessagePackSecurity's object graph depth budget. That left recursive union values and skipped unknown union payloads less constrained than source-generated unions and dynamic object formatters.

Emit DepthStep after nil handling and decrement reader.Depth before returning, matching the existing dynamic object formatter pattern. Add a regression test proving unknown union payloads respect the depth limit without including exploit payload details.
ConvertToJson recursively expands typeless extension values while composing JSON, but that path was not counted against MessagePackSecurity.MaximumObjectGraphDepth. Deeply nested typeless values could therefore bypass UntrustedData depth checks and exhaust the call stack.

Wrap typeless extension JSON processing in DepthStep/decrement accounting and add regression coverage that expects the configured depth limit to be enforced.
TinyJsonReader previously skipped JSON separators with a recursive ReadNextToken call, so a long separator sequence supplied to ConvertFromJson could consume one stack frame per separator and terminate the process. Change separator skipping to stay within the tokenizer loop instead, preserving the existing tokenization behavior without stack growth.

Add regression coverage that converts a long separator-prefixed JSON value successfully.
Promote map entry count multiplication to long when validating the minimum encoded payload length and when skipping map contents. This keeps oversized malformed map headers on the insufficient-buffer path instead of relying on Int32 arithmetic behavior. Add regression coverage for oversized map headers in ReadMapHeader and Skip.
ExpandoObject map materialization inserts each member through ExpandoObject, whose member table grows with linear scans and array copies. Under the untrusted-data resolver preset, very large maps could consume disproportionate CPU before application code sees the result.

Reject oversized ExpandoObject maps when hash-collision hardening is active, covering both direct ExpandoObject deserialization and nested maps produced by ExpandoObjectResolver. Add focused regression coverage for both paths.
MessagePackInputFormatter handles HTTP request bodies, but its default/null options path fell back to MessagePackSerializerOptions.Standard and therefore TrustedData. That left hash-based model binding without the untrusted-data collision-resistance defaults expected at this trust boundary.

Default null input-formatter options to Standard.WithSecurity(UntrustedData), while preserving caller-supplied options. Add a regression test that verifies the parameterless formatter deserializes dictionary request bodies with the collision-resistant comparer.
The `MessagePackReader` has no concept of a depth limit, and it implemented its `Skip()` method recursively which can easily blow the stack for deeply nested msgpack structures.

Rather than introduce a new API with an adjustable depth limit, set to a 'secure' but otherwise arbitrary default, we can make `Skip()` iterate instead of recurse in order to avoid ever crashing.
Typeless deserialization previously validated only the outer wire-supplied type before resolving a formatter. Container types could therefore hide a disallowed element or generic argument from the mitigation and from custom option overrides.

Validate element and constructed generic argument types before formatter resolution, and add regression coverage for nested typeless disallowed types.
Validate declared LZ4 decompressed block sizes against the compressed block size before requesting an output buffer. This rejects unreasonable Lz4Block and Lz4BlockArray declarations before allocation while preserving normal compressed payload handling.
Before this change, the length of the source span would dictate how large the destination span became and how far we advanced the writer, without any regard to how many bytes would actually be copied into that buffer.
Thanks to @svenclaesson for calling these types out as valuable to block by default.
…types-v2.x

Add several known unsafe 'gadgets' to the disallow list
AArnott and others added 2 commits June 9, 2026 07:46
This is a deliberate no-op merge to resolve conflicts going forward, since master already has the same semantic commits as v2.x
@AArnott AArnott added this to the v3.1 milestone Sep 3, 2026
@AArnott
AArnott enabled auto-merge September 3, 2026 03:04
@AArnott
AArnott merged commit b0e5cee into master Sep 3, 2026
3 checks passed
@AArnott
AArnott deleted the v2-to-master branch September 3, 2026 03:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants