CVE-2014-1904: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site scripting (XSS) vulnerability in web/servlet/tags/form/FormTag.java in Spring MVC in Spring Framework 3.0.0 before 3.2.8 and 4.0.0 before 4.0.2 allows remote attackers to inject arbitrary web script or HTML via the requested URI in a default action.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Published: 2014-03-20T16:55Z
Repository: https://github.com/spring-projects/spring-framework
Language: Java
Files changed: spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java, spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java
Commit date: 2014-02-13 14:36:12 -0500
Commit message: Add encoding for the default action in FormTag

Issue: SPR-11426

Diff: diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java
index a6aa59c55..8c50bde21 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java
@@ -1,7 +1,7 @@
 /*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
 package org.springframework.web.servlet.tags.form;
 
+import java.io.UnsupportedEncodingException;
 import java.util.Map;
 
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
@@ -30,10 +31,11 @@ import org.springframework.core.Conventions;
 import org.springframework.http.HttpMethod;
 import org.springframework.util.ObjectUtils;
 import org.springframework.util.StringUtils;
 import org.springframework.web.servlet.support.RequestDataValueProcessor;
 import org.springframework.web.util.HtmlUtils;
+import org.springframework.web.util.UriUtils;
 
 /**
  * Databinding-aware JSP tag for rendering an HTML '{@code form}' whose
  * inner elements are bound to properties on a <em>form object</em>.
  *
@@ -440,10 +442,17 @@ public class FormTag extends AbstractHtmlElementTag {
 			servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
 			return processAction(servletRelativeAction);
 		}
 		else {
 			String requestUri = getRequestContext().getRequestUri();
+			String encoding = pageContext.getResponse().getCharacterEncoding();
+			try {
+				requestUri = UriUtils.encodePath(requestUri, encoding);
+			}
+			catch (UnsupportedEncodingException e) {
+				throw new JspException(e);
+			}
 			ServletResponse response = this.pageContext.getResponse();
 			if (response instanceof HttpServletResponse) {
 				requestUri = ((HttpServletResponse) response).encodeURL(requestUri);
 				String queryString = getRequestContext().getQueryString();
 				if (StringUtils.hasText(queryString)) {
diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java
index 8fdcc1cc4..2612761a2 100644
--- a/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java
+++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java
@@ -1,7 +1,7 @@
 /*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
@@ -338,10 +338,25 @@ public class FormTagTests extends AbstractHtmlElementTagTests {
 		assertEquals("<div>\n<input type=\"hidden\" name=\"key\" value=\"value\" />\n</div>", getInputTag(output));
 		assertFormTagOpened(output);
 		assertFormTagClosed(output);
 	}
 
+	public void testDefaultActionEncoded() throws Exception {
+
+		this.request.setRequestURI("/a b c");
+		request.setQueryString("");
+
+		this.tag.doStartTag();
+		this.tag.doEndTag();
+		this.tag.doFinally();
+
+		String output = getOutput();
+		String formOutput = getFormTag(output);
+
+		assertContainsAttribute(formOutput, "action", "/a%20b%20c");
+	}
+
 	private String getFormTag(String output) {
 		int inputStart = output.indexOf("<", 1);
 		int inputEnd = output.lastIndexOf(">", output.length() - 2);
 		return output.substring(0, inputStart) + output.substring(inputEnd + 1);
 	}

Vulnerable code:  * Copyright 2002-2013 the original author or authors.
 * Copyright 2002-2013 the original author or authors.
Fixed code:  * Copyright 2002-2014 the original author or authors.
import java.io.UnsupportedEncodingException;
import org.springframework.web.util.UriUtils;
			String encoding = pageContext.getResponse().getCharacterEncoding();
			try {
				requestUri = UriUtils.encodePath(requestUri, encoding);
			}
			catch (UnsupportedEncodingException e) {
				throw new JspException(e);
			}
 * Copyright 2002-2014 the original author or authors.
	public void testDefaultActionEncoded() throws Exception {

		this.request.setRequestURI("/a b c");
		request.setQueryString("");

		this.tag.doStartTag();
		this.tag.doEndTag();
		this.tag.doFinally();

		String output = getOutput();
		String formOutput = getFormTag(output);

		assertContainsAttribute(formOutput, "action", "/a%20b%20c");
	}