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
DynaValidatorFormfor dynamic form beans - Minimum requirement: Extend
ActionFormat a minimum and implementvalidate()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,rangevalidators - 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,booleaninstead ofStringfor everything - Avoid Object type: Don't use
ObjectorStringfor 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; }
}
<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.