Skip to content

Oracle datasource connector is still vulnerable to identifier SQL injection — incomplete fix of GHSA-qqf5-x7mj-v43p

High
mjashanks published GHSA-xj29-x47g-9w2c Jul 22, 2026

Package

npm budibase (npm)

Affected versions

<3.40.0

Patched versions

3.40.0

Description

Summary

GHSA-qqf5-x7mj-v43p (fixed in 3.39.19) addressed SQL identifier injection in Budibase's PostgreSQL, MySQL, and SQL Server datasource connectors by adding dedicated identifier-quoting helpers. The same release left the Oracle connector untouched. Oracle's post-write row lookup still wraps the table name in double quotes without escaping, so an Oracle datasource whose table name contains a double-quote character produces a second-order SQL injection that executes as the datasource's database user.

The unfixed sink

packages/server/src/integrations/oracle.ts:577, in OracleIntegration.query(), after a CREATE or UPDATE:

const lastRow = await this.internalQuery({
  sql: `SELECT * FROM "${json.table.name}" WHERE ROWID = '${response.lastRowid}'`,
})

json.table.name is interpolated directly inside a double-quoted identifier with no escaping and no parameter binding. A table name containing a " closes the identifier early and lets the remainder be parsed as SQL. (response.lastRowid is the Oracle-generated ROWID and is not attacker-controllable; the sole vector is the table name.)

Why the 3.39.19 fix does not cover it

The patch introduced quotePostgresIdentifier, quoteMySqlIdentifier, and quoteSqlServerIdentifier in packages/server/src/integrations/utils/sqlIdentifiers.ts and applied them at postgres.ts:358 and mysql.ts:306. There is no quoteOracleIdentifier, and oracle.ts was not modified. The Oracle ROWID-lookup sink is a different code path from the three introspection sinks the advisory fixed (Postgres SET search_path, MSSQL INFORMATION_SCHEMA, MySQL DESCRIBE), so it was missed.

Where the table name comes from

json.table.name is the Oracle table name fetched during schema introspection from user_tables.TABLE_NAME (oracle.ts, buildSchema, ~line 185) and stored verbatim in Budibase's metadata. Oracle permits quoted identifiers that contain a ".

Reproduction

  1. A table whose name contains a double-quote exists in the connected Oracle database — pre-existing, or created by a principal able to run DDL on that database (the Budibase connection user, or a Budibase builder via schema management). For example a table named:
    EMP" UNION SELECT username, password, account_status, 1 FROM dba_users --
  2. Budibase introspects the schema and stores the name verbatim.
  3. Any Budibase user with WRITE permission on that table performs a row create or update.
  4. After the write, oracle.ts:577 runs the ROWID lookup with the table name interpolated; the injected SQL executes as the datasource's Oracle user, and its rows are returned to the caller as the "created/updated" row.

Impact

Arbitrary SQL execution against the Oracle database as the configured connection user — reading or modifying any data that user can reach, beyond the table/row permissions Budibase enforces. The injected SQL is not bounded to Budibase's own schema, so the impact can extend to other database objects and users.

Remediation

Add a quoteOracleIdentifier helper that wraps the identifier in "..." and doubles any embedded " (mirroring quotePostgresIdentifier), and apply it to the table name at oracle.ts:577 — and to any other raw identifier interpolation in oracle.ts. Better still, route the ROWID lookup through the same parameterized/Knex path used by the rest of the query builder so the identifier is quoted by the driver.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
High
Privileges required
High
User interaction
Required
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')

The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component. Without sufficient removal or quoting of SQL syntax in user-controllable inputs, the generated SQL query can cause those inputs to be interpreted as SQL instead of ordinary user data. Learn more on MITRE.

Credits