Skip to content

CVE-2026-66902: Verified Reproduction

CVE-2026-66902: Google::Auth for Perl command injection: external account credentials JSON executable run via ungated system → RCE

CVE-2026-66902 is verified against the affected target. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00323.

REPRO-2026-00323 RCE Aug 23, 2026 CVE entry .txt
Severity
CRITICAL
Confidence
HIGH
Reproduced in
16m 52s
Tool calls
169
Spend
$3.66
01 · Overview

What Is CVE-2026-66902?

CVE-2026-66902 is a critical-severity RCE vulnerability. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00323).

02 · Severity & CVSS

CVE-2026-66902 Severity

CVE-2026-66902 is rated critical severity.

CRITICAL threat level
Weakness CWE-78 — Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.

How to Reproduce CVE-2026-66902

$ pruva-verify REPRO-2026-00323
or curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00323/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2026-66902

Remote code execution — reproduced
  • reached the target end-to-end
  • full exploit chain demonstrated
  • on the real production code path
  • high confidence
  • the upstream fix blocks the same trigger
Trigger

external_account credentials JSON named by GOOGLE_APPLICATION_CREDENTIALS: credential_source.executable.command and credential_source.executable.environment_variables

Attack chain
  1. Google::Auth
  2. default()
  3. DefaultCredentials
  4. from_env()
  5. ExternalAccountCredentials::make_creds
  6. Pluggable
  7. new
  8. fetch_access_token
  9. retrieve_subject_token
  10. single-argument system($command) via /bin/sh -c
Runnable proof: reproduction_steps.sh
Captured evidence: attempt fixed 1attempt fixed 2attempt fixed allow1
How the agent worked 355 events · 169 tool calls · 17 min
17 minDuration
169Tool calls
60Reasoning steps
355Events
20Dead-ends
Agent activity over 17 min
Policy
1
Support
24
Repro
153
Judge
42
Variant
130
Verify
1
0:0016:43

Root Cause and Exploit Chain for CVE-2026-66902

