{"id":"GHSA-88f4-frh5-gmcr","summary":"compose-lint: A `.compose-lint.yml` symlinked outside the project is read, and a parse error quotes part of the target","details":"### Impact\n\ncompose-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.\n\nA 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.\n\nWhat 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.\n\nThe Compose file loader stopped quoting source lines in parse errors in 0.25.0 (GHSA-whr6-fgpq-fpv9). The policy loader did not.\n\nFound during an internal pre-1.0 security review.\n\n**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.\n\n**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.\n\n### Patches\n\nFixed 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.\n\n### Workarounds\n\n- Upgrade to 0.32.0 or later.\n- Run with an explicit `--config` pointing at a policy file inside the project; the automatic lookup is then skipped.\n- Don't run compose-lint on untrusted pull requests on a machine whose files outside the checkout hold credentials.\n\n### Reproduction\n\n```\nproject/.compose-lint.yml -\u003e /path/outside/project/credentials   (symlink)\nproject/compose.yml          services: {web: {image: nginx:1.27}}\n```\n\n`compose-lint --format sarif compose.yml` exits 2, and the notification text quotes the start of the target's second line.","aliases":["CVE-2026-123371"],"modified":"2026-11-10T16:15:04.760056530Z","published":"2026-11-10T15:57:07Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-11-10T15:57:07Z","nvd_published_at":"2026-11-09T18:17:26Z","cwe_ids":["CWE-209","CWE-59"],"severity":"LOW"},"references":[{"type":"WEB","url":"https://github.com/tmatens/compose-lint/security/advisories/GHSA-88f4-frh5-gmcr"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-123371"},{"type":"WEB","url":"https://github.com/tmatens/compose-lint/pull/943"},{"type":"WEB","url":"https://github.com/tmatens/compose-lint/commit/e80547d33b2114040c4bc0e34ef210aee51f5058"},{"type":"PACKAGE","url":"https://github.com/tmatens/compose-lint"},{"type":"WEB","url":"https://github.com/tmatens/compose-lint/releases/tag/v0.32.0"}],"affected":[{"package":{"name":"compose-lint","ecosystem":"PyPI","purl":"pkg:pypi/compose-lint"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.2.0"},{"fixed":"0.32.0"}]}],"versions":["0.10.0","0.11.0","0.12.0","0.12.1","0.12.2","0.13.0","0.14.0","0.14.1","0.15.0","0.15.1","0.15.2","0.16.0","0.17.0","0.18.0","0.19.0","0.2.0","0.20.0","0.21.0","0.22.0","0.23.0","0.24.0","0.25.0","0.26.0","0.27.0","0.28.0","0.29.0","0.3.0","0.3.2","0.3.3","0.3.4","0.3.5","0.3.6","0.3.7","0.30.0","0.31.0","0.4.0","0.4.1","0.5.0","0.5.1","0.5.2","0.6.0","0.7.0","0.7.1","0.8.0","0.9.0"],"database_specific":{"last_known_affected_version_range":"\u003c= 0.31.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-88f4-frh5-gmcr/GHSA-88f4-frh5-gmcr.json"}},{"package":{"name":"tmatens/compose-lint","ecosystem":"GitHub Actions"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.2.0"},{"fixed":"0.32.0"}]},{"type":"GIT","repo":"https://github.com/tmatens/compose-lint","events":[{"introduced":"60c091c7cc8f86c6b0c5954031097364fea0a201"},{"fixed":"2d42617e4c6416f797bbfc6a057950131fa02df3"}]}],"versions":["v0.31.0","v0.30.0","v0.29.0","v0.28.0","v0.27.0","v0.26.0","v0.25.0","v0.24.0","v0.23.0","v0.22.0","v0.21.0","v0.20.0","v0.19.0","v0.18.0","v0.17.0","v0.16.0","v0.15.2","v0.15.1","v0.15.0","v0.14.1","v0.14.0","v0.13.0","v0.12.2","v0.12.1","v0.12.0","v0.11.0","v0.10.0","v0.9.0","v0.8.0","v0.7.1","v0.7.0","v0.6.0","v0.5.2","v0.5.1","v0.5.0","v0.4.1","v0.4.0","v0.3.7","v0.3.6","v0.3.4","v0.3.3","v0.3.2","v0.3.1","v0.3.0","v0.2.0"],"database_specific":{"last_known_affected_version_range":"\u003c= 0.31.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-88f4-frh5-gmcr/GHSA-88f4-frh5-gmcr.json"}}],"schema_version":"1.9.2","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"}]}