← Back to Feed CACHED · 2026-07-15 11:10:13 · CACHE_KEY CVE-2026-59948
CVE-2026-59948 · CWE-22 · Disclosed 2026-07-08

Composer is a dependency Manager for the PHP language

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

A malicious package name that treats your filesystem like it owns the whole tree, not just vendor/

Composer trusts package names too much. A crafted name in a composer.json requirement (or in a package resolved transitively from an untrusted repository) can escape the vendor/ directory during install/update, writing arbitrary files anywhere the Composer process has permission. In practice that means dropping a .bashrc, ~/.ssh/authorized_keys, or a cron entry — turning a dependency pull into arbitrary code execution as the user running composer. Affected: Composer 1.0 through 2.2.28 and 2.3.0 through 2.10.1. Fixed in 2.2.29 and 2.10.2 (GHSA-499r-g7pc-vmp9).

The vendor's HIGH / 7.0 rating is defensible and we're keeping it. The CVSS vector (AV:L/AC:H/PR:N/UI:R) accurately reflects that this is not a wormable network flaw — it needs a malicious package and a user action to install it. But CVSS underweights *where Composer actually runs*: CI runners, container build stages, and dev workstations with SSH keys and cloud credentials. Arbitrary file write on any of those is not a workstation nuisance — it's a foothold in the supply chain.

"Vendor's HIGH holds. Not because it's easy — because Composer lives on your build servers, and a build server write-primitive is a supply-chain pivot."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Attacker publishes or compromises a package

The attacker either registers a typosquat on a public repository, seeds a malicious package on an untrusted third-party repo the target uses, or compromises the upstream credentials of an existing package. The package's manifest embeds a specially crafted name containing path-traversal sequences that Composer <2.10.2 fails to validate. Tooling: standard composer publish flow, or account takeover via credential stuffing / phishing against maintainers.
Conditions required:
  • Ability to publish to a repository the victim consumes
  • Victim uses a repository other than Packagist-with-strict-name-validation, OR uses a repo added via repositories: in composer.json
Where this breaks in practice:
  • Packagist itself validates names on submission for new packages
  • Most enterprises pin dependencies and don't chase floating versions
Detection/coverage: Package manifest linters and typosquat scanners (Socket.dev, Snyk, Phylum) flag suspicious names — but this specific traversal payload is novel enough that generic scanners may miss it until signatures update.
STEP 02

Victim runs composer install/update/require

A developer, CI job, or container build stage executes composer install or composer update and the malicious package name gets resolved. This is the UI:R in the CVSS vector — but on a CI runner, 'user interaction' means 'the pipeline ran', which happens hundreds of times a day. Tooling: any invocation of composer binary, php composer.phar, or the composer step in a Dockerfile / GitHub Actions workflow.
Conditions required:
  • The malicious package is reachable via the victim's configured repositories
  • Composer version is 1.x–2.2.28 or 2.3.0–2.10.1
Where this breaks in practice:
  • Lockfile pinning (composer.lock committed) prevents new packages from being pulled unnoticed
  • --no-scripts / --no-plugins doesn't help here (this isn't a script-hook flaw)
Detection/coverage: CI logs show package name resolution; SBOM diff tools (Dependency-Track, GUAC) can catch a package name that wasn't in the previous build.
STEP 03

Path traversal writes file outside vendor/

