Skip to content

Add opt-in SSRF guard for interceptor URLs - #2159

Open
avneetbansal-aws wants to merge 1 commit into
tektoncd:mainfrom
avneetbansal-aws:fix/interceptor-ssrf-url-validation
Open

avneetbansal-aws wants to merge 1 commit into
tektoncd:mainfrom
avneetbansal-aws:fix/interceptor-ssrf-url-validation

Conversation

@avneetbansal-aws

Copy link
Copy Markdown

Changes

Fixes #2023

interceptors.Execute() built its outbound request directly from an operator-supplied interceptor URL (clientConfig.url on a ClusterInterceptor, Interceptor, or NamespacedInterceptor) without validating the host. A cluster user who can define an interceptor could therefore point it at a cloud metadata endpoint such as 169.254.169.254, at loopback, or at any internal RFC1918 service, and the EventListener would issue that request from its own network context and forward the full InterceptorRequest payload. This is a server-side request forgery (SSRF) vector.

This change adds an opt-in guard. A new URLValidator in the interceptors package resolves the interceptor URL host and rejects any resolved address that is loopback, link-local (which covers the 169.254.0.0/16 metadata range), private, or unspecified. Execute() now takes an optional validator and runs the check before dispatching, so existing callers are unaffected.

The guard is gated behind a new feature flag interceptors.block-private-interceptor-urls in the feature-flags-triggers ConfigMap, defaulting to false so behaviour is unchanged on upgrade. It reuses the existing github.enterprise-host-allowlist entries (in config-triggers-core-interceptors) as an escape hatch, so legitimate in-cluster interceptor URLs that resolve to private addresses stay reachable when an operator turns the guard on. The design intentionally mirrors the existing enterprise-host allowlist hardening already in the repo.

One known limitation worth calling out: the check resolves the host and then a fresh connection is dialed, so there is a validate-then-reconnect (TOCTOU) window. Pinning the dialed IP via net.Dialer.Control would close that gap and is a reasonable follow-up; this PR keeps the scope to the pre-dispatch check, the flag, and the allowlist.

Submitter Checklist

  • Has Docs if any changes are user facing (added the flag to docs/install.md and the config/config-feature-flags.yaml manifest)
  • Has Tests included (unit tests for URLValidator, the new Execute path, and the feature flag)
  • Follows the commit message standard
  • Meets the Tekton contributor standards
  • Has a kind label. Adding /kind bug on the PR.
  • Release notes block below has been updated

Release Notes

Add an opt-in feature flag `interceptors.block-private-interceptor-urls` that rejects interceptor URLs resolving to loopback, link-local, private, or unspecified addresses, guarding against SSRF. It is off by default and honors the `github.enterprise-host-allowlist` as an escape hatch.

Execute() built an outbound request from an operator-supplied interceptor URL (clientConfig.url) with no host validation, so an interceptor could be pointed at cloud metadata endpoints such as 169.254.169.254, loopback, or internal services, and the EventListener would dispatch the request from its own network context.

This resolves the interceptor URL host and rejects loopback, link-local, private, and unspecified addresses when the new interceptors.block-private-interceptor-urls feature flag is enabled. The flag is off by default to preserve backwards compatibility, and hosts in the existing github.enterprise-host-allowlist are exempt so legitimate in-cluster interceptor URLs on private ranges stay reachable. The design mirrors the existing enterprise-host-allowlist hardening.

Signed-off-by: avneetbansal-aws <[email protected]>
@tekton-robot tekton-robot added the release-note Denotes a PR that will be considered when it comes time to generate release notes. label Oct 5, 2026
@tekton-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please assign khrm after the PR has been reviewed.
You can assign the PR to them by writing /assign @khrm in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@linux-foundation-easycla

linux-foundation-easycla Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

  • ✅ login: avneetbansal-aws / name: avneetbansal-aws (0fc7574)

@tekton-robot tekton-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Oct 5, 2026
@avneetbansal-aws

Copy link
Copy Markdown
Author

/kind bug
/area interceptors

@tekton-robot tekton-robot added the kind/bug Categorizes issue or PR as related to a bug. label Oct 5, 2026
@tekton-robot

Copy link
Copy Markdown

@avneetbansal-aws: The label(s) area/interceptors cannot be applied, because the repository doesn't have them.

Details

In response to this:

/kind bug
/area interceptors

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/bug Categorizes issue or PR as related to a bug. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add URL validation in interceptor Execute() to restrict outbound requests

2 participants