CVE-2026-52888
NocoBase: Sensitive Data Exposure via SQL Blacklist Bypass
CVE-2026-52888 is a medium vulnerability (CVSS 6.8) in Nocobase, published July 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.47%, the 40th percentile. Fixed in @nocobase/plugin-collection-sql 2.0.62.
NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. In 2.0.59 and earlier, NocoBase @nocobase/plugin-collection-sql used the checkSQL() function in packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts with an incomplete keyword blacklist that did not restrict PostgreSQL system catalog tables such as pg_shadow, pg_roles, and pg_stat_activity, allowing an admin-role user to read password hashes and database metadata through the SQL Collection feature. This vulnerability is fixed in 2.1.0-alpha.46.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- High
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.8
NocoBase: Sensitive Data Exposure via SQL Blacklist Bypass
NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. In 2.0.59 and earlier, NocoBase @nocobase/plugin-collection-sql used the checkSQL() function in packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts with an incomplete keyword blacklist that did not restrict PostgreSQL system catalog tables such as pg_shadow, pg_roles, and pg_stat_activity, allowing an admin-role user to read password hashes and database metadata through the SQL Collection feature. This vulnerability is fixed in 2.1.0-alpha.46.
- Record
CVE-2026-52888- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-184, CWE-200
- Updated
- 2026-11-02
EUVDEUVD-2026-44800
6.8
NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. In 2.0.59 and earlier, NocoBase @nocobase/plugin-collection-sql used the checkSQL() function in packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts with an incomplete keyword blacklist that did not restrict PostgreSQL system catalog tables such as pg_shadow, pg_roles, and pg_stat_activity, allowing an admin-role user to read password hashes and database metadata through the SQL Collection feature. This vulnerability is fixed in 2.1.0-alpha.46.
- Record
EUVD-2026-44800- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-v8vm-cqh8-q87q
6.8
NocoBase: Sensitive Data Exposure via SQL Blacklist Bypass
Security Vulnerability Report: Sensitive Data Exposure via SQL Blacklist Bypass
Summary
The checkSQL() function in plugin-collection-sql implements a keyword-based blacklist to prevent dangerous SQL queries from being executed through the SQL Collection feature. However, the blacklist is incomplete: it only checks for a subset of dangerous PostgreSQL system functions and does not restrict access to sensitive system catalog tables such as pg_shadow, pg_roles, or pg_stat_activity.
An authenticated user with the admin role can exploit this to dump PostgreSQL password hashes (pg_shadow), read all NocoBase user credentials (hashed passwords from the users table), and enumerate the full database schema — all data that admin users should never be able to access through the application interface.
Affected Component
File: packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts
export const checkSQL = (sql: string) => {
const dangerKeywords = [
// PostgreSQL — BLOCKED
'pg_read_file',
'pg_read_binary_file',
'pg_stat_file',
'pg_ls_dir',
'pg_logdir_ls',
'pg_terminate_backend',
'pg_cancel_backend',
'current_setting',
'set_config',
'pg_reload_conf',
'pg_sleep',
'generate_series',
// MySQL — BLOCKED
'LOAD_FILE',
'BENCHMARK',
'@@global.',
'@@session.',
// SQLite — BLOCKED
'sqlite3_load_extension',
'load_extension',
];
// NOT BLOCKED: pg_shadow, pg_roles, pg_stat_activity,
// information_schema, users table direct access, etc.
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');
}
};
The execute action in sql.ts passes user-supplied SQL directly through this insufficient check:
// sql.ts — execute action
execute: async (ctx: Context, next: Next) => {
const { sql } = ctx.action.params.values || {};
try {
checkSQL(sql); // ← insufficient validation
} catch (e) {
ctx.throw(400, ctx.t(e.message));
}
// SQL is executed directly against the database
const data = await model.findAll({ attributes: ['*'], limit: 5, raw: true });
ctx.body = { data, fields, sources };
}
Root Cause
The blacklist approach is fundamentally incomplete. It attempts to enumerate every dangerous construct but misses entire categories:
- PostgreSQL system catalog tables —
pg_shadow,pg_authid,pg_roles,pg_stat_activityare not restricted - Application-level sensitive tables —
users(containing hashed passwords) can be queried directly information_schema— full schema enumeration is possible- Schema-qualified variants — even some blocked functions could be bypassed via
pg_catalog.prefix (e.g.pg_catalog.pg_read_filemay bypass checks in older versions)
The correct approach is an allowlist (whitelist) of permitted tables/schemas, not a blacklist of forbidden keywords.
Steps to Reproduce
Prerequisites: A user account with the admin role (has the pm.data-source-manager.collection-sql ACL snippet).
Step 1: Authenticate and obtain a token:
TOKEN=$(curl -s -X POST http://<TARGET>/api/auth:signIn \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"<password>"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['token'])")
Step 2: Dump PostgreSQL password hashes from pg_shadow:
curl -s -X POST http://<TARGET>/api/sqlCollection:execute \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"sql":"SELECT usename, passwd…
- Record
GHSA-v8vm-cqh8-q87q- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-184, CWE-200
- Updated
- 2026-11-02
NVD
6.8
NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. In 2.0.59 and earlier, NocoBase @nocobase/plugin-collection-sql used the checkSQL() function in packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts with an incomplete keyword blacklist that did not restrict PostgreSQL system catalog tables such as pg_shadow, pg_roles, and pg_stat_activity, allowing an admin-role user to read password hashes and database metadata through the SQL Collection feature. This vulnerability is fixed in 2.1.0-alpha.46.
- Record
CVE-2026-52888- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-184, CWE-200
- Updated
- 2026-11-02
OSV
6.8
NocoBase: Sensitive Data Exposure via SQL Blacklist Bypass
NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. In 2.0.59 and earlier, NocoBase @nocobase/plugin-collection-sql used the checkSQL() function in packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts with an incomplete keyword blacklist that did not restrict PostgreSQL system catalog tables such as pg_shadow, pg_roles, and pg_stat_activity, allowing an admin-role user to read password hashes and database metadata through the SQL Collection feature. This vulnerability is fixed in 2.1.0-alpha.46.
- Record
CVE-2026-52888- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-184, CWE-200
- Updated
- 2026-11-02
OSVGHSA-v8vm-cqh8-q87q
6.8
NocoBase: Sensitive Data Exposure via SQL Blacklist Bypass
Security Vulnerability Report: Sensitive Data Exposure via SQL Blacklist Bypass
Summary
The checkSQL() function in plugin-collection-sql implements a keyword-based blacklist to prevent dangerous SQL queries from being executed through the SQL Collection feature. However, the blacklist is incomplete: it only checks for a subset of dangerous PostgreSQL system functions and does not restrict access to sensitive system catalog tables such as pg_shadow, pg_roles, or pg_stat_activity.
An authenticated user with the admin role can exploit this to dump PostgreSQL password hashes (pg_shadow), read all NocoBase user credentials (hashed passwords from the users table), and enumerate the full database schema — all data that admin users should never be able to access through the application interface.
Affected Component
File: packages/plugins/@nocobase/plugin-collection-sql/src/server/utils.ts
export const checkSQL = (sql: string) => {
const dangerKeywords = [
// PostgreSQL — BLOCKED
'pg_read_file',
'pg_read_binary_file',
'pg_stat_file',
'pg_ls_dir',
'pg_logdir_ls',
'pg_terminate_backend',
'pg_cancel_backend',
'current_setting',
'set_config',
'pg_reload_conf',
'pg_sleep',
'generate_series',
// MySQL — BLOCKED
'LOAD_FILE',
'BENCHMARK',
'@@global.',
'@@session.',
// SQLite — BLOCKED
'sqlite3_load_extension',
'load_extension',
];
// NOT BLOCKED: pg_shadow, pg_roles, pg_stat_activity,
// information_schema, users table direct access, etc.
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');
}
};
The execute action in sql.ts passes user-supplied SQL directly through this insufficient check:
// sql.ts — execute action
execute: async (ctx: Context, next: Next) => {
const { sql } = ctx.action.params.values || {};
try {
checkSQL(sql); // ← insufficient validation
} catch (e) {
ctx.throw(400, ctx.t(e.message));
}
// SQL is executed directly against the database
const data = await model.findAll({ attributes: ['*'], limit: 5, raw: true });
ctx.body = { data, fields, sources };
}
Root Cause
The blacklist approach is fundamentally incomplete. It attempts to enumerate every dangerous construct but misses entire categories:
- PostgreSQL system catalog tables —
pg_shadow,pg_authid,pg_roles,pg_stat_activityare not restricted - Application-level sensitive tables —
users(containing hashed passwords) can be queried directly information_schema— full schema enumeration is possible- Schema-qualified variants — even some blocked functions could be bypassed via
pg_catalog.prefix (e.g.pg_catalog.pg_read_filemay bypass checks in older versions)
The correct approach is an allowlist (whitelist) of permitted tables/schemas, not a blacklist of forbidden keywords.
Steps to Reproduce
Prerequisites: A user account with the admin role (has the pm.data-source-manager.collection-sql ACL snippet).
Step 1: Authenticate and obtain a token:
TOKEN=$(curl -s -X POST http://<TARGET>/api/auth:signIn \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"<password>"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['token'])")
Step 2: Dump PostgreSQL password hashes from pg_shadow:
curl -s -X POST http://<TARGET>/api/sqlCollection:execute \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"sql":"SELECT usename, passwd…
- Record
GHSA-v8vm-cqh8-q87q- CVSS 3.1
- 6.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N - Weakness
- CWE-184, CWE-200
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@nocobase/plugin-collection-sqlnpm |
before 2.0.62 | 2.0.62 |
@nocobase/plugin-collection-sqlnpm |
2.1.0-alpha.1 up to 2.1.0-alpha.46 | 2.1.0-alpha.46 |
@nocobase/plugin-collection-sqlnpm |
2.1.0-beta.1 up to 2.1.0-beta.45 | 2.1.0-beta.45 |
History
| When | Changed | Sources |
|---|---|---|
| 2026-11-02 | created | CVE List, EUVD, GitHub Advisories, NVD, OSV |
References
github.com/nocobase/nocobase/security/advisories/GHSA-v8vm-cqh8-q87q
github.com/nocobase/nocobase/commit/87c548969ce9258dd7f0d9571c9453ae10bc3fc4
github.com/nocobase/nocobase/releases/tag/v2.1.0-alpha.46
nvd.nist.gov/vuln/detail/CVE-2026-52888
github.com/nocobase/nocobase/pull/9683
github.com/nocobase/nocobase/commit/4aecb60d151a9002004dcf984f63d62f17a6cb45
Left out here: the rest of 2 source descriptions. The JSON record has them.