CVE-2021-23463 (Java, published 2021-12-10T20:15Z)
Description: value: The package com.h2database:h2 from 1.4.198 and before 2.0.202 are vulnerable to XML External Entity (XXE) Injection via the org.h2.jdbc.JdbcSQLXML class object, when it receives parsed string data from org.h2.jdbc.JdbcResultSet.getSQLXML() method. If it executes the getSource() method when the parameter is DOMSource.class it will trigger the vulnerability.
Severity: MEDIUM (CVSS v3 base score: 9.1)
Weakness: CWE-611 \u2014 Improper Restriction of XML External Entity Reference
The product processes an XML document that can contain XML entities with URIs that resolve to documents outside of the intended sphere of control, causing the product to embed incorrect documents into its output.
Repository: https://github.com/h2database/h2database
Files changed:
h2/src/main/org/h2/jdbc/JdbcSQLXML.java
Commit message: fix for #3195 CQLXML XXE vulnerability


Vulnerable code:
                return (T) new DOMSource(dbf.newDocumentBuilder().parse(new InputSource(value.getInputStream())));
                return (T) new SAXSource(new InputSource(value.getInputStream()));
                        "getSource(" + (resultClass != null ? resultClass.getSimpleName() + ".class" : "null") + ')');

Fixed code:
import java.util.HashMap;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.URIResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
    private static final Map<String,Boolean> secureFeatureMap = new HashMap<>();
    private static final EntityResolver NOOP_ENTITY_RESOLVER = (publicId, systemId) -> new InputSource(new StringReader(""));
    private static final URIResolver NOOP_URI_RESOLVER = (href, base) -> new StreamSource(new StringReader(""));

    static {
        secureFeatureMap.put(XMLConstants.FEATURE_SECURE_PROCESSING, true);
        secureFeatureMap.put("http://apache.org/xml/features/disallow-doctype-decl", true);
        secureFeatureMap.put("http://xml.org/sax/features/external-general-entities", false);
        secureFeatureMap.put("http://xml.org/sax/features/external-parameter-entities", false);
        secureFeatureMap.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    }

            // According to https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
                for (Map.Entry<String,Boolean> entry : secureFeatureMap.entrySet()) {
                    try {
                        dbf.setFeature(entry.getKey(), entry.getValue());
                    } catch (Exception ignore) {/**/}
                }
                dbf.setXIncludeAware(false);
                dbf.setExpandEntityReferences(false);
                dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
                DocumentBuilder db = dbf.newDocumentBuilder();
                db.setEntityResolver(NOOP_ENTITY_RESOLVER);
                return (T) new DOMSource(db.parse(new InputSource(value.getInputStream())));
                XMLReader reader = XMLReaderFactory.createXMLReader();
                for (Map.Entry<String,Boolean> entry : secureFeatureMap.entrySet()) {
                    try {
                        reader.setFeature(entry.getKey(), entry.getValue());
                    } catch (Exception ignore) {/**/}
                }
                reader.setEntityResolver(NOOP_ENTITY_RESOLVER);
                return (T) new SAXSource(reader, new InputSource(value.getInputStream()));
                xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
                xif.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
                xif.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
                TransformerFactory tf = TransformerFactory.newInstance();
                tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
                tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
                tf.setURIResolver(NOOP_URI_RESOLVER);
                tf.newTransformer().transform(new StreamSource(value.getInputStream()), new SAXResult(new DefaultHandler()));
                        "setResult(" + (resultClass != null ? resultClass.getSimpleName() + ".class" : "null") + ')');