High severity8.8NVD Advisory· Published Nov 30, 2017· Updated May 13, 2026
CVE-2017-12631
CVE-2017-12631
Description
Apache CXF Fediz ships with a number of container-specific plugins to enable WS-Federation for applications. A CSRF (Cross Style Request Forgery) style vulnerability has been found in the Spring 2, Spring 3 and Spring 4 plugins in versions before 1.4.3 and 1.3.3. The vulnerability can result in a security context that is set up using a malicious client's roles for the given enduser.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.cxf.fediz:fediz-spring2Maven | < 1.3.3 | 1.3.3 |
org.apache.cxf.fediz:fediz-spring2Maven | >= 1.4.0, < 1.4.3 | 1.4.3 |
org.apache.cxf.fediz:fediz-spring3Maven | < 1.3.3 | 1.3.3 |
org.apache.cxf.fediz:fediz-spring3Maven | >= 1.4.0, < 1.4.3 | 1.4.3 |
org.apache.cxf.fediz:fediz-springMaven | < 1.3.3 | 1.3.3 |
org.apache.cxf.fediz:fediz-springMaven | >= 1.4.0, < 1.4.3 | 1.4.3 |
Affected products
5- Apache Software Foundation/Apache CXF Fedizv5Range: 1.4.x prior to 1.4.3
Patches
2ccdb12b26ff8Some improvements to the Spring plugins
6 files changed · +94 −14
plugins/spring3/src/main/java/org/apache/cxf/fediz/spring/web/FederationAuthenticationFilter.java+12 −7 modified@@ -128,14 +128,19 @@ private String getState(ServletRequest request) { private void verifySavedState(HttpServletRequest request) { HttpSession session = request.getSession(false); - if (session != null) { - String savedContext = (String)session.getAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); - String state = getState(request); - if (savedContext != null && !savedContext.equals(state)) { - logger.warn("The received state does not match the state saved in the context"); - throw new BadCredentialsException("The received state does not match the state saved in the context"); - } + + if (session == null) { + logger.warn("The received state does not match the state saved in the context"); + throw new BadCredentialsException("The received state does not match the state saved in the context"); + } + + String savedContext = (String)session.getAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); + String state = getState(request); + if (savedContext == null || !savedContext.equals(state)) { + logger.warn("The received state does not match the state saved in the context"); + throw new BadCredentialsException("The received state does not match the state saved in the context"); } + session.removeAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); } /**
plugins/spring/src/main/java/org/apache/cxf/fediz/spring/web/FederationAuthenticationFilter.java+12 −7 modified@@ -128,14 +128,19 @@ private String getState(ServletRequest request) { private void verifySavedState(HttpServletRequest request) { HttpSession session = request.getSession(false); - if (session != null) { - String savedContext = (String)session.getAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); - String state = getState(request); - if (savedContext != null && !savedContext.equals(state)) { - logger.warn("The received state does not match the state saved in the context"); - throw new BadCredentialsException("The received state does not match the state saved in the context"); - } + + if (session == null) { + logger.warn("The received state does not match the state saved in the context"); + throw new BadCredentialsException("The received state does not match the state saved in the context"); + } + + String savedContext = (String)session.getAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); + String state = getState(request); + if (savedContext == null || !savedContext.equals(state)) { + logger.warn("The received state does not match the state saved in the context"); + throw new BadCredentialsException("The received state does not match the state saved in the context"); } + session.removeAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); } /**
systests/spring/src/test/java/org/apache/cxf/fediz/integrationtests/Spring3Test.java+8 −0 modified@@ -159,4 +159,12 @@ public void testCSRFAttack() throws Exception { csrfAttackTest(url); } + @Override + @org.junit.Test + public void testCSRFAttack2() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + + "/j_spring_fediz_security_check"; + csrfAttackTest2(url); + } + }
systests/spring/src/test/java/org/apache/cxf/fediz/integrationtests/SpringTest.java+8 −0 modified@@ -157,4 +157,12 @@ public void testCSRFAttack() throws Exception { + "/j_spring_fediz_security_check"; csrfAttackTest(url); } + + @Override + @org.junit.Test + public void testCSRFAttack2() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + + "/j_spring_fediz_security_check"; + csrfAttackTest2(url); + } }
systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java+53 −0 modified@@ -799,4 +799,57 @@ protected void csrfAttackTest(String rpURL) throws Exception { } + @org.junit.Test + public void testCSRFAttack2() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet"; + csrfAttackTest2(url); + } + + protected void csrfAttackTest2(String rpURL) throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet"; + + // 1. Log in as "bob" using another WebClient + WebClient webClient2 = new WebClient(); + webClient2.getOptions().setUseInsecureSSL(true); + webClient2.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials("bob", "bob")); + + webClient2.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage2 = webClient2.getPage(url); + webClient2.getOptions().setJavaScriptEnabled(true); + Assert.assertEquals("IDP SignIn Response Form", idpPage2.getTitleText()); + + // 2. Now instead of clicking on the form, send the form via alice's WebClient instead + + // Send with context... + WebRequest request = new WebRequest(new URL(rpURL), HttpMethod.POST); + request.setRequestParameters(new ArrayList<NameValuePair>()); + + DomNodeList<DomElement> results = idpPage2.getElementsByTagName("input"); + + for (DomElement result : results) { + if ("wresult".equals(result.getAttributeNS(null, "name")) + || "wa".equals(result.getAttributeNS(null, "name")) + || "wctx".equals(result.getAttributeNS(null, "name"))) { + String value = result.getAttributeNS(null, "value"); + request.getRequestParameters().add(new NameValuePair(result.getAttributeNS(null, "name"), value)); + } + } + + WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + + try { + webClient.getPage(request); + Assert.fail("Failure expected on a CSRF attack"); + } catch (FailingHttpStatusCodeException ex) { + // expected + } + + webClient.close(); + webClient2.close(); + + } + }
systests/webapps/springWebapp/src/main/webapp/WEB-INF/applicationContext-security.xml+1 −0 modified@@ -37,6 +37,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/sch <sec:intercept-url pattern="/index.html" access="permitAll"/> <sec:intercept-url pattern="/FederationMetadata/**" access="isAuthenticated()"/> <sec:intercept-url pattern="/secure/fedservlet" access="isAuthenticated()"/> + <sec:intercept-url pattern="/secure/test.html" access="isAuthenticated()"/> <sec:intercept-url pattern="/secure/manager/**" access="hasRole('ROLE_MANAGER')"/> <sec:intercept-url pattern="/secure/admin/**" access="hasRole('ROLE_ADMIN')"/> <sec:intercept-url pattern="/secure/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_MANAGER')"/>
48dd9b68d67cSome improvements to the Spring plugins
4 files changed · +73 −7
plugins/spring/src/main/java/org/apache/cxf/fediz/spring/web/FederationAuthenticationFilter.java+12 −7 modified@@ -128,14 +128,19 @@ private String getState(ServletRequest request) { private void verifySavedState(HttpServletRequest request) { HttpSession session = request.getSession(false); - if (session != null) { - String savedContext = (String)session.getAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); - String state = getState(request); - if (savedContext != null && !savedContext.equals(state)) { - logger.warn("The received state does not match the state saved in the context"); - throw new BadCredentialsException("The received state does not match the state saved in the context"); - } + + if (session == null) { + logger.warn("The received state does not match the state saved in the context"); + throw new BadCredentialsException("The received state does not match the state saved in the context"); + } + + String savedContext = (String)session.getAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); + String state = getState(request); + if (savedContext == null || !savedContext.equals(state)) { + logger.warn("The received state does not match the state saved in the context"); + throw new BadCredentialsException("The received state does not match the state saved in the context"); } + session.removeAttribute(FederationAuthenticationEntryPoint.SAVED_CONTEXT); } /**
systests/spring/src/test/java/org/apache/cxf/fediz/integrationtests/SpringTest.java+8 −0 modified@@ -157,4 +157,12 @@ public void testCSRFAttack() throws Exception { + "/j_spring_fediz_security_check"; csrfAttackTest(url); } + + @Override + @org.junit.Test + public void testCSRFAttack2() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + + "/j_spring_fediz_security_check"; + csrfAttackTest2(url); + } }
systests/tests/src/test/java/org/apache/cxf/fediz/integrationtests/AbstractTests.java+52 −0 modified@@ -803,4 +803,56 @@ protected void csrfAttackTest(String rpURL) throws Exception { } + @org.junit.Test + public void testCSRFAttack2() throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet"; + csrfAttackTest2(url); + } + + protected void csrfAttackTest2(String rpURL) throws Exception { + String url = "https://localhost:" + getRpHttpsPort() + "/" + getServletContextName() + "/secure/fedservlet"; + + // 1. Log in as "bob" using another WebClient + WebClient webClient2 = new WebClient(); + webClient2.getOptions().setUseInsecureSSL(true); + webClient2.getCredentialsProvider().setCredentials( + new AuthScope("localhost", Integer.parseInt(getIdpHttpsPort())), + new UsernamePasswordCredentials("bob", "bob")); + + webClient2.getOptions().setJavaScriptEnabled(false); + final HtmlPage idpPage2 = webClient2.getPage(url); + webClient2.getOptions().setJavaScriptEnabled(true); + Assert.assertEquals("IDP SignIn Response Form", idpPage2.getTitleText()); + + // 2. Now instead of clicking on the form, send the form via alice's WebClient instead + + // Send with context... + WebRequest request = new WebRequest(new URL(rpURL), HttpMethod.POST); + request.setRequestParameters(new ArrayList<NameValuePair>()); + + DomNodeList<DomElement> results = idpPage2.getElementsByTagName("input"); + + for (DomElement result : results) { + if ("wresult".equals(result.getAttributeNS(null, "name")) + || "wa".equals(result.getAttributeNS(null, "name")) + || "wctx".equals(result.getAttributeNS(null, "name"))) { + String value = result.getAttributeNS(null, "value"); + request.getRequestParameters().add(new NameValuePair(result.getAttributeNS(null, "name"), value)); + } + } + + WebClient webClient = new WebClient(); + webClient.getOptions().setUseInsecureSSL(true); + + try { + webClient.getPage(request); + Assert.fail("Failure expected on a CSRF attack"); + } catch (FailingHttpStatusCodeException ex) { + // expected + } + + // webClient.close(); + // webClient2.close(); + + } }
systests/webapps/springWebapp/src/main/webapp/WEB-INF/applicationContext-security.xml+1 −0 modified@@ -37,6 +37,7 @@ http://www.springframework.org/schema/context http://www.springframework.org/sch <sec:intercept-url pattern="/index.html" access="permitAll"/> <sec:intercept-url pattern="/FederationMetadata/**" access="isAuthenticated()"/> <sec:intercept-url pattern="/secure/fedservlet" access="isAuthenticated()"/> + <sec:intercept-url pattern="/secure/test.html" access="isAuthenticated()"/> <sec:intercept-url pattern="/secure/manager/**" access="hasRole('ROLE_MANAGER')"/> <sec:intercept-url pattern="/secure/admin/**" access="hasRole('ROLE_ADMIN')"/> <sec:intercept-url pattern="/secure/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN','ROLE_MANAGER')"/>
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
21- cxf.547215.n5.nabble.com/Apache-CXF-Fediz-1-4-3-and-1-3-3-released-with-a-new-security-advisory-CVE-2017-12631-td5785868.htmlnvdThird Party Advisory
- www.securityfocus.com/bid/102127nvdThird Party AdvisoryVDB EntryWEB
- github.com/advisories/GHSA-fv7x-4hpc-hf9fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2017-12631ghsaADVISORY
- github.com/apache/cxf-fediz/commit/48dd9b68d67c6b729376c1ce8886f52a57df6c45ghsaWEB
- github.com/apache/cxf-fediz/commit/ccdb12b26ff89e0a998a333e84dd84bd713ac76cghsaWEB
- lists.apache.org/thread.html/r36e44ffc1a9b365327df62cdfaabe85b9a5637de102cea07d79b2dbf@%3Ccommits.cxf.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rc774278135816e7afc943dc9fc78eb0764f2c84a2b96470a0187315c@%3Ccommits.cxf.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rd49aabd984ed540c8ff7916d4d79405f3fa311d2fdbcf9ed307839a6@%3Ccommits.cxf.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rec7160382badd3ef4ad017a22f64a266c7188b9ba71394f0d321e2d4@%3Ccommits.cxf.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rfb87e0bf3995e7d560afeed750fac9329ff5f1ad49da365129b7f89e@%3Ccommits.cxf.apache.org%3EghsaWEB
- lists.apache.org/thread.html/rff42cfa5e7d75b7c1af0e37589140a8f1999e578a75738740b244bd4@%3Ccommits.cxf.apache.org%3EghsaWEB
- web.archive.org/web/20180122175008/http://cxf.547215.n5.nabble.com/Apache-CXF-Fediz-1-4-3-and-1-3-3-released-with-a-new-security-advisory-CVE-2017-12631-td5785868.htmlghsaWEB
- web.archive.org/web/20201208184733/http://www.securitytracker.com/id/1040487ghsaWEB
- www.securitytracker.com/id/1040487nvd
- lists.apache.org/thread.html/r36e44ffc1a9b365327df62cdfaabe85b9a5637de102cea07d79b2dbf%40%3Ccommits.cxf.apache.org%3Envd
- lists.apache.org/thread.html/rc774278135816e7afc943dc9fc78eb0764f2c84a2b96470a0187315c%40%3Ccommits.cxf.apache.org%3Envd
- lists.apache.org/thread.html/rd49aabd984ed540c8ff7916d4d79405f3fa311d2fdbcf9ed307839a6%40%3Ccommits.cxf.apache.org%3Envd
- lists.apache.org/thread.html/rec7160382badd3ef4ad017a22f64a266c7188b9ba71394f0d321e2d4%40%3Ccommits.cxf.apache.org%3Envd
- lists.apache.org/thread.html/rfb87e0bf3995e7d560afeed750fac9329ff5f1ad49da365129b7f89e%40%3Ccommits.cxf.apache.org%3Envd
- lists.apache.org/thread.html/rff42cfa5e7d75b7c1af0e37589140a8f1999e578a75738740b244bd4%40%3Ccommits.cxf.apache.org%3Envd
News mentions
0No linked articles in our index yet.