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

CVE-2014-0094

CVE-2014-0094

Description

The ParametersInterceptor in Apache Struts before 2.3.16.2 allows remote attackers to "manipulate" the ClassLoader via the class parameter, which is passed to the getClass method.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.struts:struts2-coreMaven
>= 2.0.0, < 2.3.16.22.3.16.2
org.apache.struts.xwork:xwork-coreMaven
>= 2.0.0, < 2.3.16.22.3.16.2

Affected products

3

Patches

2
6315241719be

Uses global exclude patterns to initialise excludeParams

https://github.com/apache/strutsLukasz LenartApr 24, 2014via ghsa
2 files changed · +86 7
  • core/src/main/java/org/apache/struts2/interceptor/CookieInterceptor.java+71 3 modified
    @@ -24,6 +24,7 @@
     import com.opensymphony.xwork2.ActionContext;
     import com.opensymphony.xwork2.ActionInvocation;
     import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
    +import com.opensymphony.xwork2.ExcludedPatterns;
     import com.opensymphony.xwork2.util.TextParseUtil;
     import com.opensymphony.xwork2.util.ValueStack;
     import com.opensymphony.xwork2.util.logging.Logger;
    @@ -173,7 +174,8 @@ public class CookieInterceptor extends AbstractInterceptor {
         private Set<String> cookiesValueSet = Collections.emptySet();
     
         // Allowed names of cookies
    -    private Pattern acceptedPattern = Pattern.compile(ACCEPTED_PATTERN);
    +    private Pattern acceptedPattern = Pattern.compile(ACCEPTED_PATTERN, Pattern.CASE_INSENSITIVE);
    +    private Pattern excludedPattern = Pattern.compile(ExcludedPatterns.CLASS_ACCESS_PATTERN, Pattern.CASE_INSENSITIVE);
     
         /**
          * Set the <code>cookiesName</code> which if matched will allow the cookie
    @@ -223,7 +225,7 @@ public String intercept(ActionInvocation invocation) throws Exception {
                     String name = cookie.getName();
                     String value = cookie.getValue();
     
    -                if (acceptedPattern.matcher(name).matches()) {
    +                if (isAcceptableName(name) && isAcceptableValue(value)) {
                         if (cookiesNameSet.contains("*")) {
                             if (LOG.isDebugEnabled()) {
                                 LOG.debug("contains cookie name [*] in configured cookies name set, cookie with name [" + name + "] with value [" + value + "] will be injected");
    @@ -233,7 +235,7 @@ public String intercept(ActionInvocation invocation) throws Exception {
                             populateCookieValueIntoStack(name, value, cookiesMap, stack);
                         }
                     } else {
    -                    LOG.warn("Cookie name [" + name + "] does not match accepted cookie names pattern [" + acceptedPattern + "]");
    +                    LOG.warn("Cookie name [#0] with value [#1] was rejected!", name, value);
                     }
                 }
             }
    @@ -244,6 +246,72 @@ public String intercept(ActionInvocation invocation) throws Exception {
             return invocation.invoke();
         }
     
    +    /**
    +     * Checks if value of Cookie doesn't contain vulnerable code
    +     *
    +     * @param value of Cookie
    +     * @return true|false
    +     */
    +    protected boolean isAcceptableValue(String value) {
    +        boolean matches = !excludedPattern.matcher(value).matches();
    +        if (!matches) {
    +            if (LOG.isTraceEnabled()) {
    +                LOG.trace("Cookie value [#0] matches excludedPattern [#1]", value, ExcludedPatterns.CLASS_ACCESS_PATTERN);
    +            }
    +        }
    +        return matches;
    +    }
    +
    +    /**
    +     * Checks if name of Cookie doesn't contain vulnerable code
    +     *
    +     * @param name of Cookie
    +     * @return true|false
    +     */
    +    protected boolean isAcceptableName(String name) {
    +        return !isExcluded(name) && isAccepted(name);
    +    }
    +
    +    /**
    +     * Checks if name of Cookie match {@link #acceptedPattern}
    +     *
    +     * @param name of Cookie
    +     * @return true|false
    +     */
    +    protected boolean isAccepted(String name) {
    +        boolean matches = acceptedPattern.matcher(name).matches();
    +        if (matches) {
    +            if (LOG.isTraceEnabled()) {
    +                LOG.trace("Cookie [#0] matches acceptedPattern [#1]", name, ACCEPTED_PATTERN);
    +            }
    +        } else {
    +            if (LOG.isTraceEnabled()) {
    +                LOG.trace("Cookie [#0] doesn't match acceptedPattern [#1]", name, ACCEPTED_PATTERN);
    +            }
    +        }
    +        return matches;
    +    }
    +
    +    /**
    +     * Checks if name of Cookie match {@link #excludedPattern}
    +     *
    +     * @param name of Cookie
    +     * @return true|false
    +     */
    +    protected boolean isExcluded(String name) {
    +        boolean matches = excludedPattern.matcher(name).matches();
    +        if (matches) {
    +            if (LOG.isTraceEnabled()) {
    +                LOG.trace("Cookie [#0] matches excludedPattern [#1]", name, ExcludedPatterns.CLASS_ACCESS_PATTERN);
    +            }
    +        } else {
    +            if (LOG.isTraceEnabled()) {
    +                LOG.trace("Cookie [#0] doesn't match excludedPattern [#1]", name, ExcludedPatterns.CLASS_ACCESS_PATTERN);
    +            }
    +        }
    +        return matches;
    +    }
    +
         /**
          * Hook that populate cookie value into value stack (hence the action)
          * if the criteria is satisfied (if the cookie value matches with those configured).
    
  • xwork-core/src/main/java/com/opensymphony/xwork2/interceptor/ParametersInterceptor.java+15 4 modified
    @@ -17,6 +17,7 @@
     
     import com.opensymphony.xwork2.ActionContext;
     import com.opensymphony.xwork2.ActionInvocation;
    +import com.opensymphony.xwork2.ExcludedPatterns;
     import com.opensymphony.xwork2.ValidationAware;
     import com.opensymphony.xwork2.XWorkConstants;
     import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
    @@ -149,16 +150,20 @@ public class ParametersInterceptor extends MethodFilterInterceptor {
         private int paramNameMaxLength = PARAM_NAME_MAX_LENGTH;
     
         protected boolean ordered = false;
    -    protected Set<Pattern> excludeParams = Collections.emptySet();
    +    protected Set<Pattern> excludeParams;
         protected Set<Pattern> acceptParams = Collections.emptySet();
     
         private boolean devMode = false;
     
         // Allowed names of parameters
    -    private Pattern acceptedPattern = Pattern.compile(ACCEPTED_PARAM_NAMES);
    +    private Pattern acceptedPattern = Pattern.compile(ACCEPTED_PARAM_NAMES, Pattern.CASE_INSENSITIVE);
     
         private ValueStackFactory valueStackFactory;
     
    +    public ParametersInterceptor() {
    +        initializeHardCodedExcludePatterns();
    +    }
    +
         @Inject
         public void setValueStackFactory(ValueStackFactory valueStackFactory) {
             this.valueStackFactory = valueStackFactory;
    @@ -494,6 +499,13 @@ protected Set getExcludeParamsSet() {
             return excludeParams;
         }
     
    +    protected void initializeHardCodedExcludePatterns() {
    +        excludeParams = new HashSet<Pattern>();
    +        for (String pattern : ExcludedPatterns.EXCLUDED_PATTERNS) {
    +            excludeParams.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
    +        }
    +    }
    +
         /**
          * Sets a comma-delimited list of regular expressions to match
          * parameters that should be removed from the parameter map.
    @@ -503,9 +515,8 @@ protected Set getExcludeParamsSet() {
         public void setExcludeParams(String commaDelim) {
             Collection<String> excludePatterns = ArrayUtils.asCollection(commaDelim);
             if (excludePatterns != null) {
    -            excludeParams = new HashSet<Pattern>();
                 for (String pattern : excludePatterns) {
    -                excludeParams.add(Pattern.compile(pattern));
    +                excludeParams.add(Pattern.compile(pattern, Pattern.CASE_INSENSITIVE));
                 }
             }
         }
    
2e2da292166a

Moves global exclude patterns into dedicated class

https://github.com/apache/strutsLukasz LenartApr 24, 2014via ghsa
2 files changed · +26 4
  • core/src/main/resources/struts-default.xml+4 4 modified
    @@ -197,7 +197,7 @@
                     <interceptor-ref name="multiselect"/>
                     <interceptor-ref name="actionMappingParams"/>
                     <interceptor-ref name="params">
    -                    <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
    +                    <param name="excludeParams">^action:.*,^method:.*</param>
                     </interceptor-ref>
                     <interceptor-ref name="conversionError"/>
                     <interceptor-ref name="deprecation"/>
    @@ -253,7 +253,7 @@
                     <interceptor-ref name="checkbox"/>
                     <interceptor-ref name="multiselect"/>
                     <interceptor-ref name="params">
    -                    <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
    +                    <param name="excludeParams">^action:.*,^method:.*</param>
                     </interceptor-ref>
                     <interceptor-ref name="servletConfig"/>
                     <interceptor-ref name="prepare"/>
    @@ -263,7 +263,7 @@
                     <interceptor-ref name="staticParams"/>
                     <interceptor-ref name="actionMappingParams"/>
                     <interceptor-ref name="params">
    -                    <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
    +                    <param name="excludeParams">^action:.*,^method:.*</param>
                     </interceptor-ref>
                     <interceptor-ref name="conversionError"/>
                     <interceptor-ref name="validation">
    @@ -300,7 +300,7 @@
                     <interceptor-ref name="staticParams"/>
                     <interceptor-ref name="actionMappingParams"/>
                     <interceptor-ref name="params">
    -                    <param name="excludeParams">^class\..*,^dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,^parameters\..*,^action:.*,^method:.*</param>
    +                    <param name="excludeParams">^action:.*,^method:.*</param>
                     </interceptor-ref>
                     <interceptor-ref name="conversionError"/>
                     <interceptor-ref name="validation">
    
  • xwork-core/src/main/java/com/opensymphony/xwork2/ExcludedPatterns.java+22 0 added
    @@ -0,0 +1,22 @@
    +package com.opensymphony.xwork2;
    +
    +/**
    + * ExcludedPatterns contains hard-coded patterns that must be rejected by {@link com.opensymphony.xwork2.interceptor.ParametersInterceptor}
    + * and partially in CookInterceptor
    + */
    +public class ExcludedPatterns {
    +
    +    public static final String CLASS_ACCESS_PATTERN = "(.*\\.|^|.*|\\[('|\"))class(\\.|('|\")]|\\[).*";
    +
    +    public static final String[] EXCLUDED_PATTERNS = {
    +            CLASS_ACCESS_PATTERN,
    +            "^dojo\\..*",
    +            "^struts\\..*",
    +            "^session\\..*",
    +            "^request\\..*",
    +            "^application\\..*",
    +            "^servlet(Request|Response)\\..*",
    +            "^parameters\\..*"
    +    };
    +
    +}
    

Vulnerability mechanics

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

References

19

News mentions

0

No linked articles in our index yet.