CVE-2026-55410: NocoBase backup restore schema name allows command injection

Published Jul 15, 2026
·
Updated

Summary NocoBase @nocobase/plugin-backups 2.0.57 restores PostgreSQL backups by interpolating the backup metadata schema name into shell command strings that are executed with Node.js childprocess.exec(). A backup-management user who can restore an uploaded PostgreSQL backup with forced schema restore can place shell metacharacters in metadata.json under database.schema, causing arbitrary commands to execute as the NocoBase server process during restore.

The vulnerable plugin is included in the default @nocobase/preset-nocobase package and is guarded by the backup-management ACL snippet (backups: / backup:). This is not unauthenticated; the attacker must have backup restore privileges or equivalent access to the restore API/CLI.

Details Affected product evidence: - Ecosystem/package: npm package @nocobase/plugin-backups from packages/plugins/@nocobase/plugin-backups/package.json. - Tested vulnerable version: 2.0.57 (packages/plugins/@nocobase/plugin-backups/package.json:1-16). - Tested commit: e03d267362b3426f484c28783020b4a2a08911e8. - Default/common inclusion: @nocobase/preset-nocobase depends on and lists @nocobase/plugin-backups 2.0.57 as built in (packages/presets/nocobase/package.json:22-24, packages/presets/nocobase/package.json:115-128). - Affected range estimate: at least the tested 2.0.57 checkout. Earlier/later versions were not tested. - Patched version: unknown/not available in this local checkout.

Source-to-sink path: - The plugin registers backup-management snippets for backups: and backup:, so the restore API is intended for roles granted backup-management permissions (packages/plugins/@nocobase/plugin-backups/src/server/plugin.ts:51-59). - The backup restore-upload action accepts request body/query force and passes it as forceSchemaRestore to RestoreManager.restore() (packages/plugins/@nocobase/plugin-backups/src/server/resourcers/backup-cli.ts:40-42, packages/plugins/@nocobase/plugin-backups/src/server/resourcers/backup-cli.ts:200-211). - RestoreManager decompresses the uploaded backup archive, reads metadata.json, and parses attacker-controlled JSON metadata (packages/plugins/@nocobase/plugin-backups/src/server/managers/restore.ts:203-215, packages/plugins/@nocobase/plugin-backups/src/server/managers/restore.ts:257-267). - When forceSchemaRestore is true and the database dialect is PostgreSQL, the schema-mismatch check is skipped (packages/plugins/@nocobase/plugin-backups/src/server/managers/restore.ts:270-300). Existing tests confirm forced schema restore intentionally allows a metadata schema mismatch (packages/plugins/@nocobase/plugin-backups/src/server/tests/managers/restore.test.ts:336-356) and that the API passes forceSchemaRestore: true when force=true is supplied (packages/plugins/@nocobase/plugin-backups/src/server/tests/managers/restore.test.ts:377-409). - The parsed metadata.database.schema is passed into this.#dbAdapter.restore(path.join(extractedDir, dbFile), metadata.database.schema) (packages/plugins/@nocobase/plugin-backups/src/server/managers/restore.ts:427-448). - For PostgreSQL, if the backup schema differs from the target schema, PostgresAdapter.restore() assigns srcSchema = schema || 'public' and builds pgRestoreCommand using -n ${srcSchema} with no quoting or argument array (packages/plugins/@nocobase/plugin-backups/src/server/adapters/database.ts:350-420). - #restoreSchema() also interpolates srcSchema and targetSchema directly into SQL strings and then calls run(pgRestoreCommand, ...) (packages/plugins/@nocobase/plugin-backups/src/server/adapters/database.ts:423-451). - run() executes the assembled string through childprocess.exec(), which invokes a shell (packages/plugins/@nocobase/plugin-backups/src/server/adapters/database.ts:1-31).

A schema value such as safe; touch /tmp/nocobase-cve-marker # produces a restore command of this form:

text pgrestore -U u -h localhost -p 5432 -n safe; touch /tmp/nocobase-cve-marker # -d db --clean --if-exists --no-owner -j 1 /tmp/backup-data

The semicolon terminates the intended pgrestore command and starts a new shell command.

False-positive screening: - This report does not claim unauthenticated exploitation. The route is gated by backup-management permissions through the registered ACL snippet. - The older backups.upload resource path was reviewed and does not pass forceSchemaRestore; the directly confirmed force path is the backup.restoreUpload / backup-CLI API path (packages/plugins/@nocobase/plugin-backups/src/server/resourcers/backups.ts:54-77, packages/plugins/@nocobase/plugin-backups/src/server/resourcers/backup-cli.ts:200-211). - The schema mismatch check blocks mismatched metadata by default, but it is deliberately bypassed for PostgreSQL when the supported force option is true. - The command injection is in the shell command itself before any PostgreSQL connection or valid backup file is required; the safe PoC proves shell metacharacter execution locally without connecting to a database. - The finding is not based on existing reports or generated writeups.

PoC The following local-only PoC renders the same vulnerable pgrestore command shape built by PostgresAdapter.restore() and executes it through Node.js childprocess.exec(), the sink used by the plugin. It uses a harmless marker file under /tmp, does not contact external services, and cleans up after itself.

From a clean checkout of the tested commit:

bash cd nocobase rm -f /tmp/nocobase-cve-marker node - <<'NODE' const { exec } = require('childprocess');

const schemaFromBackupMetadata = 'safe; touch /tmp/nocobase-cve-marker #'; const command = pgrestore -U u -h localhost -p 5432 -n ${schemaFromBackupMetadata} -d db --clean --if-exists --no-owner -j 1 /tmp/backup-data;

