CWE-794 says the product does not filter all instances of a special element before sending data downstream. Some get removed, others remain.
MITRE separates two cases. Sequential elements appear next to each other. Non-sequential elements appear several times in different places.
How it happens
Sequential case: a filter looks for a pair or a run and removes it once, and the removal exposes another. Think of a path filter that strips dot-dot-slash a single time. Feeding it a longer run leaves a working sequence behind.
Non-sequential case: the filter handles a match in one spot and moves on, so a second copy further along survives.
def strip_tags(s):
start = s.find("<")
end = s.find(">", start)
return s[:start] + s[end + 1:] # handles one tag only
With input containing two tags, the second is passed along intact.
What an attacker gains
The record lists integrity and an unexpected state. It has no observed CVEs. The impact is set by the downstream interpreter.
How to find it
- Test with the same special element repeated back to back and spread across the input.
- Check whether a filter loops until nothing changes or runs once.
- Review any hand-written parser or tag stripper. They are rarely complete.
How to fix it
- Use a real parser or an established sanitizer library for structured formats such as HTML.
- If you write a filter, loop until the output stops changing, or better, reject on any match.
- Allowlist the expected characters.
- Use encoding or parameter binding at the destination.
- Add tests for runs and scattered copies.
Quick check
What is the difference between this and CWE-793?
CWE-793 covers filtering only one instance. CWE-794 covers not filtering all instances, in runs or scattered across the input.