CWE-168 covers input where two or more special characters or reserved words are in an inconsistent relationship. MITRE's examples: paired characters that appear in the wrong order, or special characters that are not properly nested.
Parsers for query languages, markup, expressions and protocols deal with this constantly. Any code that counts or matches openers and closers can be fooled.
How it happens
A parser or validator handles pairs with a simple rule, such as count the opening and closing characters and check that the numbers match. Equal counts do not mean valid structure. A closer before its opener has the same count as the correct order.
# Vulnerable: equal counts do not prove correct nesting
def balanced(s: str) -> bool:
return s.count("(") == s.count(")")
balanced(")(") # True, but the structure is wrong
The record lists no observed example CVEs for this entry. The consequences MITRE lists are wide, which is a signal about how different downstream parsers can react: availability loss through a crash, exit or restart, access control bypass, bypass of protection mechanisms, hiding activities, and impact on non-repudiation.
What an attacker gains
Each recorded impact follows from a misparse.
- Crash, exit or restart, when the parser hits a state it did not plan for.
- Bypass of protection mechanisms and access control, when a check and a consumer read the structure differently.
- Hiding activities and weakening non-repudiation, when logs or records are built from input whose structure was misread.
How to find it
MITRE lists no detection methods. Test directly.
- Send reversed pairs, interleaved pairs and mismatched types, such as an opening parenthesis closed by a bracket.
- Include deeply nested input to look for stack or resource problems.
- Compare the validator's reading with the consumer's.
How to fix it
- Anticipate that inconsistent special elements will be injected or manipulated.
- Check structure with a stack, not a counter. Push openers, pop on closers, and fail on a mismatch or leftover.
PAIRS = {")": "(", "]": "[", "}": "{"}
def balanced(s: str) -> bool:
stack = []
for ch in s:
if ch in "([{":
stack.append(ch)
elif ch in PAIRS:
if not stack or stack.pop() != PAIRS[ch]:
return False
return not stack
- Limit nesting depth and input length.
- Use a real parser for structured formats and reject input that does not conform.
- Consider consistency across related fields as well as within one field.
Quick check
Why is counting not enough?
Counts ignore order. A closing character before an opening one still balances the totals but breaks the structure.