GHSA-P4XF-RF54-RJ3X

Vulnerability from github – Published: 2026-06-26 22:53 – Updated: 2026-06-26 22:53
VLAI
Summary
pnpm: Git Fetch Argument Injection via Lockfile resolution.commit
Details

Summary

pnpm passes the lockfile-controlled git resolution.commit value to git fetch without a -- separator or commit-format validation. For git dependencies fetched through the shallow-fetch path, a malicious lockfile can replace the expected 40-character commit hash with a Git option such as --upload-pack=<command>. For SSH and local transports, --upload-pack can execute the supplied command. HTTPS transports ignore --upload-pack, so the practical attack surface is primarily SSH or local git dependencies.

Vulnerability Details

The vulnerable path is in fetching/git-fetcher/src/index.ts. When a git dependency host is configured for shallow fetching, pnpm calls:

await execGit(['fetch', '--depth', '1', 'origin', resolution.commit], { cwd: tempLocation })

Because resolution.commit is appended before a -- separator, Git can parse a commit value beginning with - as an option. The same file later passes the value to git checkout without a separator:

await execGit(['checkout', resolution.commit], { cwd: tempLocation })

resolution.commit comes from the lockfile and is typed as a plain string; pnpm does not validate it as a 40-character hexadecimal commit before passing it to Git.

Proof of Concept

bash autofyn_audit/exploits/vuln11_git_upload_pack_rce/exploit.sh
# Creates a local bare git repo and triggers the shallow-fetch path.
# Replaces the lockfile commit hash with '--upload-pack=touch /tmp/vuln11_pwned'.
# Result: PASS -- /tmp/vuln11_pwned created by injected touch command.

The PoC uses a local file://githost/... repository because the injection requires a local or SSH transport. HTTPS transport ignores --upload-pack.

Impact

Code execution as the user running pnpm install, under specific transport conditions. The attacker must modify pnpm-lock.yaml, and the affected dependency must use SSH or local git transport. HTTPS transport (the common case) is immune.

Suggested Remediation

Add a -- separator before lockfile-controlled git revision values. Validate resolution.commit matches /^[0-9a-f]{40}$/i before passing to Git.


Discovered by AutoFyn Full audit report: audit_report.md Exploit script: exploit.sh

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "pnpm"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "10.34.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "pnpm"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "11.0.0"
            },
            {
              "fixed": "11.4.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-50014"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-88"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-26T22:53:21Z",
    "nvd_published_at": "2026-06-25T18:16:39Z",
    "severity": "MODERATE"
  },
  "details": "## Summary\n\npnpm passes the lockfile-controlled git `resolution.commit` value to `git fetch` without a `--` separator or commit-format validation. For git dependencies fetched through the shallow-fetch path, a malicious lockfile can replace the expected 40-character commit hash with a Git option such as `--upload-pack=\u003ccommand\u003e`. For SSH and local transports, `--upload-pack` can execute the supplied command. HTTPS transports ignore `--upload-pack`, so the practical attack surface is primarily SSH or local git dependencies.\n\n## Vulnerability Details\n\nThe vulnerable path is in `fetching/git-fetcher/src/index.ts`. When a git dependency host is configured for shallow fetching, pnpm calls:\n\n```typescript\nawait execGit([\u0027fetch\u0027, \u0027--depth\u0027, \u00271\u0027, \u0027origin\u0027, resolution.commit], { cwd: tempLocation })\n```\n\nBecause `resolution.commit` is appended before a `--` separator, Git can parse a commit value beginning with `-` as an option. The same file later passes the value to `git checkout` without a separator:\n\n```typescript\nawait execGit([\u0027checkout\u0027, resolution.commit], { cwd: tempLocation })\n```\n\n`resolution.commit` comes from the lockfile and is typed as a plain `string`; pnpm does not validate it as a 40-character hexadecimal commit before passing it to Git.\n\n## Proof of Concept\n\n```bash\nbash autofyn_audit/exploits/vuln11_git_upload_pack_rce/exploit.sh\n# Creates a local bare git repo and triggers the shallow-fetch path.\n# Replaces the lockfile commit hash with \u0027--upload-pack=touch /tmp/vuln11_pwned\u0027.\n# Result: PASS -- /tmp/vuln11_pwned created by injected touch command.\n```\n\nThe PoC uses a local `file://githost/...` repository because the injection requires a local or SSH transport. HTTPS transport ignores `--upload-pack`.\n\n## Impact\n\nCode execution as the user running `pnpm install`, under specific transport conditions. The attacker must modify `pnpm-lock.yaml`, and the affected dependency must use SSH or local git transport. HTTPS transport (the common case) is immune.\n\n## Suggested Remediation\n\nAdd a `--` separator before lockfile-controlled git revision values. Validate `resolution.commit` matches `/^[0-9a-f]{40}$/i` before passing to Git.\n\n---\n\n\u003e Discovered by [AutoFyn](https://github.com/SignalPilot-Labs/AutoFyn)\n\u003e Full audit report: [audit_report.md](https://github.com/tempcollab/pnpm/blob/main/autofyn_audit/audit_report.md)\n\u003e Exploit script: [exploit.sh](https://github.com/tempcollab/pnpm/blob/main/autofyn_audit/exploits/vuln11_git_upload_pack_rce/exploit.sh)",
  "id": "GHSA-p4xf-rf54-rj3x",
  "modified": "2026-06-26T22:53:21Z",
  "published": "2026-06-26T22:53:21Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/pnpm/pnpm/security/advisories/GHSA-p4xf-rf54-rj3x"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50014"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/pnpm/pnpm"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "pnpm: Git Fetch Argument Injection via Lockfile resolution.commit"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…