Moderate severityNVD Advisory· Published Jan 21, 2015· Updated May 6, 2026
CVE-2014-8152
CVE-2014-8152
Description
Apache Santuario XML Security for Java 2.0.x before 2.0.3 allows remote attackers to bypass the streaming XML signature protection mechanism via a crafted XML document.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.santuario:xmlsecMaven | >= 2.0.0, < 2.0.3 | 2.0.3 |
Affected products
4cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.0:*:*:*:*:*:*:*+ 2 more
- cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.0:*:*:*:*:*:*:*
- cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.1:*:*:*:*:*:*:*
- cpe:2.3:a:apache:santuario_xml_security_for_java:2.0.2:*:*:*:*:*:*:*
Patches
155857fd4cdfdmore signature verification tests
4 files changed · +288 −2
src/main/java/org/apache/xml/security/stax/ext/InputProcessorChain.java+15 −0 modified@@ -72,6 +72,7 @@ public interface InputProcessorChain extends ProcessorChain { /** * Create a new SubChain. The XMLEvents will be only be processed from the given InputProcessor to the end. * All earlier InputProcessors don't get these events. In other words the chain will be splitted in two parts. + * The associated DocumentContext will be cloned. * * @param inputProcessor The InputProcessor position the XMLEvents should be processed over this SubChain. * @return A new InputProcessorChain @@ -80,6 +81,20 @@ public interface InputProcessorChain extends ProcessorChain { */ InputProcessorChain createSubChain(InputProcessor inputProcessor) throws XMLStreamException, XMLSecurityException; + /** + * Create a new SubChain. The XMLEvents will be only be processed from the given InputProcessor to the end. + * All earlier InputProcessors don't get these events. In other words the chain will be splitted in two parts. + * + * The parameter clone controls if the associated DocumentContext should be cloned or reference the existing one. + * + * @param inputProcessor The InputProcessor position the XMLEvents should be processed over this SubChain. + * @param clone if true the associated DocumentContext will be cloned otherwise the DocumentContext will be referenced. + * @return A new InputProcessorChain + * @throws XMLStreamException thrown when a streaming error occurs + * @throws XMLSecurityException thrown when a Security failure occurs + */ + InputProcessorChain createSubChain(InputProcessor inputProcessor, boolean clone) throws XMLStreamException, XMLSecurityException; + /** * Requests the next security header XMLEvent from the next processor in the chain. *
src/main/java/org/apache/xml/security/stax/impl/InputProcessorChainImpl.java+7 −1 modified@@ -200,9 +200,15 @@ public void doFinal() throws XMLStreamException, XMLSecurityException { @Override public InputProcessorChain createSubChain(InputProcessor inputProcessor) throws XMLStreamException, XMLSecurityException { + return createSubChain(inputProcessor, true); + } + + @Override + public InputProcessorChain createSubChain(InputProcessor inputProcessor, boolean clone) throws XMLStreamException, XMLSecurityException { InputProcessorChainImpl inputProcessorChain; try { - inputProcessorChain = new InputProcessorChainImpl(inboundSecurityContext, documentContext.clone(), + final DocumentContextImpl docContext = clone ? documentContext.clone() : documentContext; + inputProcessorChain = new InputProcessorChainImpl(inboundSecurityContext, docContext, inputProcessors.indexOf(inputProcessor) + 1, new ArrayList<InputProcessor>(this.inputProcessors)); } catch (CloneNotSupportedException e) { throw new XMLSecurityException(e);
src/main/java/org/apache/xml/security/stax/impl/processor/input/XMLSecurityInputProcessor.java+5 −1 modified@@ -138,11 +138,15 @@ public XMLSecEvent processNextEvent(InputProcessorChain inputProcessorChain) inputProcessorChain.addProcessor(internalReplayProcessor); //...and let the SignatureVerificationProcessor process the buffered events (enveloped signature). - InputProcessorChain subInputProcessorChain = inputProcessorChain.createSubChain(this); + InputProcessorChain subInputProcessorChain = inputProcessorChain.createSubChain(this, false); while (!xmlSecEventList.isEmpty()) { subInputProcessorChain.reset(); subInputProcessorChain.processEvent(); } + + // copy all processor back to main chain for finalization + inputProcessorChain.getProcessors().clear(); + inputProcessorChain.getProcessors().addAll(subInputProcessorChain.getProcessors()); } break; }
src/test/java/org/apache/xml/security/test/stax/signature/SignatureVerificationTest.java+261 −0 modified@@ -63,6 +63,7 @@ import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; +import org.w3c.dom.Element; /** * A set of test-cases for Signature verification. @@ -1420,4 +1421,264 @@ public void testCustomC14nAlgo() throws Exception { StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader); } + + @Test + public void testPartialSignedDocumentTampered_ContentFirst() throws Exception { + // Read in plaintext document + InputStream sourceDocument = + this.getClass().getClassLoader().getResourceAsStream( + "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml"); + DocumentBuilder builder = XMLUtils.createDocumentBuilder(false); + Document document = builder.parse(sourceDocument); + + // Set up the Key + KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load( + this.getClass().getClassLoader().getResource("transmitter.jks").openStream(), + "default".toCharArray() + ); + Key key = keyStore.getKey("transmitter", "default".toCharArray()); + X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter"); + + // Sign using DOM + List<String> localNames = new ArrayList<String>(); + localNames.add("PaymentInfo"); + XMLSignature sig = signUsingDOM( + "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key + ); + + // Add KeyInfo + sig.addKeyInfo(cert); + + // Now modify the context of PaymentInfo + Element paymentInfoElement = + (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0); + paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US"); + + // Convert Document to a Stream Reader + javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + transformer.transform(new DOMSource(document), new StreamResult(baos)); + final XMLStreamReader xmlStreamReader = + xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())); + + // Verify signature + XMLSecurityProperties properties = new XMLSecurityProperties(); + InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties); + TestSecurityEventListener securityEventListener = new TestSecurityEventListener(); + XMLStreamReader securityStreamReader = + inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener); + + try { + StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader); + fail("Failure expected on a modified document"); + } catch (XMLStreamException ex) { + Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference")); + } + } + + @Test + public void testPartialSignedDocumentTampered_SignatureFirst() throws Exception { + // Read in plaintext document + InputStream sourceDocument = + this.getClass().getClassLoader().getResourceAsStream( + "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml"); + DocumentBuilder builder = XMLUtils.createDocumentBuilder(false); + Document document = builder.parse(sourceDocument); + + // Set up the Key + KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load( + this.getClass().getClassLoader().getResource("transmitter.jks").openStream(), + "default".toCharArray() + ); + Key key = keyStore.getKey("transmitter", "default".toCharArray()); + X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter"); + + // Sign using DOM + List<String> localNames = new ArrayList<String>(); + localNames.add("PaymentInfo"); + XMLSignature sig = signUsingDOM( + "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key + ); + + // Add KeyInfo + sig.addKeyInfo(cert); + + // Now modify the context of PaymentInfo + Element paymentInfoElement = + (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0); + paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US"); + + //move signature below root element + Element sigElement = (Element)document.getElementsByTagNameNS( + XMLSecurityConstants.TAG_dsig_Signature.getNamespaceURI(), + XMLSecurityConstants.TAG_dsig_Signature.getLocalPart()).item(0); + document.getDocumentElement().insertBefore(sigElement, + XMLUtils.getNextElement(document.getDocumentElement().getFirstChild())); + + // Convert Document to a Stream Reader + javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + transformer.transform(new DOMSource(document), new StreamResult(baos)); + final XMLStreamReader xmlStreamReader = + xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())); + + // Verify signature + XMLSecurityProperties properties = new XMLSecurityProperties(); + InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties); + TestSecurityEventListener securityEventListener = new TestSecurityEventListener(); + XMLStreamReader securityStreamReader = + inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener); + + try { + StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader); + fail("Failure expected on a modified document"); + } catch (XMLStreamException ex) { + Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference")); + } + } + + @Test + public void testEnvelopedSignatureTampered_ContentFirst() throws Exception { + // Read in plaintext document + InputStream sourceDocument = + this.getClass().getClassLoader().getResourceAsStream( + "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml"); + DocumentBuilder builder = XMLUtils.createDocumentBuilder(false); + Document document = builder.parse(sourceDocument); + + // Set up the Key + KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load( + this.getClass().getClassLoader().getResource("transmitter.jks").openStream(), + "default".toCharArray() + ); + Key key = keyStore.getKey("transmitter", "default".toCharArray()); + X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter"); + + // Sign using DOM + List<String> localNames = new ArrayList<String>(); + + ReferenceInfo referenceInfo = new ReferenceInfo( + "", + new String[]{ + "http://www.w3.org/2000/09/xmldsig#enveloped-signature", + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" + }, + "http://www.w3.org/2000/09/xmldsig#sha1", + false + ); + + List<ReferenceInfo> referenceInfos = new ArrayList<ReferenceInfo>(); + referenceInfos.add(referenceInfo); + + XMLSignature sig = signUsingDOM( + "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key, referenceInfos + ); + + // Add KeyInfo + sig.addKeyInfo(cert); + + // Now modify the context of PaymentInfo + Element paymentInfoElement = + (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0); + paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US"); + + // Convert Document to a Stream Reader + javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + transformer.transform(new DOMSource(document), new StreamResult(baos)); + final XMLStreamReader xmlStreamReader = + xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())); + + // Verify signature + XMLSecurityProperties properties = new XMLSecurityProperties(); + InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties); + TestSecurityEventListener securityEventListener = new TestSecurityEventListener(); + XMLStreamReader securityStreamReader = + inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener); + + try { + final Document res = StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader); + fail("Failure expected on a modified document"); + } catch (XMLStreamException ex) { + Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference")); + } + } + + @Test + public void testEnvelopedSignatureTampered_SignatureFirst() throws Exception { + // Read in plaintext document + InputStream sourceDocument = + this.getClass().getClassLoader().getResourceAsStream( + "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml"); + DocumentBuilder builder = XMLUtils.createDocumentBuilder(false); + Document document = builder.parse(sourceDocument); + + // Set up the Key + KeyStore keyStore = KeyStore.getInstance("jks"); + keyStore.load( + this.getClass().getClassLoader().getResource("transmitter.jks").openStream(), + "default".toCharArray() + ); + Key key = keyStore.getKey("transmitter", "default".toCharArray()); + X509Certificate cert = (X509Certificate)keyStore.getCertificate("transmitter"); + + // Sign using DOM + List<String> localNames = new ArrayList<String>(); + + ReferenceInfo referenceInfo = new ReferenceInfo( + "", + new String[]{ + "http://www.w3.org/2000/09/xmldsig#enveloped-signature", + "http://www.w3.org/TR/2001/REC-xml-c14n-20010315" + }, + "http://www.w3.org/2000/09/xmldsig#sha1", + false + ); + + List<ReferenceInfo> referenceInfos = new ArrayList<ReferenceInfo>(); + referenceInfos.add(referenceInfo); + + XMLSignature sig = signUsingDOM( + "http://www.w3.org/2000/09/xmldsig#rsa-sha1", document, localNames, key, referenceInfos + ); + + // Add KeyInfo + sig.addKeyInfo(cert); + + // Now modify the context of PaymentInfo + Element paymentInfoElement = + (Element)document.getElementsByTagNameNS("urn:example:po", "BillingAddress").item(0); + paymentInfoElement.setTextContent("Dig PLC, 1 First Ave, Dublin 1, US"); + + //move signature below root element + Element sigElement = (Element)document.getElementsByTagNameNS( + XMLSecurityConstants.TAG_dsig_Signature.getNamespaceURI(), + XMLSecurityConstants.TAG_dsig_Signature.getLocalPart()).item(0); + document.getDocumentElement().insertBefore(sigElement, + XMLUtils.getNextElement(document.getDocumentElement().getFirstChild())); + + // Convert Document to a Stream Reader + javax.xml.transform.Transformer transformer = transformerFactory.newTransformer(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + transformer.transform(new DOMSource(document), new StreamResult(baos)); + final XMLStreamReader xmlStreamReader = + xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())); + + // Verify signature + XMLSecurityProperties properties = new XMLSecurityProperties(); + InboundXMLSec inboundXMLSec = XMLSec.getInboundWSSec(properties); + TestSecurityEventListener securityEventListener = new TestSecurityEventListener(); + XMLStreamReader securityStreamReader = + inboundXMLSec.processInMessage(xmlStreamReader, null, securityEventListener); + + try { + final Document res = StAX2DOM.readDoc(XMLUtils.createDocumentBuilder(false), securityStreamReader); + fail("Failure expected on a modified document"); + } catch (XMLStreamException ex) { + Assert.assertTrue(ex.getMessage().contains("Invalid digest of reference")); + } + } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
13- santuario.apache.org/secadv.data/CVE-2014-8152.txt.ascnvdVendor AdvisoryWEB
- github.com/advisories/GHSA-w7cq-j9p9-hm3mghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2014-8152ghsaADVISORY
- seclists.org/oss-sec/2015/q1/181nvdWEB
- exchange.xforce.ibmcloud.com/vulnerabilities/99993nvdWEB
- github.com/apache/santuario-java/commit/55857fd4cdfdb1af4069170ecdac448c078f544eghsaWEB
- lists.apache.org/thread.html/680e6938b6412e26d5446054fd31de2011d33af11786b989127d1cc3@%3Ccommits.santuario.apache.org%3EghsaWEB
- lists.apache.org/thread.html/r1c07a561426ec5579073046ad7f4207cdcef452bb3100abaf908e0cd@%3Ccommits.santuario.apache.org%3EghsaWEB
- svn.apache.org/viewvcghsaWEB
- www.securityfocus.com/bid/72115nvd
- www.securitytracker.com/id/1031556nvd
- lists.apache.org/thread.html/680e6938b6412e26d5446054fd31de2011d33af11786b989127d1cc3%40%3Ccommits.santuario.apache.org%3Envd
- lists.apache.org/thread.html/r1c07a561426ec5579073046ad7f4207cdcef452bb3100abaf908e0cd%40%3Ccommits.santuario.apache.org%3Envd
News mentions
0No linked articles in our index yet.