{"answers":{"affected":"2 open source packages ship an affected version, including @cyclonedx/cdxgen.","exploited":"There is no known exploitation of GHSA-qhh4-458h-xwh2 in the wild and no public exploit code.","fix":"Upgrade @cyclonedx/cdxgen to 12.3.3 or later.","what":"GHSA-qhh4-458h-xwh2 is a vulnerability in @cyclonedx/cdxgen, published on 8 May 2026. An attacker can exploit it over the internet without logging in, with no action from the victim."},"fix_prompt":"Check this codebase for GHSA-qhh4-458h-xwh2 and fix it if it is affected.\n\nWhat it is: GHSA-qhh4-458h-xwh2 is a vulnerability in @cyclonedx/cdxgen, published on 8 May 2026. An attacker can exploit it over the internet without logging in, with no action from the victim.\nExploitation: There is no known exploitation of GHSA-qhh4-458h-xwh2 in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- @cyclonedx/cdxgen (npm): affected from 9.9.5; fixed in 12.3.3\n- @cyclonedx/cdxgen (npm): affected from 9.9.5; fixed in 12.3.3\n\nTask:\n1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.\n2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.\n3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.\n4. Run the tests and summarise what changed and why.\n5. If nothing in the project is affected, say so and change nothing.\n\nReference: https://insights.sbomify.com/GHSA-qhh4-458h-xwh2/ (Markdown: https://insights.sbomify.com/GHSA-qhh4-458h-xwh2/index.md)","id":"GHSA-qhh4-458h-xwh2","markdown":"https://insights.sbomify.com/GHSA-qhh4-458h-xwh2/index.md","name":"GHSA-qhh4-458h-xwh2","record":{"aliases":[],"analysis":{"component_type":"developer_tool","fix_type":"upgrade","impacts":["data_read"],"network_reachable":"yes","non_default_config":false,"product_category":"npm SBOM generator","requires_auth":"none","summary":"An attacker can steal Docker registry credentials by exploiting substring matching logic that forwards private registry credentials to unrelated public registries.","user_interaction":"not_required","vuln_class":"information_disclosure"},"analysis_generated_by":"qwen3.8-flash-next","assigner":null,"cpe":[],"cvss":{"score":null,"severity":null,"source":null,"vector":null,"version":null},"cwes":[],"description":"# Docker registry auth substring match forwards credentials to a different registry\n\n## Repository\n\n`cdxgen/cdxgen`\n\n## Affected product/package\n\n- Ecosystem: npm\n- Package: `@cyclonedx/cdxgen`\n- Reviewed tree version: `12.3.3`\n- Reviewed commit: `b1e179869fd7c6032c3d483c3f7bd4d7154ec22b`\n- Affected file: `lib/managers/docker.js`\n- Affected from: v9.9.5\n\nThe Single Executable Applications (SEA) binaries and container images are also affected.\n\n## Weakness\n\nCWE-522 / CWE-346.\n\n## Summary\n\nWhen cdxgen scans or pulls container images through the Docker daemon API, it builds an `X-Registry-Auth` header from Docker credentials in `DOCKER_CONFIG/config.json`. The credential selection logic matches configured registry keys with substring checks:\n\n```js\nif (forRegistry \u0026\u0026 !serverAddress.includes(forRegistry)) {\n  continue;\n}\n```\n\nThis is not an origin-safe registry comparison. For example, credentials configured for `private-registry.example.com` are selected for a requested image under `registry.example.com`, because:\n\n```js\n\"private-registry.example.com\".includes(\"registry.example.com\") === true\n```\n\nThe selected credentials are then serialized into `X-Registry-Auth` for the Docker API pull request targeting the requested registry.\n\n## Reproduction\n\nUse the attached/local proof:\n\n```sh\nnode submissions/github-gsa/cdxgen-docker-registry-auth-substring-forwarding/evidence/cdxgen_docker_registry_auth_substring_probe.mjs\n```\n\nThe proof is fully local. It creates a temporary Docker config containing credentials for `private-registry.example.com`, starts a localhost mock Docker API endpoint, sets `DOCKER_HOST` to that endpoint, then calls cdxgen's exported Docker request path for a pull from `registry.example.com`.\n\nObserved vulnerable output:\n\n```json\n{\n  \"decision\": \"GO\",\n  \"dockerConfigAuthHost\": \"private-registry.example.com\",\n  \"requestedRegistry\": \"registry.example.com\",\n  \"substringMatch\": true,\n  \"dockerApiUrl\": \"/images/create?fromImage=registry.example.com/team/app:latest\",\n  \"headerPresent\": true,\n  \"decodedHeader\": {\n    \"username\": \"trusted-user\",\n    \"password\": \"trusted-pass\",\n    \"serveraddress\": \"private-registry.example.com\"\n  }\n}\n```\n\n## Impact\n\nIf an operator has Docker credentials for a private registry and uses cdxgen to scan an image from a different registry whose hostname is a substring of that private registry hostname, cdxgen can attach the private registry credentials to the Docker pull request for the different registry.\n\nIn a realistic attack, an attacker who controls or can observe the requested registry can induce a victim to scan an image from that registry. The Docker daemon API receives an `X-Registry-Auth` payload containing credentials for the victim's private registry but associated with the attacker-requested pull. This is a credential forwarding/misbinding issue in cdxgen's container image handling.\n\n## References\n\nFunctions `normalizeRegistryHost` and `registriesMatch` added to normalize and perform strict host matching.\n\nFix PR: https://github.com/cdxgen/cdxgen/pull/3964\n\nResearcher: Francesco SabiuResearcher: Francesco Sabiu","ecosystems":["npm"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"@cyclonedx/cdxgen: Docker registry auth substring match forwards credentials to a different registry","id":"GHSA-qhh4-458h-xwh2","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"npm","product":null,"products":[],"type":"information_disclosure","year":"2026"},"n_packages":2,"n_references":null,"packages":[{"ecosystem":"npm","fixed":["12.3.3"],"introduced":["9.9.5"],"last_affected":[],"package":"@cyclonedx/cdxgen","purl":null,"source":"GHSA-qhh4-458h-xwh2"},{"ecosystem":"npm","fixed":["12.3.3"],"introduced":["9.9.5"],"last_affected":[],"package":"@cyclonedx/cdxgen","purl":"pkg:npm/%40cyclonedx/cdxgen","source":"GHSA-qhh4-458h-xwh2"}],"products":null,"published":"2026-05-08","related":[],"sources":[{"class":"attribution","licence":"CC BY 4.0","name":"GitHub Advisory Database","prefix":"GHSA"}],"ssvc":{"automatable":null,"exploitation":null,"technical_impact":null},"state":null,"updated":null,"vendors":null},"summary":"An attacker can steal Docker registry credentials by exploiting substring matching logic that forwards private registry credentials to unrelated public registries.","url":"https://insights.sbomify.com/GHSA-qhh4-458h-xwh2/"}