NocoBase versions up to 2.0.8 expose a critical SQL injection vulnerability in the @nocobase/plugin-workflow-sql plugin. Attackers need only trigger a workflow with a SQL node that uses user-controlled template variables. The plugin directly substitutes these variables into raw SQL strings without escaping or parameterization, granting arbitrary SQL execution.
This flaw affects all deployments through 2.0.8. NocoBase, an open-source no-code/low-code platform for internal tools, relies on workflows to automate tasks across its collections—think custom CRMs or dashboards pulling from Postgres or MySQL. Admins often build these workflows with SQL nodes for complex queries, inserting placeholders like {{$context.data.nickname}} from trigger data. That’s the entry point.
Vulnerability Mechanics
In SQLInstruction.ts (line 28), the code calls processor.getParsedValue() on the node’s SQL config:
// SQLInstruction.ts:28
const sql = processor.getParsedValue(node.config.sql || '', node.id).trim();
This swaps placeholders with raw user input from the workflow context. It then runs the string directly via Sequelize:
// SQLInstruction.ts:35
const [result] = await collectionManager.db.sequelize.query(sql, {
transaction: this.workflow.useDataSourceTransaction(dataSourceName, processor.transaction),
});
No bind parameters. No quoting. If an admin sets up a SQL node like SELECT * FROM users WHERE nickname = '{{$context.data.nickname}}', any user creating a record with a malicious nickname injects SQL. In the proof-of-concept, ' UNION SELECT 1,version(),current_user -- dumps the Postgres version (16.13 on Debian) and current user into the result set.
Proof of Concept Steps
Reproduce it in minutes:
- Log in as admin.
- Create a collection-trigger workflow on the
userstable (after create mode). - Add SQL node:
SELECT id, nickname, email FROM users WHERE nickname = '{{$context.data.nickname}}'. - Enable workflow.
- Regular user creates account with
nickname=' UNION SELECT 1,version(),current_user --. - Workflow runs; result shows DB version in
nicknamefield.
Output snippet:
[
{
"id": 1,
"nickname": "PostgreSQL 16.13 (Debian 16.13-1.pgdg13+1) on x86_64-pc-linux-gnu...",
"email": "nocobase"
}
]
Impact and Why It Matters
Attackers gain full database read/write access. Extract credentials from users tables. Dump sensitive collections. Alter records or drop tables. Severity hinges on DB user privileges—in NocoBase’s default Docker setup, it runs as superuser. Total compromise.
Why care? NocoBase powers production internal apps at scale (10k+ GitHub stars, active community). Workflows handle real data flows: user signups, payment triggers, API integrations. A single vulnerable SQL node turns user input into DB takeover. Even low-priv users suffice if workflows trigger on public actions like registrations.
Default Docker image uses postgres superuser. Self-hosted setups often mirror this for simplicity. No auth on workflows means unauthenticated exploits if triggers expose them.
Mitigation and Fix
Upgrade to 2.0.9 or later—advisory implies the patch. Manually, swap string substitution for Sequelize binds:
// SQLInstruction.ts
- const sql = processor.getParsedValue(node.config.sql || '', node.id).trim();
+ const { sql, bind } = processor.getParsedValueAsParams(node.config.sql || '', node.id);
const [result] = await collectionManager.db.sequelize.query(sql, {
+ bind,
transaction: ...
});
Audit all workflows for SQL nodes with templates. Disable or rewrite them. Run DB as least-priv user (e.g., read-only for queries). Monitor logs for suspicious queries like UNIONs.
Fair assessment: NocoBase moves fast (weekly releases), but this highlights no-code pitfalls—admins build “simple” automations that bite back. Parameterization is ORM 101; skipping it here risks real breaches. If you’re on NocoBase, patch now and review workflows.