VYPR
High severity8.8NVD Advisory· Published May 25, 2017· Updated May 13, 2026

CVE-2014-0225

CVE-2014-0225

Description

When processing user provided XML documents, the Spring Framework 4.0.0 to 4.0.4, 3.0.0 to 3.2.8, and possibly earlier unsupported versions did not disable by default the resolution of URI references in a DTD declaration. This enabled an XXE attack.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.springframework:spring-webmvcMaven
>= 4.0.0, < 4.0.54.0.5
org.springframework:spring-webmvcMaven
>= 3.0.0, < 3.2.83.2.8

Affected products

35
  • Pivotal/Spring Frameworkv5
    Range: 4.0.0 to 4.0.4
  • cpe:2.3:a:vmware:spring_framework:3.0.3:*:*:*:*:*:*:*+ 29 more
    • cpe:2.3:a:vmware:spring_framework:3.0.3:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.0.4:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.0.5:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.0.6:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.0.7:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.1.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.1.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.1.1:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.1.2:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.1.4:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.0:rc2-a:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.1:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.2:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.1.3:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.3:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.4:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.5:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.6:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.7:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:3.2.8:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:4.0.0:rc1:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:4.0.0:rc2:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:4.0.1:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:4.0.2:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:4.0.3:*:*:*:*:*:*:*
    • cpe:2.3:a:vmware:spring_framework:4.0.4:*:*:*:*:*:*:*
  • cpe:2.3:a:pivotal_software:spring_framework:3.0.0:*:*:*:*:*:*:*+ 3 more
    • cpe:2.3:a:pivotal_software:spring_framework:3.0.0:*:*:*:*:*:*:*
    • cpe:2.3:a:pivotal_software:spring_framework:3.1.0:*:*:*:*:*:*:*
    • cpe:2.3:a:pivotal_software:spring_framework:3.2.0:*:*:*:*:*:*:*
    • cpe:2.3:a:pivotal_software:spring_framework:4.0.0:*:*:*:*:*:*:*

Patches

3
8e096aeef552

Disable URL resolution in DTD declarations

https://github.com/spring-projects/spring-frameworkRossen StoyanchevMay 20, 2014via ghsa
7 files changed · +88 8
  • spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java+14 1 modified
    @@ -21,6 +21,7 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.OutputStream;
    +import java.io.StringReader;
     import java.io.UnsupportedEncodingException;
     import java.lang.reflect.GenericArrayType;
     import java.lang.reflect.ParameterizedType;
    @@ -72,6 +73,7 @@
     import org.apache.commons.logging.Log;
     import org.apache.commons.logging.LogFactory;
     import org.w3c.dom.ls.LSResourceResolver;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -806,7 +808,11 @@ else if (streamSource.getReader() != null) {
     			if (xmlReader == null) {
     				xmlReader = XMLReaderFactory.createXMLReader();
     			}
    -			xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
    +			String name = "http://xml.org/sax/features/external-general-entities";
    +			xmlReader.setFeature(name, isProcessExternalEntities());
    +			if (!isProcessExternalEntities()) {
    +				xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			return new SAXSource(xmlReader, inputSource);
     		}
     		catch (SAXException ex) {
    @@ -1019,4 +1025,11 @@ public String getName() {
     		}
     	}
     
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java+13 0 modified
    @@ -20,6 +20,7 @@
     import java.io.InputStream;
     import java.io.OutputStream;
     import java.io.Reader;
    +import java.io.StringReader;
     import java.io.Writer;
     import javax.xml.parsers.DocumentBuilder;
     import javax.xml.parsers.DocumentBuilderFactory;
    @@ -43,6 +44,7 @@
     import org.w3c.dom.Document;
     import org.w3c.dom.Node;
     import org.xml.sax.ContentHandler;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -156,6 +158,9 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
     	protected XMLReader createXmlReader() throws SAXException {
     		XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     		xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
    +		if (!isProcessExternalEntities()) {
    +			xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +		}
     		return xmlReader;
     	}
     
    @@ -545,4 +550,12 @@ protected abstract Object unmarshalInputStream(InputStream inputStream)
     	protected abstract Object unmarshalReader(Reader reader)
     			throws XmlMappingException, IOException;
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java+11 0 modified
    @@ -16,6 +16,7 @@
     
     package org.springframework.http.converter.xml;
     
    +import java.io.ByteArrayInputStream;
     import java.io.IOException;
     import java.lang.reflect.ParameterizedType;
     import java.lang.reflect.Type;
    @@ -32,6 +33,7 @@
     import javax.xml.bind.annotation.XmlRootElement;
     import javax.xml.bind.annotation.XmlType;
     import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLResolver;
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.transform.Result;
    @@ -230,7 +232,16 @@ protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOE
     	protected XMLInputFactory createXmlInputFactory() {
     		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
     		inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
    +		inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
     		return inputFactory;
     	}
     
    +
    +	private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
    +		@Override
    +		public Object resolveEntity(String publicID, String systemID, String base, String ns) {
    +			return new ByteArrayInputStream(new byte[0]);
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java+18 1 modified
    @@ -17,6 +17,7 @@
     package org.springframework.http.converter.xml;
     
     import java.io.IOException;
    +import java.io.StringReader;
     import javax.xml.bind.JAXBElement;
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.MarshalException;
    @@ -38,6 +39,7 @@
     import org.springframework.http.converter.HttpMessageNotReadableException;
     import org.springframework.http.converter.HttpMessageNotWritableException;
     import org.springframework.util.ClassUtils;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -67,6 +69,10 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
     		this.processExternalEntities = processExternalEntities;
     	}
     
    +	public boolean isProcessExternalEntities() {
    +		return this.processExternalEntities;
    +	}
    +
     	@Override
     	public boolean canRead(Class<?> clazz, MediaType mediaType) {
     		return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
    @@ -113,7 +119,10 @@ protected Source processSource(Source source) {
     			try {
     				XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     				String featureName = "http://xml.org/sax/features/external-general-entities";
    -				xmlReader.setFeature(featureName, this.processExternalEntities);
    +				xmlReader.setFeature(featureName, isProcessExternalEntities());
    +				if (!isProcessExternalEntities()) {
    +					xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +				}
     				return new SAXSource(xmlReader, inputSource);
     			}
     			catch (SAXException ex) {
    @@ -148,4 +157,12 @@ private void setCharset(MediaType contentType, Marshaller marshaller) throws Pro
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java+30 4 modified
    @@ -20,12 +20,14 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.OutputStream;
    +import java.io.StringReader;
     import java.util.HashSet;
     import java.util.Set;
     import javax.xml.parsers.DocumentBuilder;
     import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLResolver;
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.transform.Result;
    @@ -39,6 +41,7 @@
     import javax.xml.transform.stream.StreamSource;
     
     import org.w3c.dom.Document;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -136,8 +139,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
     			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
     			documentBuilderFactory.setNamespaceAware(true);
     			documentBuilderFactory.setFeature(
    -					"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
    +					"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
     			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    +			if (!isProcessExternalEntities()) {
    +				documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			Document document = documentBuilder.parse(body);
     			return new DOMSource(document);
     		}
    @@ -152,9 +158,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
     	private SAXSource readSAXSource(InputStream body) throws IOException {
     		try {
     			XMLReader reader = XMLReaderFactory.createXMLReader();
    -			reader.setFeature(
    -					"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
    +			reader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
     			byte[] bytes = StreamUtils.copyToByteArray(body);
    +			if (!isProcessExternalEntities()) {
    +				reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
     		}
     		catch (SAXException ex) {
    @@ -165,7 +173,10 @@ private SAXSource readSAXSource(InputStream body) throws IOException {
     	private Source readStAXSource(InputStream body) {
     		try {
     			XMLInputFactory inputFactory = XMLInputFactory.newFactory();
    -			inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, this.processExternalEntities);
    +			inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities());
    +			if (!isProcessExternalEntities()) {
    +				inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
    +			}
     			XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body);
     			return new StAXSource(streamReader);
     		}
    @@ -231,4 +242,19 @@ public void write(byte[] b, int off, int len) throws IOException {
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
    +	private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
    +		@Override
    +		public Object resolveEntity(String publicID, String systemID, String base, String ns) {
    +			return new ByteArrayInputStream(new byte[0]);
    +		}
    +	};
    +
     }
    
  • spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java+1 1 modified
    @@ -110,7 +110,7 @@ public void readXmlType() throws Exception {
     	@Test
     	public void readXmlRootElementExternalEntityDisabled() throws Exception {
     		Resource external = new ClassPathResource("external.txt", getClass());
    -		String content =  "<!DOCTYPE root [" +
    +		String content =  "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
     				"  <!ELEMENT external ANY >\n" +
     				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
     				"  <rootElement><external>&ext;</external></rootElement>";
    
  • spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java+1 1 modified
    @@ -66,7 +66,7 @@ public void setUp() throws IOException {
     		converter = new SourceHttpMessageConverter<Source>();
     		Resource external = new ClassPathResource("external.txt", getClass());
     
    -		bodyExternal = "<!DOCTYPE root [" +
    +		bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
     				"  <!ELEMENT root ANY >\n" +
     				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>";
     	}
    
c6503ebbf7c9

Disable URL resolution in DTD declarations

https://github.com/spring-projects/spring-frameworkRossen StoyanchevMay 20, 2014via ghsa
7 files changed · +85 6
  • spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java+15 1 modified
    @@ -21,6 +21,7 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.OutputStream;
    +import java.io.StringReader;
     import java.io.UnsupportedEncodingException;
     import java.lang.reflect.GenericArrayType;
     import java.lang.reflect.ParameterizedType;
    @@ -70,6 +71,7 @@
     import org.apache.commons.logging.Log;
     import org.apache.commons.logging.LogFactory;
     import org.w3c.dom.ls.LSResourceResolver;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -800,7 +802,11 @@ else if (streamSource.getReader() != null) {
     			if (xmlReader == null) {
     				xmlReader = XMLReaderFactory.createXMLReader();
     			}
    -			xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
    +			String name = "http://xml.org/sax/features/external-general-entities";
    +			xmlReader.setFeature(name, isProcessExternalEntities());
    +			if (!isProcessExternalEntities()) {
    +				xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			return new SAXSource(xmlReader, inputSource);
     		}
     		catch (SAXException ex) {
    @@ -1009,4 +1015,12 @@ public String getName() {
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java+13 0 modified
    @@ -20,6 +20,7 @@
     import java.io.InputStream;
     import java.io.OutputStream;
     import java.io.Reader;
    +import java.io.StringReader;
     import java.io.Writer;
     import javax.xml.parsers.DocumentBuilder;
     import javax.xml.parsers.DocumentBuilderFactory;
    @@ -42,6 +43,7 @@
     import org.apache.commons.logging.LogFactory;
     import org.w3c.dom.Node;
     import org.xml.sax.ContentHandler;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -134,6 +136,9 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
     	protected XMLReader createXmlReader() throws SAXException {
     		XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     		xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
    +		if (!isProcessExternalEntities()) {
    +			xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +		}
     		return xmlReader;
     	}
     
    @@ -545,4 +550,12 @@ protected abstract Object unmarshalInputStream(InputStream inputStream)
     	protected abstract Object unmarshalReader(Reader reader)
     			throws XmlMappingException, IOException;
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java+11 0 modified
    @@ -16,6 +16,7 @@
     
     package org.springframework.http.converter.xml;
     
    +import java.io.ByteArrayInputStream;
     import java.io.IOException;
     import java.lang.reflect.ParameterizedType;
     import java.lang.reflect.Type;
    @@ -32,6 +33,7 @@
     import javax.xml.bind.annotation.XmlRootElement;
     import javax.xml.bind.annotation.XmlType;
     import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLResolver;
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.transform.Result;
    @@ -226,7 +228,16 @@ protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOE
     	protected XMLInputFactory createXmlInputFactory() {
     		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
     		inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
    +		inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
     		return inputFactory;
     	}
     
    +
    +	private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
    +		@Override
    +		public Object resolveEntity(String publicID, String systemID, String base, String ns) {
    +			return new ByteArrayInputStream(new byte[0]);
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java+18 1 modified
    @@ -17,6 +17,7 @@
     package org.springframework.http.converter.xml;
     
     import java.io.IOException;
    +import java.io.StringReader;
     import javax.xml.bind.JAXBElement;
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.MarshalException;
    @@ -38,6 +39,7 @@
     import org.springframework.http.converter.HttpMessageNotReadableException;
     import org.springframework.http.converter.HttpMessageNotWritableException;
     import org.springframework.util.ClassUtils;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -66,6 +68,10 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
     		this.processExternalEntities = processExternalEntities;
     	}
     
    +	public boolean isProcessExternalEntities() {
    +		return this.processExternalEntities;
    +	}
    +
     
     	@Override
     	public boolean canRead(Class<?> clazz, MediaType mediaType) {
    @@ -113,7 +119,10 @@ protected Source processSource(Source source) {
     			try {
     				XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     				String featureName = "http://xml.org/sax/features/external-general-entities";
    -				xmlReader.setFeature(featureName, this.processExternalEntities);
    +				xmlReader.setFeature(featureName, isProcessExternalEntities());
    +				if (!isProcessExternalEntities()) {
    +					xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +				}
     				return new SAXSource(xmlReader, inputSource);
     			}
     			catch (SAXException ex) {
    @@ -148,4 +157,12 @@ private void setCharset(MediaType contentType, Marshaller marshaller) throws Pro
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java+26 2 modified
    @@ -20,11 +20,13 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.OutputStream;
    +import java.io.StringReader;
     import java.util.HashSet;
     import java.util.Set;
     import javax.xml.parsers.DocumentBuilder;
     import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
    +import javax.xml.stream.XMLResolver;
     import javax.xml.transform.Result;
     import javax.xml.transform.Source;
     import javax.xml.transform.TransformerException;
    @@ -35,6 +37,7 @@
     import javax.xml.transform.stream.StreamSource;
     
     import org.w3c.dom.Document;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -128,8 +131,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
     			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
     			documentBuilderFactory.setNamespaceAware(true);
     			documentBuilderFactory.setFeature(
    -					"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
    +					"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
     			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    +			if (!isProcessExternalEntities()) {
    +				documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			Document document = documentBuilder.parse(body);
     			return new DOMSource(document);
     		}
    @@ -145,8 +151,11 @@ private SAXSource readSAXSource(InputStream body) throws IOException {
     		try {
     			XMLReader reader = XMLReaderFactory.createXMLReader();
     			reader.setFeature(
    -					"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
    +					"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
     			byte[] bytes = StreamUtils.copyToByteArray(body);
    +			if (!isProcessExternalEntities()) {
    +				reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
     		}
     		catch (SAXException ex) {
    @@ -211,4 +220,19 @@ public void write(byte[] b, int off, int len) throws IOException {
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
    +	private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
    +		@Override
    +		public Object resolveEntity(String publicID, String systemID, String base, String ns) {
    +			return new ByteArrayInputStream(new byte[0]);
    +		}
    +	};
    +
     }
    
  • spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTest.java+1 1 modified
    @@ -100,7 +100,7 @@ public void readXmlType() throws Exception {
     	@Test
     	public void readXmlRootElementExternalEntityDisabled() throws Exception {
     		Resource external = new ClassPathResource("external.txt", getClass());
    -		String content =  "<!DOCTYPE root [" +
    +		String content =  "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
     				"  <!ELEMENT external ANY >\n" +
     				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
     				"  <rootElement><external>&ext;</external></rootElement>";
    
  • spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java+1 1 modified
    @@ -63,7 +63,7 @@ public class SourceHttpMessageConverterTests {
     	public void setUp() throws IOException {
     		converter = new SourceHttpMessageConverter<Source>();
     		Resource external = new ClassPathResource("external.txt", getClass());
    -		bodyExternal = "<!DOCTYPE root [" +
    +		bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
     				"  <!ELEMENT root ANY >\n" +
     				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>";
     	}
    
44ee51a6c9c3

Disable URL resolution in DTD declarations

https://github.com/spring-projects/spring-frameworkRossen StoyanchevMay 20, 2014via ghsa
7 files changed · +88 8
  • spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java+14 1 modified
    @@ -21,6 +21,7 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.OutputStream;
    +import java.io.StringReader;
     import java.io.UnsupportedEncodingException;
     import java.lang.reflect.GenericArrayType;
     import java.lang.reflect.ParameterizedType;
    @@ -72,6 +73,7 @@
     import org.apache.commons.logging.Log;
     import org.apache.commons.logging.LogFactory;
     import org.w3c.dom.ls.LSResourceResolver;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -806,7 +808,11 @@ else if (streamSource.getReader() != null) {
     			if (xmlReader == null) {
     				xmlReader = XMLReaderFactory.createXMLReader();
     			}
    -			xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
    +			String name = "http://xml.org/sax/features/external-general-entities";
    +			xmlReader.setFeature(name, isProcessExternalEntities());
    +			if (!isProcessExternalEntities()) {
    +				xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			return new SAXSource(xmlReader, inputSource);
     		}
     		catch (SAXException ex) {
    @@ -1019,4 +1025,11 @@ public String getName() {
     		}
     	}
     
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java+13 0 modified
    @@ -20,6 +20,7 @@
     import java.io.InputStream;
     import java.io.OutputStream;
     import java.io.Reader;
    +import java.io.StringReader;
     import java.io.Writer;
     import javax.xml.parsers.DocumentBuilder;
     import javax.xml.parsers.DocumentBuilderFactory;
    @@ -43,6 +44,7 @@
     import org.w3c.dom.Document;
     import org.w3c.dom.Node;
     import org.xml.sax.ContentHandler;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -156,6 +158,9 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
     	protected XMLReader createXmlReader() throws SAXException {
     		XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     		xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
    +		if (!isProcessExternalEntities()) {
    +			xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +		}
     		return xmlReader;
     	}
     
    @@ -545,4 +550,12 @@ protected abstract Object unmarshalInputStream(InputStream inputStream)
     	protected abstract Object unmarshalReader(Reader reader)
     			throws XmlMappingException, IOException;
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java+11 0 modified
    @@ -16,6 +16,7 @@
     
     package org.springframework.http.converter.xml;
     
    +import java.io.ByteArrayInputStream;
     import java.io.IOException;
     import java.lang.reflect.ParameterizedType;
     import java.lang.reflect.Type;
    @@ -32,6 +33,7 @@
     import javax.xml.bind.annotation.XmlRootElement;
     import javax.xml.bind.annotation.XmlType;
     import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLResolver;
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.transform.Result;
    @@ -230,7 +232,16 @@ protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOE
     	protected XMLInputFactory createXmlInputFactory() {
     		XMLInputFactory inputFactory = XMLInputFactory.newInstance();
     		inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
    +		inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
     		return inputFactory;
     	}
     
    +
    +	private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
    +		@Override
    +		public Object resolveEntity(String publicID, String systemID, String base, String ns) {
    +			return new ByteArrayInputStream(new byte[0]);
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java+18 1 modified
    @@ -17,6 +17,7 @@
     package org.springframework.http.converter.xml;
     
     import java.io.IOException;
    +import java.io.StringReader;
     import javax.xml.bind.JAXBElement;
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.MarshalException;
    @@ -38,6 +39,7 @@
     import org.springframework.http.converter.HttpMessageNotReadableException;
     import org.springframework.http.converter.HttpMessageNotWritableException;
     import org.springframework.util.ClassUtils;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -67,6 +69,10 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
     		this.processExternalEntities = processExternalEntities;
     	}
     
    +	public boolean isProcessExternalEntities() {
    +		return this.processExternalEntities;
    +	}
    +
     	@Override
     	public boolean canRead(Class<?> clazz, MediaType mediaType) {
     		return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
    @@ -113,7 +119,10 @@ protected Source processSource(Source source) {
     			try {
     				XMLReader xmlReader = XMLReaderFactory.createXMLReader();
     				String featureName = "http://xml.org/sax/features/external-general-entities";
    -				xmlReader.setFeature(featureName, this.processExternalEntities);
    +				xmlReader.setFeature(featureName, isProcessExternalEntities());
    +				if (!isProcessExternalEntities()) {
    +					xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +				}
     				return new SAXSource(xmlReader, inputSource);
     			}
     			catch (SAXException ex) {
    @@ -148,4 +157,12 @@ private void setCharset(MediaType contentType, Marshaller marshaller) throws Pro
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
     }
    
  • spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java+30 4 modified
    @@ -20,12 +20,14 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.OutputStream;
    +import java.io.StringReader;
     import java.util.HashSet;
     import java.util.Set;
     import javax.xml.parsers.DocumentBuilder;
     import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLResolver;
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.transform.Result;
    @@ -39,6 +41,7 @@
     import javax.xml.transform.stream.StreamSource;
     
     import org.w3c.dom.Document;
    +import org.xml.sax.EntityResolver;
     import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     import org.xml.sax.XMLReader;
    @@ -136,8 +139,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
     			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
     			documentBuilderFactory.setNamespaceAware(true);
     			documentBuilderFactory.setFeature(
    -					"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
    +					"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
     			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    +			if (!isProcessExternalEntities()) {
    +				documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			Document document = documentBuilder.parse(body);
     			return new DOMSource(document);
     		}
    @@ -152,9 +158,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
     	private SAXSource readSAXSource(InputStream body) throws IOException {
     		try {
     			XMLReader reader = XMLReaderFactory.createXMLReader();
    -			reader.setFeature(
    -					"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
    +			reader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
     			byte[] bytes = StreamUtils.copyToByteArray(body);
    +			if (!isProcessExternalEntities()) {
    +				reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
    +			}
     			return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
     		}
     		catch (SAXException ex) {
    @@ -165,7 +173,10 @@ private SAXSource readSAXSource(InputStream body) throws IOException {
     	private Source readStAXSource(InputStream body) {
     		try {
     			XMLInputFactory inputFactory = XMLInputFactory.newFactory();
    -			inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, this.processExternalEntities);
    +			inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities());
    +			if (!isProcessExternalEntities()) {
    +				inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
    +			}
     			XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body);
     			return new StAXSource(streamReader);
     		}
    @@ -231,4 +242,19 @@ public void write(byte[] b, int off, int len) throws IOException {
     		}
     	}
     
    +
    +	private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
    +		@Override
    +		public InputSource resolveEntity(String publicId, String systemId) {
    +			return new InputSource(new StringReader(""));
    +		}
    +	};
    +
    +	private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
    +		@Override
    +		public Object resolveEntity(String publicID, String systemID, String base, String ns) {
    +			return new ByteArrayInputStream(new byte[0]);
    +		}
    +	};
    +
     }
    
  • spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java+1 1 modified
    @@ -110,7 +110,7 @@ public void readXmlType() throws Exception {
     	@Test
     	public void readXmlRootElementExternalEntityDisabled() throws Exception {
     		Resource external = new ClassPathResource("external.txt", getClass());
    -		String content =  "<!DOCTYPE root [" +
    +		String content =  "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
     				"  <!ELEMENT external ANY >\n" +
     				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
     				"  <rootElement><external>&ext;</external></rootElement>";
    
  • spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java+1 1 modified
    @@ -66,7 +66,7 @@ public void setUp() throws IOException {
     		converter = new SourceHttpMessageConverter<Source>();
     		Resource external = new ClassPathResource("external.txt", getClass());
     
    -		bodyExternal = "<!DOCTYPE root [" +
    +		bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
     				"  <!ELEMENT root ANY >\n" +
     				"  <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>";
     	}
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.