VYPR
Critical severityNVD Advisory· Published May 3, 2021· Updated Aug 3, 2024

CVE-2021-29369

CVE-2021-29369

Description

The gnuplot Node.js package before 0.1.0 allows command injection via shell metacharacters in filenames passed to the plot function, enabling remote code execution.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The gnuplot Node.js package before 0.1.0 allows command injection via shell metacharacters in filenames passed to the plot function, enabling remote code execution.

Vulnerability

The gnuplot package for Node.js prior to version 0.1.0 does not sanitize user-supplied filenames before passing them to the Gnuplot command-line tool. This allows shell metacharacters (e.g., &, |, ;) embedded in the filename to be interpreted by the underlying shell, leading to command injection. The vulnerable code path is in the plot function, which constructs a Gnuplot command using the unsanitized options.filename parameter [1].

Exploitation

An attacker who can control the filename argument passed to the plot function (e.g., via user input in a web application) can inject arbitrary shell commands. For example, a filename like output.png & frog > frog.txt would cause the shell to execute the injected command after the Gnuplot process. No authentication or special privileges are required if the application exposes this function to untrusted input [1].

Impact

Successful exploitation results in arbitrary command execution on the server with the privileges of the Node.js process. This can lead to full system compromise, including data exfiltration, installation of malware, or lateral movement within the network [1].

Mitigation

The vulnerability is fixed in version 0.1.0 of the gnuplot package. The fix adds filename validation using the filenamify library, which rejects filenames containing shell metacharacters [2]. Users should upgrade to 0.1.0 or later. No workarounds are available for earlier versions [1].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@rkesters/gnuplotnpm
< 0.1.10.1.1

Affected products

2

Patches

1
23671d4d3d28

validate filename

https://github.com/rkesters/gnuplotRobert KestersonJan 22, 2021via ghsa
4 files changed · +56 2
  • package.json+1 0 modified
    @@ -54,6 +54,7 @@
         "typescript": "^4.0.5"
       },
       "dependencies": {
    +    "filenamify": "^4.2.0",
         "lodash": "^4.17.15"
       }
     }
    
  • package-lock.json+32 2 modified
    @@ -406,8 +406,7 @@
         "escape-string-regexp": {
           "version": "1.0.5",
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
    -      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
    -      "dev": true
    +      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
         },
         "esprima": {
           "version": "4.0.1",
    @@ -421,6 +420,21 @@
           "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=",
           "dev": true
         },
    +    "filename-reserved-regex": {
    +      "version": "2.0.0",
    +      "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
    +      "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik="
    +    },
    +    "filenamify": {
    +      "version": "4.2.0",
    +      "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.2.0.tgz",
    +      "integrity": "sha512-pkgE+4p7N1n7QieOopmn3TqJaefjdWXwEkj2XLZJLKfOgcQKkn11ahvGNgTD8mLggexLiDFQxeTs14xVU22XPA==",
    +      "requires": {
    +        "filename-reserved-regex": "^2.0.0",
    +        "strip-outer": "^1.0.1",
    +        "trim-repeated": "^1.0.0"
    +      }
    +    },
         "fill-range": {
           "version": "7.0.1",
           "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
    @@ -986,6 +1000,14 @@
           "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
           "dev": true
         },
    +    "strip-outer": {
    +      "version": "1.0.1",
    +      "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
    +      "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
    +      "requires": {
    +        "escape-string-regexp": "^1.0.2"
    +      }
    +    },
         "supports-color": {
           "version": "6.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
    @@ -1004,6 +1026,14 @@
             "is-number": "^7.0.0"
           }
         },
    +    "trim-repeated": {
    +      "version": "1.0.0",
    +      "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
    +      "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
    +      "requires": {
    +        "escape-string-regexp": "^1.0.2"
    +      }
    +    },
         "ts-node": {
           "version": "8.10.2",
           "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz",
    
  • src/index.ts+6 0 modified
    @@ -354,11 +354,17 @@ function plotCallack(options: PlotOptions) {
       gnuplot.stdin.end();
     }
     
    +import validFilename from "filenamify";
    +
     /**
      * Plots data to a PDF file. If it does not exist, the PDF file will
      * be created, otherwise this plot will be appended as a new page.
      */
     export function plot(options: PlotOptions): Promise<boolean> | void {
    +  const f = validFilename.path(options.filename);
    +  if (f !== options.filename) {
    +    throw new Error(`invalid filename of '${options.filename}' -- ${f}`);
    +  }
       if (options.finish) {
         return plotCallack(options);
       }
    
  • src/test.ts+17 0 modified
    @@ -6,6 +6,7 @@ import "mocha";
     
     import { plot } from "./index";
     import { expect as should } from "chai";
    +import { fail } from "assert";
     
     function handleResult(
       error: any,
    @@ -55,6 +56,22 @@ describe("Plot tests", function () {
       // });
     
       describe("PNG output", function () {
    +    it("bad filename ", async () => {
    +      let passed = false;
    +      try {
    +        const ploted = await plot({
    +          data: [3, 1, 2, 3, 4],
    +          filename: __dirname + "/test/output1.png & frog > frog.txt",
    +          format: "png",
    +        });
    +      } catch (e) {
    +        should(e.message).contain("invalid filename of");
    +        passed = true;
    +      }
    +      if (!passed) {
    +        fail();
    +      }
    +    });
         it("Async Output1", async () => {
           const ploted = await plot({
             data: [3, 1, 2, 3, 4],
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.