{"id":"GHSA-rmx9-2pp3-xhcr","summary":"Tekton Pipelines has VerificationPolicy regex pattern bypass via substring matching","details":"hey guys,\n\ntriage contract\nthis is a first-screen summary; deterministic proof is in the proof bundle (canonical.log/control.log/witness.txt).\n\nsummary\ntrusted resources verification policies match a resource source string (`refSource.URI`) against `spec.resources[].pattern` using `regexp.MatchString`. in go, `regexp.MatchString` reports a match if the pattern matches anywhere in the string, so common unanchored patterns (including examples in tekton documentation) can be bypassed by attacker-controlled source strings that contain the trusted pattern as a substring. this can cause an unintended policy match and change which verification mode/keys apply.\n\npins\n- repo: https://github.com/tektoncd/pipeline\n- commit: 0133513db03dadb3cb08801d6b0330badcb63830\n- callsite: pkg/trustedresources/verify.go:118-137 (getMatchedPolicies)\n\nseverity\nMEDIUM (provisional CVSS 5.3–6.5) (signing request tampering)\n\nrepro (canonical)\n- command: unzip -q -o poc.zip -d poc && cd poc/poc-F-TEKTON-REGEX-001 && make canonical\n- expected: cap not reached; canonical does not emit the vulnerability markers.\n- actual: cap reached; canonical emits the vulnerability markers.\n- canonical markers (mandatory): [CALLSITE\\_HIT] + [PROOF\\_MARKER]\n\nnegative control\n- command: unzip -q -o poc.zip -d poc && cd poc/poc-F-TEKTON-REGEX-001 && make control\n- expected: cap not reached under the same harness; control emits the control marker and does not emit the vulnerability markers.\n- control markers (mandatory): [CALLSITE\\_HIT] + [NC\\_MARKER]\n\nfix\nconsider making matching safe-by-default by requiring full-string matches (or validating patterns and documenting substring semantics clearly). one option is to anchor patterns before matching (e.g., wrap `pattern` as `^(?:pattern)$` when not already anchored), or to provide a separate field for exact match vs regex match.\nfix accepted when: under the same harness, canonical still hits [CALLSITE\\_HIT] but does not emit [PROOF\\_MARKER].\n\nproof bundle pointers\n- bundle: poc.zip\n- bundle convention: zip extracts under a single top-level folder (poc-F-TEKTON-REGEX-001/) to avoid collisions\n- contains: canonical.log, control.log, witness.txt\n- extracted paths: after extraction, see ./poc/poc-F-TEKTON-REGEX-001/canonical.log, ./poc/poc-F-TEKTON-REGEX-001/control.log, ./poc/poc-F-TEKTON-REGEX-001/witness.txt\n- verify: compare shasum -a 256 for canonical.log/control.log/fix.patch/test source against witness.txt\n- supported-mode note: if your supported integration uses verified https app-links/universal links only, provide the supported tag/branch and we can retest on that pin.\n\n[poc.zip](https://github.com/user-attachments/files/24833926/poc.zip)\n\n---\n\nimpact\nan attacker can craft a trusted resources source string that embeds a trusted substring and still matches an unanchored verificationpolicy `spec.resources[].pattern`, even if the policy is intended to constrain matches to a specific trusted source. this occurs because `regexp.MatchString` succeeds on substring matches, so patterns like `https://github.com/tektoncd/catalog.git` match attacker-controlled sources such as `https://evil.com/?x=https://github.com/tektoncd/catalog.git`.\n\naffected: deployments using trusted resources verification with unanchored verificationpolicy patterns, where an attacker can influence the `refSource.URI` value used for policy matching.\n\nnot affected: deployments that anchor all patterns (`^...$`) or otherwise enforce full-string matching; deployments where attackers cannot influence `refSource.URI`.\n\nsteps to reproduce\n```bash\nunzip -q -o poc.zip -d /tmp/poc-tekton-regex-001\ncd /tmp/poc-tekton-regex-001/poc-F-TEKTON-REGEX-001\nbash ./run.sh canonical | tee /tmp/tekton-regex-001-canonical.log\nbash ./run.sh control | tee /tmp/tekton-regex-001-control.log\ngrep -n '\\\\[PROOF_MARKER\\\\]' /tmp/tekton-regex-001-canonical.log && grep -n '\\\\[NC_MARKER\\\\]' /tmp/tekton-regex-001-control.log && ! grep -n '\\\\[PROOF_MARKER\\\\]' /tmp/tekton-regex-001-control.log\n```\n\nsuggested patch options:\n- make matching safe-by-default by anchoring patterns before matching (or by validating and rejecting unanchored patterns).\n- document the substring semantics explicitly and update documentation examples to include anchors.\n\nworkarounds\nanchor verificationpolicy resource patterns so they must match the full source string. example:\n\n- `^https://github.com/tektoncd/catalog\\\\.git$`\n\nbest,\noleh","aliases":["CVE-2026-25542","GO-2026-5630"],"modified":"2026-07-17T21:06:31.588417510Z","published":"2026-04-21T16:25:19Z","database_specific":{"cwe_ids":["CWE-185"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-04-21T16:25:19Z","nvd_published_at":"2026-04-21T17:16:24Z"},"references":[{"type":"WEB","url":"https://github.com/tektoncd/pipeline/security/advisories/GHSA-rmx9-2pp3-xhcr"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-25542"},{"type":"WEB","url":"https://github.com/tektoncd/pipeline/commit/2c398711e6e9e232180508f0648425a8ea34dc9e"},{"type":"WEB","url":"https://github.com/tektoncd/pipeline/commit/b8905600322aa86327baae0a7c04d6cf1207362a"},{"type":"PACKAGE","url":"https://github.com/tektoncd/pipeline"},{"type":"WEB","url":"https://github.com/tektoncd/pipeline/releases/tag/v1.11.0"}],"affected":[{"package":{"name":"github.com/tektoncd/pipeline","ecosystem":"Go","purl":"pkg:golang/github.com/tektoncd/pipeline"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0.43.0"},{"fixed":"1.0.2"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-rmx9-2pp3-xhcr/GHSA-rmx9-2pp3-xhcr.json"}},{"package":{"name":"github.com/tektoncd/pipeline","ecosystem":"Go","purl":"pkg:golang/github.com/tektoncd/pipeline"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.2.0"},{"fixed":"1.3.4"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-rmx9-2pp3-xhcr/GHSA-rmx9-2pp3-xhcr.json"}},{"package":{"name":"github.com/tektoncd/pipeline","ecosystem":"Go","purl":"pkg:golang/github.com/tektoncd/pipeline"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.4.0"},{"fixed":"1.6.2"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-rmx9-2pp3-xhcr/GHSA-rmx9-2pp3-xhcr.json"}},{"package":{"name":"github.com/tektoncd/pipeline","ecosystem":"Go","purl":"pkg:golang/github.com/tektoncd/pipeline"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.7.0"},{"fixed":"1.9.3"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-rmx9-2pp3-xhcr/GHSA-rmx9-2pp3-xhcr.json"}},{"package":{"name":"github.com/tektoncd/pipeline","ecosystem":"Go","purl":"pkg:golang/github.com/tektoncd/pipeline"},"ranges":[{"type":"SEMVER","events":[{"introduced":"1.10.0"},{"fixed":"1.11.1"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-rmx9-2pp3-xhcr/GHSA-rmx9-2pp3-xhcr.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N"}]}