Skip to content

Fix Unsafe SQL Queries in Knex Example Files#446

Open
MatrixNeoKozak wants to merge 2 commits into
fastify:mainfrom
MatrixNeoKozak:scout-improvement-1780252225020
Open

Fix Unsafe SQL Queries in Knex Example Files#446
MatrixNeoKozak wants to merge 2 commits into
fastify:mainfrom
MatrixNeoKozak:scout-improvement-1780252225020

Conversation

@MatrixNeoKozak
Copy link
Copy Markdown

The Knex example files (example/example-knex-mysql.js and example/example-knex.js) contained unsafe raw SQL queries that directly interpolated user-supplied values (this.route and key) into SQL strings, making them vulnerable to SQL injection. This change replaces those raw queries with proper parameterized queries using Knex's binding syntax, which prevents injection attacks and improves safety. The changes are necessary because the examples are distributed as part of the package and could be used as reference by users.

try {
// NOTE: MySQL syntax FOR UPDATE for read lock on counter stats in row
const row = await trx('rate_limits')
.whereRaw('route = ? AND source = ? FOR UPDATE', [cond.route || '', cond.source]) // Create read lock
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL-injection protected here because this uses parameter bindings.

// Optimization - no need to UPDATE if max has been reached.
if (d.count < max) {
await trx
.raw('UPDATE rate_limits SET count = ? WHERE route = ? AND source = ?', [d.count + 1, cond.route, key])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL-injection protected here because this uses parameter bindings.

process.nextTick(cb, null, { current: d.count + 1, ttl: d.ttl })
} else {
await trx
.raw('INSERT INTO rate_limits(route, source, count, ttl) VALUES(?,?,1,?) ON DUPLICATE KEY UPDATE count = 1, ttl = ?', [cond.route, key, d?.ttl || ttl, ttl])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQL-injection protected here because this uses parameter bindings.

Comment thread example/example-knex.js
})
} else {
trx
.raw(`INSERT INTO RateLimits(Route, Source, Count, TTL) VALUES('${this.route}', '${key}',1,${d.TTL || ttl}) ON CONFLICT(Route, Source) DO UPDATE SET Count=Count+1,TTL=${ttl}`)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this query is generally unsafe because it interpolates values directly into the SQL string.
That said, the values appear to come from plugin/user configuration rather than directly from a network client. So much less critical than the PR description suggests.

Copy link
Copy Markdown
Member

@jean-michelet jean-michelet Jun 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok for changing this, let's keep the other queries as they are

@MatrixNeoKozak
Copy link
Copy Markdown
Author

I have reverted the changes to example/example-knex-mysql.js as they were already using safe parameter bindings, and kept the security fixes for the unsafe string interpolations in example/example-knex.js as requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants