Safeguard
Application Security•

CWE-157 Paired Delimiters: Unbalanced Quotes and Brackets

Missing closing quotes and brackets have crashed databases and caused overflows. How CWE-157 works and how to handle paired delimiters safely.

Safeguard Security Team
3 min read

CWE-157 covers products that do not properly handle the characters that start and end a group, such as parentheses, brackets, braces, angle brackets and quotes. The pair is a promise: whatever opens will close. Attackers send input that breaks the promise.

Parsers for queries, mail, markup and protocols are the usual targets. If your code looks for a closing character and trusts that it exists, read on.

How it happens

Code finds an opener, then searches for the matching closer, then uses the position it found.

# Vulnerable: find returns -1 when the closing quote is missing
start = text.index('"') + 1
end = text.find('"', start)
value = text[start:end]   # with end == -1 this silently drops the last character

The bug is not always a crash. A missing closer can make a length calculation wrong, and in lower level languages that becomes a memory error.

Observed examples show each outcome. CVE-2004-0956 is a crash from a missing paired delimiter, an open double quote with no closing one. CVE-2000-1165 is a crash from a message without a closing angle bracket. CVE-2005-2933 is a buffer overflow from a mailbox name with an opening double quote and no closing one, causing a larger copy than expected.

What an attacker gains

MITRE lists integrity impact as unexpected state. The examples add denial of service by crash and, in the overflow case, memory corruption.

How to find it

No detection methods are listed, so test and review.

  • Send every opener without its closer, closers without openers, and wrongly ordered or nested pairs.
  • Read each parser for code that assumes a closer exists. Check every search that can return not found.
  • Fuzz protocol fields with truncated input.

How to fix it

  1. Treat a missing closer as invalid input. Reject it with an error instead of guessing where the value ends.
start = text.index('"') + 1
end = text.find('"', start)
if end == -1:
    raise ValueError("unterminated quoted value")
value = text[start:end]
  1. Anticipate that delimiters will be injected, removed or manipulated.
  2. Use an allowlist for acceptable input and reject what does not conform.
  3. Base any copy length on the data you verified, not on an assumption about the shape of the input.

Quick check

Is an unbalanced quote only a crash risk?

No. CVE-2005-2933 turned a missing closing quote into a buffer overflow because the copy was larger than expected.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.