CWE-707, Improper Neutralization, is the pillar behind the injection family. The product does not ensure, or incorrectly ensures, that structured messages or data are well-formed and meet certain security properties before being read from an upstream component or sent to a downstream component.
If you have met SQL injection, cross-site scripting or OS command injection, you have met children of this entry. It is not language, OS, architecture or technology specific.
How it happens
MITRE explains that a malformed message may be interpreted incorrectly. The typical trigger is a product that prepares a control message, such as a command or a query, that another process must act on. Input that was meant to be data then enters the control part of the message.
Here is a simple illustration with a database query:
# Vulnerable: data becomes part of the control message
query = "SELECT * FROM users WHERE name = '" + name + "'"
cursor.execute(query)
A name containing a quote changes the structure of the query. The database cannot tell which part the developer wrote and which part the user wrote. The same happens with shell commands, HTML pages, LDAP filters and header values.
The record lists no observed CVEs for the pillar itself, since specific injection types are catalogued under their own entries.
What an attacker gains
MITRE's consequence entry is open ended. The impact depends on the downstream component: data theft from a database, script in a browser, commands on a host.
What neutralization means
MITRE defines neutralization as any technique that ensures input and output conform to expectations and are safe. It lists four families:
- Check that the input or output is already safe, which is validation.
- Transform it to be safe, through filtering, encoding or decoding, escaping or unescaping, quoting or unquoting, or canonicalization.
- Prevent the input from being directly supplied by an attacker, with indirect selection that maps external values to internally controlled ones.
- Prevent the input from being processed at all.
How to find it
MITRE notes static analysis can find some instances by modelling data and control flow. Trace each source of outside data to each sink that builds a command, query, document or message. Dynamic testing with hostile characters complements this.
How to fix it
Pick the strongest option available for each sink. Where the downstream component supports separate channels for code and data, use them:
# Fixed: parameters keep data out of the control message
cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
For HTML, encode on output for the exact context. For shells, avoid them and pass argument lists. For values with a small valid set, map to internal constants. Neutralize at the point of use, because only there do you know the downstream syntax.
Dependencies can contain these flaws as well. The free scan at gold.safeguard.sh/scan checks a dependency file in your browser against known vulnerabilities, with no login and no upload.
Quick check
What is the difference between validation and transformation?
Validation checks that input is already safe and rejects it if not. Transformation changes the input, by encoding or escaping for example, so it becomes safe.
Why prefer parameterized queries over escaping?
They keep data and control in separate channels, so the database never has to guess where data ends.