CWE-181, Incorrect Behavior Order: Validate Before Filter, happens when a product validates data before it is filtered. Validation then cannot see data that becomes invalid after the filtering step.
How it happens
Filters remove or replace characters. If an attacker places forbidden characters in between the pieces of a dangerous pattern, the filter can stitch the pieces together.
MITRE gives two examples, CVE-2002-0934 and CVE-2003-0282. In both, a directory traversal flaw let attackers read, modify or overwrite files through invalid characters placed between two dots. The filter removed the invalid characters and left a ".." sequence.
# Vulnerable: validate, then filter
def safe_name(s):
if ".." in s:
raise ValueError
return s.replace("*", "") # ".*." passes, then becomes ".."
# Fixed: filter first, validate the result, or reject bad characters outright
def safe_name(s):
s = s.replace("*", "")
if ".." in s:
raise ValueError
return s
Rejecting is better than stripping. If a character is not allowed, fail the request.
What an attacker gains
MITRE lists access control impact, specifically bypass of a protection mechanism.
How to find it
No detection methods are listed. Review any code that both validates and strips, and check the order. Test by inserting forbidden characters inside a blocked pattern and see whether the output contains the pattern.
How to fix it
General steps, since no mitigations are listed.
- Apply all filtering, then validate the final string.
- Prefer an allowlist of permitted characters.
- Reject disallowed input instead of silently removing it.
Quick check
Why is rejecting safer than stripping?
Stripping changes the value and can assemble a dangerous pattern. Rejecting leaves nothing to assemble.