Developers should never trust user input. Even when you think you’ve sanitized everything and even when you’re using the familiar ? placeholder in Node.js MySQL libraries mistakes and wrong assumptions can still leave your app vulnerable.
A few essential points:
- ? placeholders protect values, not SQL structure. They safely substitute data values, but they do not and cannot be used for identifiers, SQL keywords, or fragments you build by string concatenation. If you concatenate table names, column names, ORDER BY clauses, or entire SQL snippets with user input, a placeholder won’t help.
- Misusing escaping, trusting client-side validation, or doing shallow sanitization (like stripping a few characters) can be bypassed. There are second‑order injections (stored malicious input executed later), encoding tricks, and edge cases with JSON and binary data.
- The typical Node.js + MySQL pitfalls: building queries with template strings, using unvalidated inputs for identifiers, relying on naive input filters, or assuming middleware has already made the input safe.
Endpoints
- api/v1/users/filter?name=
- api/v1/blogs/filter
- api/v1/blogs/filter?author=
Walkthrough
We are logged in as Alice.
If we visit this endpoint api/v1/blogs/filter:

If we use something like api/v1/blogs/filter?author= from any author for example Alice or Bob we make a request like:


But let’s say we have another endpoint api/v1/users/filter?name=. Remember we are logged in as Alice, so our request would be:
api/v1/users/filter?name=Alice as shown below

Our SQL request would look like this :
Built users query: SELECT * FROM users WHERE name=? Data: [ 'Alice' ]

What if we try to access Bob’s information?
We can’t, we get Unauthorized.

What if we change the name parameter to something different, for example: api/v1/users/filter?foo=bar

Server running on port 3000
Built users query: SELECT * FROM users WHERE name=? Data: [ 'Alice' ]
Built users query: SELECT * FROM users WHERE foo=? Data: [ 'bar' ]
We were able to modify the query as you can see above. That means there is a potential for SQL injection for example, to make a condition always true one common payload is OR 1=1. First, let’s explore more: what if we sent something like api/v1/users/filter?name%20bar=bar
Server running on port 3000
Built users query: SELECT * FROM users WHERE name=? Data: [ 'Alice' ]
Built users query: SELECT * FROM users WHERE foo=? Data: [ 'bar' ]
Built users query: SELECT * FROM users WHERE name bar=? Data: [ 'bar' ]

We fully controlled the query, which means if we sent something like OR 1=1 it could return true and dump information:
Server running on port 3000
Built users query: SELECT * FROM users WHERE name=? Data: [ 'Alice' ]
Built users query: SELECT * FROM users WHERE foo=? Data: [ 'bar' ]
Built users query: SELECT * FROM users WHERE name bar=? Data: [ 'bar' ]
Built users query: SELECT * FROM users WHERE name OR 1=? Data: [ '1' ]


Quick mitigations and takeaways
- Always use parameterized queries / prepared statements for data values.
- Never inject user input into SQL structure (identifiers, keywords, clause fragments). If you must vary structure, use strict whitelists or server-side mappings.
- Validate and coerce types server-side (numbers, enums, ranges) instead of relying on shallow string sanitization or client-side checks.
- Apply least privilege for database accounts and avoid exposing powerful permissions to the application user.
- Log unexpected input and monitor query patterns to detect abuse or probing.
- Defense in depth: input validation, prepared statements, minimal DB permissions, and runtime monitoring.