Apache Struts2 JSON Plugin Insecure Deserialisation -- Object Deserialisation Element-Count Limit Bypass
Full Disclosuremailing list archivesFrom: Daniel Owens via Fulldisclosure <fulld 2026-11-2 06:10:46 Author: seclists.org(查看原文) 阅读量:17 收藏

fulldisclosure logo

Full Disclosure mailing list archives


From: Daniel Owens via Fulldisclosure <fulldisclosure () seclists org>
Date: Thu, 29 Oct 2026 11:16:48 +0000

As of the current versions of the Apache Struts2 JSON Plugin (e.g., version 7.4.0 and the 7.5.0 snapshot dated 28 
October 2026), attackers can bypass the element-count limit purported to protect Object deserialisation added to said 
code as part of the WW-5618 and S2-072 "hardening controls".  Please note that this vulnerability and the attack string 
is different than the previously reported bypass against the JSON array deserialisation, which was discussed in detail 
via "Continued Apache Struts2 JSON Plugin Insecure Deserialisation" (28 October 2026) and "Maximised JSON Array Attacks 
-- "Let the Commas Hit the Floor" Proof of Concept" (28 October 2026).  Said previous discussions pertained strictly to 
bypassing protections on array deserialisation, with distinct code paths, mistakes, and attack strings.

Description:
The information system's JavaScript Object Notation (JSON) object parser enforces the `maxElements` resource limit by 
checking the size of the `HashMap` being populated rather than by counting the number of key-value pairs actually being 
parsed, so a payload consisting of entirely repeated keys never grows the map past a single entry while incurring both 
memory and compute costs.

Impact:
An attacker who can send a request body to any endpoint protected by a `JSONInterceptor` configured with a 
`maxElements` ceiling (including the default value) can construct a JSON object consisting of an arbitrarily large 
number of duplicate-key pairs -- for example, the same key repeated hundreds of thousands of times -- bounded only by 
the value of `struts.json.maxLength`, and have every pair be fully parsed, hashed, and boxed before the `maxElements` 
check ever has a chance to trip since `Map.put(Object, Object)` with an already-present key never increases the value 
`ret.size()`.


Attackers can force disproportionate CPU and allocation work, memory usage (similar to that discussed in "Continued 
Apache Struts2 JSON Plugin Insecure Deserialisation" (28 October 2026) and "Maximised JSON Array Attacks -- "Let the 
Commas Hit the Floor" Proof of Concept" (28 October 2026)) with a single request and exhaust server resources across 
concurrent requests.  For example, attackers can build a single object containing 262,143 String-Double key-value pairs 
(only limited by `struts.json.maxLength`, to a 2MB string), with a single request consuming over 46MB and taking ~37ms 
to parse and build on a pre-warmed system (assume 64-bit HotSpot JVM running with compressed oops and 8-byte alignment, 
which is a standard configuration).  Making several concurrent requests of such a nature can quickly create denial of 
service conditions.



Examples:

Sample Vulnerable Code

`StrutsJSONReader.object()` in the `struts2-json-plugin` module, enforces the `maxElements` ceiling by comparing the 
size of the `HashMap` being populated against the limit immediately before every `put(Object, Object)` call, as shown 
below.



```java

    protected Map<String, Object> object() throws JSONException {

        if (this.depth >= this.maxDepth) {

            throw new JSONException("JSON object nesting exceeds maximum allowed depth ("

                    + this.maxDepth + "). Use " + JSONConstants.JSON_MAX_DEPTH + " to increase the limit.");

        }

        this.depth++;

        try {

            Map<String, Object> ret = new HashMap<>();

            Object next = this.read();

            if (next != OBJECT_END) {

                String key = (String) next;

                validateKeyLength(key);

                while (this.token != OBJECT_END) {

                    this.read(); // should be a colon



                    if (this.token != OBJECT_END) {

                        if (ret.size() >= this.maxElements) {

                            throw new JSONException("JSON object exceeds maximum allowed elements ("

                                    + this.maxElements + "). Use " + JSONConstants.JSON_MAX_ELEMENTS + " to increase 
the limit.");

                        }

                        ret.put(key, this.read());



                        if (this.read() == COMMA) {

                            Object name = this.read();



                            if (name instanceof String nextKey) {

                                key = nextKey;

                                validateKeyLength(key);

                            } else {

                                throw buildInvalidInputException();

                            }

                        }

                    }

                }

            }



            return ret;

        } finally {

            this.depth--;

        }

    }

```

Code snippet from `struts-2-json-plugin`'s plugins/json/src/main/java/org/apache/struts2/json/StrutsJSONReader.java, 
lines 156-196



Importantly, attackers can further couple this with the previously disclosed Apache Struts2 JSON Plugin `maxElements` 
bypass in the `array()` method in the same class (please see the aforementioned Full Disclosure postings for details).  
While attackers can choose from a variety of Objects, `Double` is the most damaging for this particular attack since 
they incur the cost of building and boxing/unboxing and are never cached (unlike `Long` and `String` objects).
_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: https://seclists.org/fulldisclosure/


Current thread:

  • Apache Struts2 JSON Plugin Insecure Deserialisation -- Object Deserialisation Element-Count Limit Bypass Daniel Owens via Fulldisclosure (Nov 01)

文章来源: https://seclists.org/fulldisclosure/2026/Nov/0
如有侵权请联系:admin#unsafe.sh