Skip to content

CWE-104: Struts: Form Bean Does Not Extend Validation Class

Overview

This vulnerability occurs when Struts form beans do not extend the proper validation base class (ActionForm, ValidatorForm, or DynaValidatorForm), preventing the framework's built-in validation mechanisms from executing. This allows unvalidated user input to reach application logic.

OWASP Classification

A05:2025 - Injection

Risk

High: Bypassing Struts validation framework exposes the application to injection attacks, data integrity issues, and business logic flaws. Attackers can submit malicious payloads that would normally be caught by framework validation.

Remediation Steps

Core principle: Do not rely on informal warnings; enforce secure usage through APIs, tooling, and tests rather than documentation alone.

Locate the Non-Validating Form Bean

Review the security findings to identify which form bean class doesn't extend a proper validation class:

  • Check if the class is a plain POJO without extending ActionForm
  • Look for form beans that don't integrate with Struts validation framework
  • Identify which user inputs are processed without validation
  • Trace the data_path from source (HTTP parameters) to sink (business logic)

Extend Proper Validation Class

Update the form bean to extend an appropriate Struts validation class:

  • For declarative validation: Extend ValidatorForm (works with validation.xml)
  • For dynamic forms: Use DynaValidatorForm for dynamic form beans
  • Minimum requirement: Extend ActionForm at a minimum and implement validate() method
  • Never use plain POJOs: All form beans must integrate with Struts lifecycle

Implement Declarative Validation

Define validation rules in validation.xml for common patterns:

  • Create validation.xml configuration: Map form name to validation rules
  • Use built-in validators: Apply required, email, minlength, maxlength, range validators
  • Specify error messages: Define user-friendly error messages for validation failures
  • Leverage framework validators: Let Struts handle common validation patterns automatically

Add Programmatic Validation

Override the validate() method for complex business rules:

  • Call super.validate(): Execute declarative validation first, then add custom checks
  • Return ActionErrors object: Always return ActionErrors (never null), add field-specific errors
  • Validate all user inputs: Check every field that comes from untrusted data sources
  • Implement business logic validation: Check constraints that go beyond format/type validation

Use Type-Safe Form Beans

Define proper field types and getters/setters:

  • Use correct data types: Define fields as int, Date, boolean instead of String for everything
  • Avoid Object type: Don't use Object or String for all fields - let Struts perform type conversion
  • Provide proper getters/setters: Follow JavaBean naming conventions
  • Leverage type conversion: Let the framework convert and validate types automatically

Test the Form Validation

Verify the fix handles both valid and malicious inputs:

  • Test with valid data: Ensure legitimate form submissions work correctly
  • Test with invalid data: Verify validation rejects wrong types, missing required fields, excessive lengths
  • Test with injection payloads: Try SQL injection, XSS, command injection in form fields
  • Test edge cases: Boundary values, special characters, null values, empty strings

Common Vulnerable Patterns

Using plain POJO without extending ActionForm

// Plain POJO - no validation integration
public class UserData {
    private String username;
    private String password;

    // Getters and setters only
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
}

Why this is vulnerable:

  • Missing validation.xml configuration
  • Form beans that don't integrate with Struts lifecycle
  • Bypassing framework validation with custom routing

Secure Patterns

Extend ValidatorForm for framework integration

import org.apache.struts.validator.ValidatorForm;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;

// Properly extends ValidatorForm for framework integration
public class UserForm extends ValidatorForm {
    private String username;
    private String password;

    @Override
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
        // Declarative validation from validation.xml runs first
        ActionErrors errors = super.validate(mapping, request);

        // Add custom validation logic
        if (username != null && username.contains("admin")) {
            errors.add("username", 
                new ActionMessage("error.username.reserved"));
        }

        return errors;
    }

    // Getters and setters
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}
validation.xml
<form-validation>
    <formset>
        <form name="userForm">
            <field property="username" depends="required,minlength,maxlength">
                <arg key="label.username"/>
                <var><var-name>minlength</var-name><var-value>3</var-value></var>
                <var><var-name>maxlength</var-name><var-value>20</var-value></var>
            </field>
            <field property="password" depends="required,minlength">
                <arg key="label.password"/>
                <var><var-name>minlength</var-name><var-value>8</var-value></var>
            </field>
        </form>
    </formset>
</form-validation>

Why this works: Extending ValidatorForm integrates the form bean with the Struts validation framework, enabling automatic validation from validation.xml (declarative) combined with custom validation logic in the validate() method. The framework automatically validates data types, formats, lengths, and required fields before the form reaches application logic, preventing malformed or malicious data from being processed.

Additional Resources