flawopen.com/SQL Injection in JavaScript/Sequelize
Is Sequelize query() safe from SQL injection?
A query parameter is like a sealed value card: SQL receives the value separately from the query instructions. In Sequelize v6, bind sends values separately; replacements safely escapes and inserts values before sending the SQL. Building the query string with untrusted input bypasses both. Neither can stand in for a table or column name.
sequelize.query(
`SELECT * FROM users WHERE id = ${userId}`
)
sequelize.query(
"SELECT id FROM users WHERE id = $id",
{ bind: { id: userId },
type: QueryTypes.SELECT }
)
Keep values out of SQL syntax
In Sequelize v6, replacements are escaped and inserted by Sequelize before the query reaches the database; bind values are sent separately from the SQL text. Both avoid concatenating user values into SQL, but their syntax differs by method and dialect. Parameters cannot represent table names, column names, sort directions, or arbitrary SQL fragments. Map any user-selectable query structure to a fixed application-owned allowlist. Structured model methods can parameterize ordinary values, but raw SQL helpers and literal expressions still need review.
How to audit Sequelize query construction
rg -n 'sequelize\.query\(|Sequelize\.literal\(' --glob '*.{js,ts,mjs,cjs}' .FAQ
Ordinary structured values in model methods are handled by Sequelize's query construction. Still review raw SQL, literal expressions, and application-built strings. Parameterization does not authorize access to a record or validate business rules.
References
- Sequelize v6 documentation — Raw Queries, replacements, and bind parameters
- OWASP — SQL Injection Prevention Cheat Sheet
- flawopen.com — SQL Injection in JavaScript