When an application builds a query from user input, the query is code. If the input can change what that code means, the attacker is no longer just supplying data. They are editing your logic.
CWE-943 is the class weakness for exactly this: the product generates a query to access or manipulate data in a data store, but does not neutralize, or incorrectly neutralizes, special elements that can modify the intended logic of the query. MITRE marks it as language independent. It applies to any team that touches a database, a directory service or a document store.
SQL injection is the best known child of this class. MITRE is explicit that it is far from the only one. The extended description names HTSQL, LDAP, DQL, XQuery, XPath and "NoSQL" languages as targets too.
How it happens
The pattern is always the same. A trusted query template gets combined with untrusted input, and the combination is parsed by an engine that cannot tell which part came from whom.
Depending on what the query language allows, an attacker may be able to:
- Modify the intended selection criteria, changing which records are returned, modified or manipulated.
- Append additional commands to the query.
- Return more entities than intended, or fewer.
- Change the sort order in an unexpected way.
That last pair matters more than it looks. MITRE gives a clear example: if a query is expected to return a single entity that identifies an administrative user, and an attacker can change which entities come back, the code may return a regular user's record and then wrongly assume that user has administrative privileges. The logic after the query trusted the shape of the result.
Here is the classic string concatenation case, adapted from the MITRE demonstrative example. The code restricts results to items owned by the signed in user:
# Vulnerable: input is concatenated into the query text
query = ("SELECT * FROM items WHERE owner = '" + user_name +
"' AND itemname = '" + item_name + "'")
cursor.execute(query)
If the attacker submits name' OR 'a'='a as the item name, the condition becomes always true and the owner restriction stops mattering. Every item in the table comes back.
The fix is a parameterized query, which keeps data and query structure apart:
# Fixed: placeholders, values sent separately
cursor.execute(
"SELECT * FROM items WHERE owner = %s AND itemname = %s",
(user_name, item_name),
)
The NoSQL version
Teams sometimes assume that moving off SQL removes injection. It does not. Document databases accept structured query objects, and if request parsing turns attacker input into an object instead of a string, operators can slip in.
The observed examples on the MITRE page show this is real. CVE-2024-50672 is a NoSQL injection in an eLearning course builder that allows password resets using a query processed by the Mongoose find function. CVE-2020-35666 is a NoSQL injection in a platform as a service product using a MongoDB operator. CVE-2021-20736 is another, in a team collaboration product. And CVE-2014-2503 shows injection using Documentum Query Language, which is neither SQL nor NoSQL in the usual sense.
A typical vulnerable shape in Node:
// Vulnerable: req.body.email could be an object such as an operator expression
const user = await User.findOne({ email: req.body.email, resetToken: req.body.token });
If the JSON body carries an operator object instead of a plain string for the token, the match condition can be made to succeed without knowing the real value. A safer version insists on the expected type before querying:
// Fixed: reject anything that is not a plain string
const { email, token } = req.body;
if (typeof email !== "string" || typeof token !== "string") {
return res.status(400).end();
}
const user = await User.findOne({ email, resetToken: token });
Schema validation at the edge of your API does this more cleanly than ad hoc checks.
What an attacker gains
The MITRE record lists these consequences, varying by context:
- Bypassing a protection mechanism, such as an authentication or ownership check.
- Reading application data the query was meant to restrict.
- Modifying application data, where the query language can write.
- Effects on availability, and on access control more broadly.
The password reset CVE above is a good illustration of what that looks like in practice. The query was part of an authentication flow, so bending it meant taking over accounts.
How to find it
MITRE lists automated static analysis as a detection method. SAST can trace user input into query construction and flag concatenation or unsafe object building. It will find some instances, not all.
Practical checks you can run yourself:
- Search the codebase for queries built with string concatenation or formatting, in every language you use.
- Search for query objects built straight from request bodies, query strings or headers.
- For each database layer, list the special elements of its query language and check that input is neutralized for that language, not just for SQL.
- Test with inputs containing quotes, operator syntax and unexpected types, and watch for changed result counts or errors.
- Review logic that assumes a query returns exactly one row. That assumption is where a changed selection turns into a privilege error.
How to fix it
The record does not list formal mitigations for this class, so these steps follow directly from the weakness definition.
- Separate data from query structure. Use parameterized queries or prepared statements wherever the engine supports them.
- Neutralize for the right language. Where parameters are not available, escape special elements using the rules of that specific query language.
- Enforce types and shapes. Validate that each input is the type you expect before it reaches the query. Reject objects where strings belong.
- Do not let result logic assume too much. Check that a query returned the entity you intended, and verify authorization separately from selection.
- Limit what the query account can do. A read only account cannot append destructive commands.
Also keep your libraries current. Several of the CVEs above are in products and frameworks rather than in your own code, which is why a dependency inventory belongs next to code review.
Try it yourself
This demo shows a SAST scan finding injectable query construction in source code.
Click through it at your own pace, or open it full screen.
To check the libraries your project pulls in, try the free in-browser scan at gold.safeguard.sh/scan. No login, your file stays on your machine, up to 100 dependencies. Reachability analysis, which checks whether your code actually calls a vulnerable function, helps you decide which findings to fix first.
Quick check
Is CWE-943 only about SQL?
No. It is a class weakness covering any query language, including LDAP, XPath, XQuery, DQL, HTSQL and NoSQL languages.
Why can changing the number of returned rows be dangerous?
If the code expects exactly one entity, such as an administrative user, and an attacker changes which entity returns, the code may treat a regular user as an administrator.
Does moving to a document database remove the risk?
No. The observed examples include NoSQL injections that use operators through a function such as Mongoose find.