NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
📦 GitHub Actions🐍 PyPI
Not in CISA KEV

CVE-2026-123371 — compose-lint

Fix: tmatens/compose-lint@e80547d

CVE-2026-123371 is a CWE-59 vulnerability in tmatens/compose-lint. A fix is available for tmatens/compose-lint — see the affected versions and patch details below.

compose-lint: A `.compose-lint.yml` symlinked outside the project is read, and a parse error quotes part of the target

Also known asGHSA-88f4-frh5-gmcr
Published
Updated
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Nov 11, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

EPSS Exploitation Probability

via FIRST.org ↗
0.4%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs39th percentile — riskier than 39% of all scored CVEsHighest risk

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

2 pkgs affected
📦tmatens/compose-lint🐍compose-lint

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects GitHub Actions, PyPI packages — download data is not available via public APIs for these ecosystems.

Description

Impact

compose-lint automatically reads a .compose-lint.yml policy file beside the Compose file. It is meant to read nothing outside the project directory, but it follows that file if it is a symlink, wherever it points.

A pull request can commit .compose-lint.yml as a symlink to a file on the CI runner. If the target is not valid YAML, the error compose-lint reports quotes part of the line the parser failed on. That quote reaches the job log (standard error), JSON errors[], and the SARIF toolExecutionNotifications, which the Action uploads to Code Scanning. The run exits 2.

What can be read is small. The quote is cut to about 30 characters around the error position, and the attacker cannot choose which line of the target the parser fails on. For an INI-style credentials file, this was the start of the second line (aws_access_key_id = followed by the first characters of the value). Targets in KEY=value form, and YAML files that parse, disclosed no values in testing. The pass/fail result is not affected. On a public repository, the job log is visible to the pull request's author.

The Compose file loader stopped quoting source lines in parse errors in 0.25.0 (GHSA-whr6-fgpq-fpv9). The policy loader did not.

Found during an internal pre-1.0 security review.

GitHub Action. Action tags v0.18.0 through v0.31.0 install their own compose-lint version and are affected. Earlier tags install the newest release unless version: is set, and so currently install an affected one.

Docker image. composelint/compose-lint tags 0.3.3 through 0.31.0, the matching minor tags, and latest are affected. Inside the container, a symlink resolves within the container, so what can be read is the container's own files and anything mounted into it.

Patches

Fixed in 0.32.0. A .compose-lint.yml discovered in the working directory that resolves outside it is refused with exit 2 rather than read, and a policy parse error no longer quotes the line it failed on, matching the Compose loader. --config is read as given. 0.32.0 also stops following a Compose file that is a symlink to a target outside the checkout.

Workarounds

  • Upgrade to 0.32.0 or later.
  • Run with an explicit --config pointing at a policy file inside the project; the automatic lookup is then skipped.
  • Don't run compose-lint on untrusted pull requests on a machine whose files outside the checkout hold credentials.

Reproduction

project/.compose-lint.yml -> /path/outside/project/credentials   (symlink)
project/compose.yml          services: {web: {image: nginx:1.27}}

compose-lint --format sarif compose.yml exits 2, and the notification text quotes the start of the target's second line.

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
📦GitHub Actionstmatens/compose-lint≥ 0.2.0&&< 0.32.00.32.0
🐍PyPIcompose-lint≥ 0.2.0&&< 0.32.00.32.0pip install --upgrade 'compose-lint==0.32.0'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for tmatens/compose-lint, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update tmatens/compose-lint to 0.32.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-123371 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

Frequently Asked Questions

### Impact compose-lint automatically reads a `.compose-lint.yml` policy file beside the Compose file. It is meant to read nothing outside the project directory, but it follows that file if it is a symlink, wherever it points. A pull request can commit `.compose-lint.yml` as a symlink to a file on the CI runner. If the target is not valid YAML, the error compose-lint reports quotes part of the line the parser failed on. That quote reaches the job log (standard error), JSON `errors[]`, and the SARIF `toolExecutionNotifications`, which the Action uploads to Code Scanning. The run exits 2. Wha
O3 Security · Impact-Aware SCA

Is CVE-2026-123371 in your dependencies?

Find it across GitHub Actions, PyPI, including transitive dependencies.

CVE-2026-123371: compose-lint — Fixed in 0.32.0