CVE-2026-25244: Verified Repro With Script Download
CVE-2026-25244: @wdio/browserstack-service: OS command injection via crafted git branch name
CVE-2026-25244 is verified against @wdio/browserstack-service · npm. Affected versions: <= 9.23.2. Fixed in 9.24.0. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00143.
What Is CVE-2026-25244?
CVE-2026-25244 (GHSA-5c46-x3qw-q7j7) is a critical OS command injection vulnerability (CWE-78) in @wdio/browserstack-service, the BrowserStack integration for WebdriverIO, that allows arbitrary command execution via a crafted git branch name. Pruva reproduced it (reproduction REPRO-2026-00143).
CVE-2026-25244 Severity & CVSS Score
CVE-2026-25244 is rated critical severity, with a CVSS base score of 9.8 out of 10.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected @wdio/browserstack-service Versions
@wdio/browserstack-service · npm versions <= 9.23.2 are affected.
How to Reproduce CVE-2026-25244
pruva-verify REPRO-2026-00143 curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00143/artifacts/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for CVE-2026-25244
Reproduced by Pruva's autonomous agents — 274 tool calls over 1h 0m. Full root-cause analysis and the complete transcript are below.
How the agent worked
Root Cause and Exploit Chain for CVE-2026-25244
Summary
CVE-2026-25244 is an OS command injection vulnerability (CWE-78) in @wdio/browserstack-service versions <= 9.23.2. The getGitMetadataForAISelection() function in packages/wdio-browserstack-service/src/testorchestration/helpers.ts interpolates git branch names and commit hashes directly into shell command strings passed to child_process.execSync(). Because git branch names can contain shell metacharacters (backticks, $(), ;, |, &), an attacker who controls a branch name (e.g., via a malicious pull request branch in CI/CD) can cause arbitrary OS command execution when the BrowserStack service runs the metadata helper.
Impact
- Package:
@wdio/browserstack-service(webdriverio monorepo) - Affected versions:
<= 9.23.2 - Fixed version:
9.24.0 - Risk level: Critical (CVSS 9.8)
- Consequences: Remote Code Execution (RCE) in CI/CD runners. Any pipeline that checks out an attacker-controlled branch and runs WebdriverIO with the BrowserStack service can be compromised.
Root Cause
The vulnerable code in getGitMetadataForAISelection() (v9.23.2) uses child_process.execSync() with JavaScript template literals to build git commands:
const changedFilesOutput = execSync(`git diff --name-only ${baseBranch}..${currentBranch}`).toString().trim()
const commitsOutput = execSync(`git log ${baseBranch}..${currentBranch} --pretty=%H`).toString().trim()
When currentBranch (or baseBranch / commit) contains shell metacharacters, execSync() passes the entire string to /bin/sh, which interprets the metacharacters and executes the embedded commands.
The fix (commit 0e6748ecd, v9.24.0) replaces execSync() with spawnSync('git', [args...]), which passes arguments directly to the git executable without shell interpretation. It also adds isValidGitRef() validation using a SAFE_GIT_REF_PATTERN regex (^[a-zA-Z0-9_./-]+$) to reject any ref containing dangerous characters before it reaches the command execution layer.
Reproduction Steps
The reproduction script is repro/reproduction_steps.sh. It performs the following:
- Clones the webdriverio repository and extracts
helpers.tsfrom tagsv9.23.2(vulnerable) andv9.24.0(fixed). - Creates a mock
@wdio/loggermodule so the TypeScript source compiles withtsx. - Creates a dummy git repository for the test.
- Creates a fake
gitbinary that returns a malicious branch name (master; touch <marker>) when asked for the current branch. - Runs
getGitMetadataForAISelection()from the vulnerable source with the fake git inPATH. The shell interprets the;in the branch name and executes the injectedtouchcommand, creating the marker file. - Runs
getGitMetadataForAISelection()from the fixed source with the same fake git. TheisValidGitRef()check rejects the malicious branch name and the function skips the folder, leaving the marker file absent. - Prints a summary of code differences and test results.
Expected evidence:
- Vulnerable run: marker file created (
VULNERABLE: marker file was created by injected command!) - Fixed run: marker file NOT created (
FIXED: marker file was NOT created.)
Evidence
Log files:
logs/vulnerable_output.log— output of running the vulnerablegetGitMetadataForAISelection()logs/fixed_output.log— output of running the fixedgetGitMetadataForAISelection()
Key excerpts from vulnerable run (logs/vulnerable_output.log):
VULNERABLE: marker file was created by injected command!
The shell interpreted metacharacters in the branch name
and executed the embedded touch command.
Key excerpts from fixed run (logs/fixed_output.log):
[WARN] Invalid current branch name detected: master; touch /tmp/.../marker_fixed. Skipping this folder for security reasons.
Result: []
FIXED: marker file was NOT created.
The sanitization (isValidGitRef + spawnSync) prevented
shell metacharacters from being evaluated.
Code diff highlights (from repro/reproduction_steps.sh output):
Vulnerable (v9.23.2) - uses execSync with string interpolation:
204: execSync(`git diff --name-only ${baseBranch}..${currentBranch}`)
209: execSync(`git log ${baseBranch}..${currentBranch} --pretty=%H`)
Fixed (v9.24.0) - uses spawnSync with array arguments:
3: import { spawnSync } from 'node:child_process'
29: spawnSync('git', args, { ... })
Fixed (v9.24.0) - adds isValidGitRef validation:
15: const SAFE_GIT_REF_PATTERN = /^[a-zA-Z0-9_./-]+$/
17: function isValidGitRef(ref: string): boolean { ... }
Recommendations / Next Steps
- Upgrade immediately to
@wdio/browserstack-service >= 9.24.0(or webdriverio >= 9.24.0). - Defense in depth: CI/CD pipelines should validate branch names before checking them out, especially for fork/PR builds.
- Code review: Audit any other
execSync()usages in the webdriverio monorepo that interpolate user-controlled data into shell commands. - Regression testing: Add unit tests that pass malicious branch names and commit hashes to
getGitMetadataForAISelection()to ensure the validation regex catches future bypasses.
Additional Notes
- Idempotency: The reproduction script was run twice consecutively and produced identical results both times.
- No live BrowserStack account needed: The vulnerability is entirely in local git-metadata collection. The reproduction uses only Node.js, git, and
tsx. - Edge case: The
isValidGitRef()regex (^[a-zA-Z0-9_./-]+$) is restrictive but safe. It may reject unusual but legitimate branch names in rare cases (e.g., names containing@or#), but this is an acceptable trade-off for preventing command injection. - Fix commit: https://github.com/webdriverio/webdriverio/commit/0e6748ecdb116f80495449a758d430201106dbcc
CVE-2026-25244 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
Artifacts and Evidence for CVE-2026-25244
Scripts, logs, diffs, and output captured during the reproduction.
No artifacts available
How to Fix CVE-2026-25244
Upgrade @wdio/browserstack-service · npm to 9.24.0 or later.
FAQ: CVE-2026-25244
How does the CVE-2026-25244 command injection exploit work?
$(...), ;, |, &), an attacker who controls the checked-out branch name — such as a pull-request branch in CI — embeds a shell payload in the branch name. When getGitMetadataForAISelection() builds and runs its execSync() git commands, /bin/sh executes the embedded payload in the context of the process running the WebdriverIO test session, typically a CI runner.Which @wdio/browserstack-service versions are affected by CVE-2026-25244, and where is it fixed?
How severe is CVE-2026-25244?
How can I reproduce CVE-2026-25244?
@wdio/browserstack-service <= 9.23.2. It checks out a git branch whose name contains shell metacharacters, runs the WebdriverIO test session with the BrowserStack service enabled, and shows the embedded payload executing via getGitMetadataForAISelection()'s execSync() calls.References for CVE-2026-25244
Authoritative sources for CVE-2026-25244 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.