CWE-103, Struts: Incomplete validate() Method Definition, hits Java web applications built on Struts. The validator form either does not define a validate() method, or defines one but never calls super.validate().
It is an easy slip to make. A developer adds custom checks to validate(), tests them, and ships, without noticing that the framework's own rule based checks no longer run.
How it happens
In a Struts form bean, the base class validate() is what runs the Validation Framework against the rules in the configuration. If you override the method and skip the call to the parent, the framework never sees the form.
// Vulnerable: custom check only, framework validation never runs
public class RegisterForm extends ValidatorForm {
private String email;
@Override
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if (email == null || email.isEmpty()) {
errors.add("email", new ActionMessage("error.email.required"));
}
return errors; // missing: super.validate(mapping, request)
}
}
MITRE states the effect directly: if the code does not call super.validate(), the Validation Framework cannot check the contents of the form against a validation form, so validation is disabled for that form.
What an attacker gains
MITRE lists an unexpected state outcome, which varies by context. It adds a second, wider point: although J2EE applications are not generally susceptible to memory corruption, if the application interfaces with native code that does not check array bounds, an attacker may use an input validation mistake in the Java layer to launch a buffer overflow.
How to find it
Static analysis (SAST) can find some instances, according to MITRE. A quick manual check: search form beans that extend a validator class and confirm each overrides validate() and calls super.validate() inside it.
How to fix it
MITRE's fix is to implement the validate() method and call super.validate() within it.
@Override
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = super.validate(mapping, request); // framework rules first
if (errors == null) {
errors = new ActionErrors();
}
// custom checks here
return errors;
}
Call the parent first, then add your own checks to the same error collection. A unit test that submits a deliberately bad value defined in the XML rules, and expects an error, will catch a regression.
Quick check
What does skipping super.validate() do?
It disables the Validation Framework for that form, so the rules in the validation configuration are never applied to its fields.