VYPR
Moderate severityNVD Advisory· Published Mar 20, 2014· Updated May 6, 2026

CVE-2014-1904

CVE-2014-1904

Description

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.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.springframework:spring-webmvcMaven
>= 3.0.0, < 3.2.8.RELEASE3.2.8.RELEASE
org.springframework:spring-webmvcMaven
>= 4.0.0, < 4.0.2.RELEASE4.0.2.RELEASE

Affected products

1

Patches

2
75e08695a049

Mixed polishing along with recent changes

https://github.com/spring-projects/spring-frameworkJuergen HoellerFeb 14, 2014via ghsa
5 files changed · +50 29
  • spring-context/src/main/java/org/springframework/cache/CacheManager.java+7 6 modified
    @@ -1,5 +1,5 @@
     /*
    - * Copyright 2002-2011 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.
    @@ -19,7 +19,8 @@
     import java.util.Collection;
     
     /**
    - * A manager for a set of {@link Cache}s.
    + * Spring's central cache manager SPI.
    + * Allows for retrieving named {@link Cache} regions.
      *
      * @author Costin Leau
      * @since 3.1
    @@ -28,14 +29,14 @@ public interface CacheManager {
     
     	/**
     	 * Return the cache associated with the given name.
    -	 * @param name cache identifier (must not be {@code null})
    -	 * @return associated cache, or {@code null} if none is found
    +	 * @param name the cache identifier (must not be {@code null})
    +	 * @return the associated cache, or {@code null} if none found
     	 */
     	Cache getCache(String name);
     
     	/**
    -	 * Return a collection of the caches known by this cache manager.
    -	 * @return names of caches known by the cache manager.
    +	 * Return a collection of the cache names known by this manager.
    +	 * @return the names of all caches known by the cache manager
     	 */
     	Collection<String> getCacheNames();
     
    
  • spring-expression/src/test/java/org/springframework/expression/spel/MapAccessTests.java+13 3 modified
    @@ -81,9 +81,19 @@ public void testGetValue(){
     		Object bean = new TestBean("name1", new TestBean("name2", null, "Description 2", 15, props1), "description 1", 6, props1);
     
     		ExpressionParser parser = new SpelExpressionParser();
    -		Expression exp = parser.parseExpression("testBean.properties['key2']");
    -		String key = (String) exp.getValue(bean);
    -		assertNotNull(key);
    +		Expression expr = parser.parseExpression("testBean.properties['key2']");
    +		assertEquals("value2", expr.getValue(bean));
    +	}
    +
    +	@Test
    +	public void testGetValueFromRootMap() {
    +		Map<String, String> map = new HashMap<String, String>();
    +		map.put("key", "value");
    +		EvaluationContext context = new StandardEvaluationContext(map);
    +
    +		ExpressionParser spelExpressionParser = new SpelExpressionParser();
    +		Expression expr = spelExpressionParser.parseExpression("#root['key']");
    +		assertEquals("value", expr.getValue(map));
     	}
     
     
    
  • spring-tx/src/main/java/org/springframework/transaction/interceptor/RollbackRuleAttribute.java+8 8 modified
    @@ -1,5 +1,5 @@
     /*
    - * Copyright 2002-2012 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.
    @@ -16,10 +16,10 @@
     
     package org.springframework.transaction.interceptor;
     
    -import org.springframework.util.Assert;
    -
     import java.io.Serializable;
     
    +import org.springframework.util.Assert;
    +
     /**
      * Rule determining whether or not a given exception (and any subclasses)
      * should cause a rollback.
    @@ -59,8 +59,8 @@ public class RollbackRuleAttribute implements Serializable{
     	 * @throws IllegalArgumentException if the supplied {@code clazz} is
     	 * not a {@code Throwable} type or is {@code null}
     	 */
    -	public RollbackRuleAttribute(Class clazz) {
    -		Assert.notNull(clazz, "'clazz' cannot be null.");
    +	public RollbackRuleAttribute(Class<?> clazz) {
    +		Assert.notNull(clazz, "'clazz' cannot be null");
     		if (!Throwable.class.isAssignableFrom(clazz)) {
     			throw new IllegalArgumentException(
     					"Cannot construct rollback rule from [" + clazz.getName() + "]: it's not a Throwable");
    @@ -87,7 +87,7 @@ public RollbackRuleAttribute(Class clazz) {
     	 * {@code exceptionName} is {@code null} or empty
     	 */
     	public RollbackRuleAttribute(String exceptionName) {
    -		Assert.hasText(exceptionName, "'exceptionName' cannot be null or empty.");
    +		Assert.hasText(exceptionName, "'exceptionName' cannot be null or empty");
     		this.exceptionName = exceptionName;
     	}
     
    @@ -110,8 +110,8 @@ public int getDepth(Throwable ex) {
     	}
     
     
    -	private int getDepth(Class exceptionClass, int depth) {
    -		if (exceptionClass.getName().indexOf(this.exceptionName) != -1) {
    +	private int getDepth(Class<?> exceptionClass, int depth) {
    +		if (exceptionClass.getName().contains(this.exceptionName)) {
     			// Found it!
     			return depth;
     		}
    
  • spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java+4 5 modified
    @@ -1,5 +1,5 @@
     /*
    - * Copyright 2002-2012 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.
    @@ -19,7 +19,6 @@
     import java.io.IOException;
     import java.io.InputStream;
     import java.io.Reader;
    -import java.lang.reflect.Method;
     import java.security.Principal;
     import java.util.Locale;
     
    @@ -102,9 +101,9 @@ else if (Reader.class.isAssignableFrom(paramType)) {
     			return request.getReader();
     		}
     		else {
    -			// should never happen..
    -			Method method = parameter.getMethod();
    -			throw new UnsupportedOperationException("Unknown parameter type: " + paramType + " in method: " + method);
    +			// should never happen...
    +			throw new UnsupportedOperationException(
    +					"Unknown parameter type: " + paramType + " in method: " + parameter.getMethod());
     		}
     	}
     
    
  • spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java+18 7 modified
    @@ -1,5 +1,5 @@
     /*
    - * 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.
    @@ -16,8 +16,8 @@
     
     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;
    @@ -32,6 +32,7 @@
     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
    @@ -352,8 +353,7 @@ protected int writeTagContent(TagWriter tagWriter) throws JspException {
     		tagWriter.startTag(FORM_TAG);
     		writeDefaultAttributes(tagWriter);
     		tagWriter.writeAttribute(ACTION_ATTRIBUTE, resolveAction());
    -		writeOptionalAttribute(tagWriter, METHOD_ATTRIBUTE,
    -				isMethodBrowserSupported(getMethod()) ? getMethod() : DEFAULT_METHOD);
    +		writeOptionalAttribute(tagWriter, METHOD_ATTRIBUTE, getHttpMethod());
     		writeOptionalAttribute(tagWriter, TARGET_ATTRIBUTE, getTarget());
     		writeOptionalAttribute(tagWriter, ENCTYPE_ATTRIBUTE, getEnctype());
     		writeOptionalAttribute(tagWriter, ACCEPT_CHARSET_ATTRIBUTE, getAcceptCharset());
    @@ -389,6 +389,10 @@ protected int writeTagContent(TagWriter tagWriter) throws JspException {
     		return EVAL_BODY_INCLUDE;
     	}
     
    +	private String getHttpMethod() {
    +		return (isMethodBrowserSupported(getMethod()) ? getMethod() : DEFAULT_METHOD);
    +	}
    +
     	private void assertHttpMethod(String method) {
     		for (HttpMethod httpMethod : HttpMethod.values()) {
     			if (httpMethod.name().equalsIgnoreCase(method)) {
    @@ -426,7 +430,6 @@ protected String resolveModelAttribute() throws JspException {
     	 * with the context and servlet paths, and the result is used. Otherwise, the
     	 * {@link org.springframework.web.servlet.support.RequestContext#getRequestUri()
     	 * originating URI} is used.
    -	 *
     	 * @return the value that is to be used for the '{@code action}' attribute
     	 */
     	protected String resolveAction() throws JspException {
    @@ -438,14 +441,22 @@ protected String resolveAction() throws JspException {
     		}
     		else if (StringUtils.hasText(servletRelativeAction)) {
     			String pathToServlet = getRequestContext().getPathToServlet();
    -			if (servletRelativeAction.startsWith("/") && !servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
    +			if (servletRelativeAction.startsWith("/") &&
    +					!servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
     				servletRelativeAction = pathToServlet + servletRelativeAction;
     			}
     			servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
     			return processAction(servletRelativeAction);
     		}
     		else {
     			String requestUri = getRequestContext().getRequestUri();
    +			String encoding = this.pageContext.getResponse().getCharacterEncoding();
    +			try {
    +				requestUri = UriUtils.encodePath(requestUri, encoding);
    +			}
    +			catch (UnsupportedEncodingException ex) {
    +				// shouldn't happen - if it does, proceed with requestUri as-is
    +			}
     			ServletResponse response = this.pageContext.getResponse();
     			if (response instanceof HttpServletResponse) {
     				requestUri = ((HttpServletResponse) response).encodeURL(requestUri);
    @@ -471,7 +482,7 @@ else if (StringUtils.hasText(servletRelativeAction)) {
     	private String processAction(String action) {
     		RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
     		ServletRequest request = this.pageContext.getRequest();
    -		if ((processor != null) && (request instanceof HttpServletRequest)) {
    +		if (processor != null && request instanceof HttpServletRequest) {
     			action = processor.processAction((HttpServletRequest) request, action);
     		}
     		return action;
    
741b4b229ae0

Add encoding for the default action in FormTag

https://github.com/spring-projects/spring-frameworkRossen StoyanchevFeb 13, 2014via ghsa
2 files changed · +26 2
  • spring-webmvc/src/main/java/org/springframework/web/servlet/tags/form/FormTag.java+10 1 modified
    @@ -1,5 +1,5 @@
     /*
    - * 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.
    @@ -16,6 +16,7 @@
     
     package org.springframework.web.servlet.tags.form;
     
    +import java.io.UnsupportedEncodingException;
     import java.util.Map;
     
     import javax.servlet.ServletRequest;
    @@ -32,6 +33,7 @@
     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
    @@ -442,6 +444,13 @@ else if (StringUtils.hasText(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);
    
  • spring-webmvc/src/test/java/org/springframework/web/servlet/tags/form/FormTagTests.java+16 1 modified
    @@ -1,5 +1,5 @@
     /*
    - * 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.
    @@ -340,6 +340,21 @@ public void testRequestDataValueProcessorHooks() throws Exception {
     		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);
    

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

12

News mentions

0

No linked articles in our index yet.