Versions: < 0.06 (verified at commit

Google::Auth for Perl (CPAN distribution Google-Auth, maintained at GoogleCloudPlatform/google-auth-library-perl) executes a command taken verbatim from an external_account credentials JSON file through a single-argument system($command) call. In versions before 0.06 there is no opt-in gate: any application that builds Application Default Credentials from a configuration it does not fully control runs the embedded shell command (with full /bin/sh -c interpretation and attacker-chosen environment variables) with the privileges of the application process. This is CWE-78 OS command injection leading to arbitrary OS command execution.

  • Package/component: CPAN Google-Auth (Google::Auth), lib/Google/Auth/ExternalAccountCredentials/Pluggable.pm
  • Affected versions: < 0.06 (verified at commit 913fb1780202c1ee9dd640c28c01549903f8e23a = fix commit parent; packaged as 0.05)
  • Risk level: Critical. Any service/workload that consumes a credentials JSON from an untrusted or partially trusted source (mounted config, user-supplied file, CI artifact) executes attacker-chosen shell commands as the application user.

Impact Parity

  • Disclosed/claimed maximum impact: arbitrary OS command execution (RCE) in the application process.
  • Reproduced impact from this run: arbitrary shell command execution in the Perl application process. The embedded command used shell output redirection to write a unique attacker-chosen marker file, and consumed attacker-controlled environment variables copied from the same JSON (environment_variables map) — proving both full shell interpretation and environment injection.
  • Parity: full.
  • Not demonstrated: nothing material; the claimed impact (code/command execution) was reproduced directly, twice, against the real library entrypoint.

Root Cause

Google::Auth::ExternalAccountCredentials::Pluggable::retrieve_subject_token() (in versions < 0.06) does the following with zero validation and no opt-in:

  1. Copies every entry of credential_source.executable.environment_variables from the credentials JSON into %ENV.
  2. Reads credential_source.executable.command and runs capture { system($command) }. Because system() receives a single string, Perl invokes /bin/sh -c, giving the attacker pipes, redirection, command substitution, and all shell metacharacters.

Dispatch reaches this subclass automatically: Google::Auth->default()Google::Auth::DefaultCredentials->from_env() reads the JSON named by GOOGLE_APPLICATION_CREDENTIALSmake_creds() in ExternalAccountCredentials.pm selects the Pluggable subclass whenever credential_source.executable exists → construction succeeds with only audience, subject_token_type, token_url, and credential_source → the first fetch_access_token() (which every consuming application performs to use the credential) calls retrieve_subject_token() and executes the command before any network access.

Fix commit c95c77e70bec94f17e239d88050f843ea1cade95 (released as 0.06) adds an opt-in gate at the top of retrieve_subject_token() that throws unless GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1, plus a bounded execution timeout, schema validation of the command output, and URL domain validation in the base class. Version 0.10 additionally parses with Text::ParseWords and uses indirect system exec.

Reproduction Steps

  1. Run bundle/repro/reproduction_steps.sh (self-contained; re-runnable).
  2. The script:
    • Clones GoogleCloudPlatform/google-auth-library-perl (into the prepared project cache when available) and resolves the vulnerable checkout as c95c77e70bec94f17e239d88050f843ea1cade95^ (= 913fb17) and the fixed checkout as the fix commit itself; verifies the gate string is absent in the vulnerable tree and present in the fixed tree.
    • Installs the pure-Perl runtime dependencies (Moo, Capture::Tiny, LWP::UserAgent, Log::Any, Throwable, URI) via apt when permitted, otherwise into a bundle-local INSTALL_BASE with cpan, then builds the real module including its XS component (perl Makefile.PL && make) for both versions.
    • Generates an attacker-controlled external_account credentials JSON whose credential_source.executable.command writes a unique marker file using shell redirection and attacker-injected environment variables, and points token_url at a closed localhost port so the STS exchange fails fast after the command has already executed.
    • Invokes the real ADC flow as a CLI command: GOOGLE_APPLICATION_CREDENTIALS=<json> perl -I... trigger.pl, where trigger.pl calls Google::Auth->default() and then fetch_access_token() — exactly the sequence a real application performs.
    • Runs the matrix: 2 vulnerable attempts, 2 fixed attempts (default gated), and 1 fixed attempt with the opt-in gate set (positive control).
  3. Expected evidence: both vulnerable attempts create their unique marker files; both fixed attempts throw Pluggable credentials are not enabled. Set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1 and create no marker; the opt-in control creates its marker again.

Evidence

  • Main log: bundle/logs/reproduction_steps.log
  • Per-attempt process logs: bundle/logs/attempt_vuln_1.log, bundle/logs/attempt_vuln_2.log, bundle/logs/attempt_fixed_1.log, bundle/logs/attempt_fixed_2.log, bundle/logs/attempt_fixed_allow1.log
  • Marker files (written by the injected shell command through /bin/sh -c): bundle/repro/markers/vuln_1.marker, bundle/repro/markers/vuln_2.marker, bundle/repro/markers/fixed_allow1.marker
  • Per-attempt observation JSONs: bundle/repro/observations/*.json
  • Attacker configs used: bundle/repro/adc/*.json
  • Runtime manifest: bundle/repro/runtime_manifest.json

Key excerpts (identical across two consecutive runs):

[run] vuln attempt 1 ... 
RESULT: credentials class = Google::Auth::ExternalAccountCredentials::Pluggable
RESULT: fetch_access_token error: Token exchange failed with status 500: Can't connect to 127.0.0.1:9
[run] vuln attempt 1: MARKER CREATED -> pwned-via-CVE-2026-66902 vuln attempt 1 shell+env injection
[matrix] vulnerable attempts with marker: 2/2

RESULT: fetch_access_token error: Pluggable credentials are not enabled. Set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1 to enable.
[matrix] fixed attempts blocked (no marker): 2/2

[run] fixed attempt allow1: MARKER CREATED -> pwned-via-CVE-2026-66902 fixed attempt allow1 shell+env injection
[matrix] fixed+opt-in attempts with marker: 1/1
=== RESULT: CONFIRMED - command injection via Pluggable external_account credentials ===

Environment: Ubuntu 24.04, perl 5.38.2 (x86_64-linux-gnu-thread-multi), OpenSSL 3.0.13 headers for the XS build, pure-Perl deps installed into bundle/repro/deps (cpan INSTALL_BASE). No sanitizers, no mocks, no network interaction with Google endpoints (token_url is http://127.0.0.1:9/v1/token, which fails after the injected command has executed).

Recommendations / Next Steps

  • Upgrade to Google-Auth 0.06 or later; 0.06 throws unless GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1 is set, and 0.10 additionally shell-parses the command with Text::ParseWords and uses indirect (list-form) system exec, removing /bin/sh -c interpretation.
  • Treat every credentials JSON reachable by the ADC flow (GOOGLE_APPLICATION_CREDENTIALS, well-known paths) as executable code: restrict write access, prefer trusted provisioning, and avoid setting the opt-in gate.
  • Regression testing: the upstream fix commit already adds tests (t/16-pluggable-credentials.t); downstream should additionally test that a credential_source.executable config without the gate never spawns a process.

Additional Notes

  • Idempotency: the script was executed twice consecutively (plus two more times after adding unique per-attempt markers/observations) — every run produced the full matrix result (2/2 vulnerable markers, 2/2 fixed blocked, 1/1 opt-in control) and exit code 0.
  • The command executes before the STS token exchange; the proof intentionally uses a closed-loopback token_url so no external network call is needed and the marker is created regardless of the later (expected) STS failure.
  • Both the claimed entrypoint variants are supported: the primary proof uses Google::Auth->default() (requires the XS build, which the script performs); if the XS toolchain were unavailable the script falls back to Google::Auth::DefaultCredentials->from_env(), which is the same dispatch path named in the claim.
  • Edge case: the vulnerable code only executes the command when a token is fetched, not at config parse time — matching real application behavior, since any consumer of the credential calls fetch_access_token() to use it.

CVE-2026-66902 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.

Event 1/40
0:002:06
0:00
session startedaccounts/fireworks/models/kimi-k3 · CVE-2026-66902 · REPRO-20
0:09
0:10
web search
0:15
0:16
0:19
0:20
web search
0:32
0:34
web search
0:37
1:04
1:06
1:07
web search
1:48
1:48
extract_facts
no facts extracted
1:49
1:49
1:49
supportclaim_contract
1:55
1:55
1:55
1:58
1:58
1:58
1:58
2:02
2:03
$ls -la /data/pruva/project-cache/.run-views/e0d7614274d099ca25147d868040f8a99d1f2796b570b6bba6a5f6ab22c5eed5/ /data/pruva/project-cache/.run-views/e0d7614274d099ca25147d868040f8a99d1f2796b570b6bba6a5f6ab22c5eed5/repo-mirrors/ 2>&1; cat /data/pruva/project-cache/.run-views/e0d7614274d099ca25147d868040f8a99d1f2796b570b6bba6a5f6ab22c5eed5/.pruva/cache_manifest.json 2>&1
/data/pruva/project-cache/.run-views/e0d7614274d099ca25147d868040f8a99d1f2796b570b6bba6a5f6ab22c5eed5/:
total 16
drwx------ 4 pruva pruva 4096 Aug  9 14:00 .
drwx------ 4 pruva pruva 4096 Aug  9 14:00 ..
drwx------ 2 pruva pruva 4096 Aug  9 14:00 .pruva
drwx------ 2 pruva pruva 4096 Aug  9 14:00 repo-mirrors

/data/pruva/project-cache/.run-views/e0d7614274d099ca25147d868040f8a99d1f2796b570b6bba6a5f6ab22c5eed5/repo-mirrors/:
2:06
08 · How to Fix

How to Fix CVE-2026-66902

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2026-66902 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2026-66902

Is CVE-2026-66902 exploitable?

Yes. Pruva independently reproduced CVE-2026-66902 and verified the exploit fires end-to-end in a sandboxed environment. A runnable proof-of-concept script and the full agent transcript are on this page (reproduction REPRO-2026-00323).

How severe is CVE-2026-66902?

CVE-2026-66902 is rated critical severity.

What type of vulnerability is CVE-2026-66902?

CVE-2026-66902 is classified as CWE-78 (Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')), a RCE vulnerability.

How can I reproduce CVE-2026-66902?

Pruva provides a verified reproduction script on this page. Download it and run it inside an isolated environment such as a container or virtual machine — never against production. The reproduction was confirmed end-to-end by Pruva's automated agents.

Is the CVE-2026-66902 reproduction verified?

Yes. Pruva reproduced CVE-2026-66902 with high confidence in a sandboxed environment, capturing the full agent transcript and artifacts as evidence.
11 · References

References for CVE-2026-66902

Authoritative sources for CVE-2026-66902 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.