exec(command, () => { const fs = require('fs'); console.log(fs.existsSync('/tmp/nocobase-cve-marker') ? 'marker-created' : 'marker-missing'); fs.rmSync('/tmp/nocobase-cve-marker', { force: true }); }); NODE

Observed output in this environment:

text marker-created

Expected vulnerable output: marker-created, proving the schema value starts a second shell command.

Negative/control case: replace schemaFromBackupMetadata with safeschema; the same harness should print marker-missing because no shell metacharacter starts the touch command.

Maintainer-runnable application-level trigger: 1. Run NocoBase 2.0.57 with PostgreSQL and the built-in @nocobase/plugin-backups enabled. 2. Use a role granted the backup-management snippet/actions (backups: / backup:). 3. Create a NocoBase backup archive containing a data member and metadata.json with matching dialect/table settings but database.schema set to safe; touch /tmp/nocobase-cve-marker #. 4. Restore the uploaded backup through the backup restore-upload path with force=true so PostgreSQL schema mismatch is allowed. 5. Vulnerable behavior: /tmp/nocobase-cve-marker exists on the server after restore begins, even if pgrestore or database connection later fails. 6. Cleanup: remove /tmp/nocobase-cve-marker and discard the test database/container.

Impact A user with backup restore privileges can execute arbitrary shell commands as the NocoBase server OS user. In a typical server or container deployment, this can read application configuration and environment secrets, modify application files or database backups, run network clients from the server, and disrupt service availability.

The required application privilege is high because backup restore is an administrative operation. However, backup-management permission is still an application-level role boundary; it should not imply arbitrary operating-system command execution.

Suggested remediation Do not execute database tools through shell-interpreted command strings. Use spawn() or execFile() with an argument array for pgrestore, psql, pgdump, mysql, and related tools. Validate PostgreSQL schema identifiers from backup metadata against PostgreSQL identifier rules or quote them using the database driver's identifier-quoting facilities before using them in SQL.

For this specific path: - Pass pgrestore arguments as an array, for example ['-U', username, '-h', host, '-p', String(port), '-n', srcSchema, '-d', database, ...]. - Reject schema names containing shell metacharacters, quotes, whitespace, comments, or characters outside accepted PostgreSQL identifier syntax unless they are safely handled as identifiers. - Replace dynamic SQL string interpolation in #restoreSchema() with identifier-safe quoting (format('%I', ...) in PostgreSQL or equivalent server-side parameters) and string-literal escaping where literals are required. - Add regression tests that restore a backup whose metadata schema contains ; touch /tmp/should-not-exist # and assert no marker file is created and the request is rejected.

Other sources

NocoBase is an AI-powered no-code/low-code platform for building business applications and enterprise solutions. Prior to 2.1.19, NocoBase @nocobase/plugin-backups restored PostgreSQL backups by interpolating the database.schema value from metadata.json into shell command strings executed with Node.js childprocess.exec(), allowing a backup-management user restoring a crafted backup to execute commands as the NocoBase server process. This vulnerability is fixed in 2.1.19.

MITRE

Affected Software

2 affected componentsFixes available
NocoBase NocoBase<2.1.19
npm/@nocobase/plugin-backups<2.1.19
2.1.19

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@nocobase/plugin-backups to a version that resolves this vulnerability.

    Fixed in 2.1.19
  2. Upgrade

    Upgrade @nocobase/plugin-backups to a version that resolves this vulnerability.

    Fixed in 2.1.19
  3. Configuration

    Do not restore uploaded PostgreSQL backups with `force=true` (i.e., avoid passing `forceSchemaRestore: true` / skipping the schema-mismatch check for PostgreSQL).

    @nocobase/plugin-backups (backup restore) force = false
  4. Configuration

    Replace interpolation of attacker-controlled `metadata.database.schema` into shell/SQl strings with identifier-safe handling: (1) validate schema names against PostgreSQL identifier syntax or quote as identifiers (e.g., `format('%I', ...)` / driver identifier quoting) and reject/escape metacharacters, quotes, whitespace, comments; and (2) avoid `child_process.exec()` with a command string—pass `pg_restore` arguments as an array (e.g., `['-U', username, '-h', host, '-p', String(port), '-n', srcSchema, '-d', database, ...]`) via an argv-based API such as `spawn()`/`execFile()`.

    @nocobase/plugin-backups (PostgresAdapter / #restoreSchema / RestoreManager) schema identifier handling = identifier-safe quoting/arguments
  5. Compensating control

    Use/retain the backup-management ACL role gating for restore APIs/snippets (`backups:*` / `backup:*`), since restore/upload is an administrative operation and the command injection requires backup restore privileges.

Event History

Jul 15, 2026
CVE Published
via MITRE·08:19 PM
Data Sourced
via MITRE·08:19 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·09:16 PM
DescriptionSeverityWeakness
Aug 20, 2026
Advisory Published
via GitHub·06:30 PM
Data Sourced
via GitHub·06:30 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

What is the severity of CVE-2026-55410?

The severity of CVE-2026-55410 is rated as medium with a CVSS score of 6.7.

2

How do I fix CVE-2026-55410?

To fix CVE-2026-55410, upgrade to NocoBase version 2.1.19 or later.

3

What kind of vulnerability is CVE-2026-55410?

CVE-2026-55410 is classified as an OS Command Injection vulnerability.

4

What versions of NocoBase are affected by CVE-2026-55410?

CVE-2026-55410 affects all versions of NocoBase prior to 2.1.19.

5

What is the impact of CVE-2026-55410?

The impact of CVE-2026-55410 includes potential command injection that could allow an attacker to execute arbitrary commands on the server.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203