During package extraction, Composer uses the unvalidated name to construct a destination path. Sequences like ../ or absolute-path components escape vendor/ and write to attacker-chosen locations — $HOME/.bashrc, $HOME/.ssh/authorized_keys, /etc/cron.d/* (if root), or the CI workspace's post-build hook directories.
Conditions required:
  • Composer process has write permission to the target file/directory
  • Target path exists or its parent directory is writable
Where this breaks in practice:
  • Composer typically runs as a non-root user on CI, limiting /etc/cron.d writes
  • Immutable/read-only container filesystems block most useful targets
Detection/coverage: File-integrity monitoring (auditd watch on ~/.ssh, ~/.bashrc, /etc/cron.*) catches the write. EDR with FIM rules on developer/CI hosts will flag it.
STEP 04

Code execution on next shell or scheduled trigger

The dropped file executes on the next login (.bashrc), next SSH connection (authorized_keys allowing attacker in), or next cron tick. On a CI runner this typically becomes whoami = the CI user, with access to build secrets, cloud tokens, artifact-signing keys, and network egress. Tooling: the attacker's implant is usually a small reverse shell or a credential harvester tailored to the CI environment.
Conditions required:
  • A shell login, SSH connection, or cron trigger occurs after the write
  • Written file survives long enough to fire (ephemeral runners narrow this window)
Where this breaks in practice:
  • Ephemeral CI runners (fresh container per job) destroy the write before it fires — unless the payload targets in-job secret exfil directly
  • MFA-gated SSH and hardware key requirements neutralize authorized_keys in most enterprise setups
Detection/coverage: EDR flags anomalous child processes from bash, sshd, or cron; SIEM correlation on 'first-time process' from a CI runner.
STEP 05

Supply-chain pivot from build server

If the compromised host is a build server, the attacker now has the ability to modify build artifacts, steal signing keys, and push tampered releases downstream — the classic SolarWinds / Codecov pattern. This is where a 'local, high-complexity' bug becomes an enterprise-scale incident.
Conditions required:
  • Composer ran on a build/CI system that produces signed or distributed artifacts
  • Build secrets are reachable from the composer process
Where this breaks in practice:
  • Hardware-backed signing (HSM, GitHub artifact attestations, Sigstore) prevents key theft
  • Just-in-time secret injection with short TTLs limits blast radius
Detection/coverage: Anomalous artifact hashes, unexpected commits from CI identities, secret-usage telemetry from your secret manager.
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo confirmed exploitation reported as of 2026-07-15. No mentions in threat-intel feeds, no incident writeups.
Proof-of-conceptNo public PoC in Exploit-DB, GitHub, or Metasploit at time of assessment. Advisory text (shell startup files, authorized_keys, cron) provides enough detail for a competent researcher to reproduce.
EPSS0.00132 (~0.13%) — bottom of the exploitation-likelihood distribution, consistent with 'no public PoC, requires malicious package'.
CISA KEVNot listed. Highly unlikely to be added — KEV favors network-reachable, unauthenticated bugs.
CVSS vectorAV:L/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:Hlocal attack vector, high complexity (needs the malicious-name payload to be resolved), no privileges, user interaction required. Full CIA impact once landed.
Affected versionsComposer 1.0 – 2.2.28 and 2.3.0 – 2.10.1
Fixed versions2.2.29 (LTS branch) and 2.10.2. Distro backports: check Debian/Ubuntu composer package, Alpine composer, RHEL/Fedora php-composer2 — most distros ship 2.x and will backport.
Sibling CVEs in same releaseCVE-2026-59946 (bin-path traversal, MEDIUM) and CVE-2026-59947 (URL token leakage in verbose output). Patch all three at once via the 2.10.2 upgrade.
Exposure populationComposer is on effectively every PHP dev workstation and every CI runner that builds PHP — millions of hosts. Shodan/Censys don't scan for it (not a network service), but SBOM prevalence data (Sonatype, Snyk) puts it in the top-tier of package managers.
Disclosure & attributionPublished 2026-07-08 via GitHub Security Advisory GHSA-499r-g7pc-vmp9. Reporter credited in the Composer changelog for 2.10.2.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (7.5/10)

The single most decisive factor is the role multiplier: Composer runs on CI/CD build servers, and an arbitrary file-write primitive on a build runner is a supply-chain pivot — that keeps the floor at HIGH regardless of the local-only, UI-required CVSS vector. The friction (needs a malicious package pulled from an untrusted repo, needs someone to run composer) prevents an upgrade to CRITICAL but is not sufficient to break the HIGH floor set by the deployment role.

HIGH Technical impact (arbitrary file write → RCE via .bashrc/authorized_keys/cron)
HIGH Affected version range and patch availability
MEDIUM Real-world exploitation likelihood — depends entirely on whether attackers can seed a package into your repo graph
LOW Blast radius on any given host — varies wildly between ephemeral CI runners and long-lived dev workstations

Why this verdict

  • Vendor baseline is fair. 7.0 accurately captures a local, UI-required file-write-to-RCE bug. Nothing about the underlying tech screams underrated.
  • Friction adjustment: −0.5. Needs a malicious package on a repository the victim consumes, needs a composer install/update, and needs write access to a meaningful target. Enterprise Packagist mirrors and committed composer.lock files kill most opportunistic attempts.
  • Role multiplier: +1.0 — floor is HIGH. Composer's canonical deployment includes CI/CD build servers (Jenkins, GitLab Runner, GitHub Actions self-hosted, Bitbucket Pipelines, Bamboo). File write on any of those = access to build secrets, artifact-signing keys, and downstream distribution. That is a supply-chain pivot, and it easily represents ≥10% of the installed base — Composer is *native* to build servers, not a peripheral. The HIGH floor is firm.
  • Role multiplier: +0.0 on dev workstations. Compromised laptop = one developer's git creds, cloud tokens, SSH keys. Bad, but bounded. Doesn't push the score higher on its own.
  • No exploitation multiplier. EPSS 0.13%, no KEV, no PoC. This is not a 'drop everything' bug — it is a 'patch it in the normal HIGH lane' bug.

Why not higher?

No active exploitation, no public PoC, and the delivery mechanism requires an attacker to first get a malicious package into your dependency graph — a non-trivial prerequisite for any organization that uses Private Packagist, a proxy repo (Nexus/Artifactory), or committed lockfiles. CRITICAL is reserved for chains that are network-reachable or have KEV evidence; this is neither.

Why not lower?

MEDIUM would ignore the deployment-role reality: Composer runs on CI, and file-write-to-RCE on CI is a supply-chain vector. The role multiplier explicitly floors this at HIGH — friction alone cannot pull it below. Even if you have strong dev-workstation controls, a single unpinned dependency on one build agent is enough for full impact.

05 · Compensating Control

What to do — in priority order.

  1. Upgrade Composer to 2.10.2 (or 2.2.29 on the LTS branch) fleet-wide — This is the actual fix. Push it via your config-management tool (Ansible/Chef/Puppet), your base container images, and your CI runner provisioning. Deploy within 30 days per the noisgate mitigation SLA for HIGH — but on CI/build hosts, treat as the top of the queue and aim for 7 days.
  2. Route all Composer traffic through a private proxy (Private Packagist, Nexus, Artifactory, Toran Proxy) — Prevents unreviewed third-party repositories from reaching your build hosts. Even after patching, this is the single highest-leverage supply-chain control for PHP shops. Deploy within 30 days.
  3. Commit and enforce composer.lock in every PHP repository, and require composer install (not update) in CI — Locks the exact package name+version set. A malicious name can't be resolved unless it's already in the lockfile — which turns the attack into an obvious PR-review event. Roll out via repo-template policy and CI linter.
  4. Enable file-integrity monitoring on CI runners and dev workstations for ~/.ssh/, ~/.bashrc, ~/.zshrc, ~/.profile, /etc/cron.*, /etc/profile.d/ — Detects the exploit primitive directly, regardless of which CVE delivered it. Feed alerts to SIEM with high priority when the writing process is php or composer.
  5. Move CI to ephemeral runners with read-only base images — Even if exploitation succeeds, the container is destroyed at job end and the payload can't persist. Combine with just-in-time secret injection (OIDC-federated cloud creds, short-TTL vault leases) to minimize what any single compromised job can steal.
What doesn't work
  • composer install --no-scripts / --no-plugins — this bug is in the *name-resolution* path, not the post-install script hook. These flags don't touch it.
  • Network egress restrictions on CI — Composer legitimately needs to reach package registries; you can't blanket-block it without breaking builds.
  • Perimeter WAFs, IPS, TLS inspection — this is a local file-write vulnerability triggered by a legitimate dependency pull. Nothing on the wire looks anomalous.
  • Running Composer as non-root — helps limit /etc/cron.d writes but does NOT stop the attack: ~/.bashrc and ~/.ssh/authorized_keys are writable by the running user by definition, and that's the whole payload.
06 · Verification

Crowdsourced verification payload.

Run on each host that has Composer installed — dev workstations, CI runners, build agents, container base images. Invoke as bash check-composer-59948.sh with no arguments; needs only read access to the composer binary in PATH. Exits 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check-composer-59948.sh
# Detects Composer versions vulnerable to CVE-2026-59948 (arbitrary file write via package name)
# Fixed in 2.2.29 (LTS) and 2.10.2
set -u

COMPOSER_BIN="$(command -v composer || true)"
if [ -z "$COMPOSER_BIN" ]; then
  # Also try common alt locations
  for c in /usr/local/bin/composer /usr/bin/composer ~/.composer/vendor/bin/composer /opt/composer/composer.phar; do
    [ -x "$c" ] && COMPOSER_BIN="$c" && break
  done
fi

if [ -z "$COMPOSER_BIN" ]; then
  echo "UNKNOWN: composer binary not found in PATH or common locations"
  exit 2
fi

VER_LINE="$($COMPOSER_BIN --version --no-ansi 2>/dev/null | head -n1)"
# Example: "Composer version 2.7.1 2024-02-09 15:26:28"
VER="$(echo "$VER_LINE" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)"

if [ -z "$VER" ]; then
  echo "UNKNOWN: could not parse version from: $VER_LINE"
  exit 2
fi

# Split version
IFS='.' read -r MAJ MIN PATCH <<< "$VER"

vuln=1  # assume vulnerable until proven otherwise

if [ "$MAJ" -eq 2 ] && [ "$MIN" -ge 3 ]; then
  # 2.3.0 - 2.10.1 vulnerable; 2.10.2+ patched
  if [ "$MIN" -gt 10 ] || { [ "$MIN" -eq 10 ] && [ "$PATCH" -ge 2 ]; }; then
    vuln=0
  fi
elif [ "$MAJ" -eq 2 ] && [ "$MIN" -le 2 ]; then
  # 2.0.0 - 2.2.28 vulnerable; 2.2.29+ patched on LTS branch
  if [ "$MIN" -eq 2 ] && [ "$PATCH" -ge 29 ]; then
    vuln=0
  fi
elif [ "$MAJ" -ge 3 ]; then
  # Future majors assumed patched
  vuln=0
fi

if [ "$vuln" -eq 0 ]; then
  echo "PATCHED: composer $VER at $COMPOSER_BIN"
  exit 0
else
  echo "VULNERABLE: composer $VER at $COMPOSER_BIN — upgrade to 2.10.2 (or 2.2.29 on LTS)"
  exit 1
fi
07 · Bottom Line

If you remember one thing.

TL;DR
Treat this as a HIGH in your normal patch cadence — not a fire drill. Per the noisgate mitigation SLA for HIGH, deploy compensating controls within 30 days: get all builds routed through a private proxy repo (Private Packagist / Nexus / Artifactory), enforce committed composer.lock files, and turn on FIM for ~/.ssh/, shell rc files, and /etc/cron.* on CI runners. Per the noisgate remediation SLA for HIGH, upgrade Composer to 2.10.2 (or 2.2.29 on the LTS branch) across dev laptops, CI runners, and container base images within 180 days — but prioritize build servers to the front of that window (aim for 7 days on CI/build hosts specifically, because that's where the supply-chain blast radius lives). No KEV, no PoC, EPSS is negligible; skip the emergency change-management channel unless your threat model includes targeted supply-chain adversaries.

Sources

  1. GHSA-499r-g7pc-vmp9 — Composer advisory
  2. Composer 2.10.2 release notes
  3. Composer releases index
  4. The Hacker News — Composer flaws coverage
  5. Laravel News — Composer security fixes
  6. OpenCVE — getcomposer vendor page
  7. MITRE CVE search — composer php
  8. CTIWatch — sibling CVE-2026-59946
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.