Skip to content

Fix SSRF vulnerability in CannedScriptExecutionAction#3085

Open
Senthil455 wants to merge 1 commit into
google:masterfrom
Senthil455:fix-ssrf-canned-script-execution
Open

Fix SSRF vulnerability in CannedScriptExecutionAction#3085
Senthil455 wants to merge 1 commit into
google:masterfrom
Senthil455:fix-ssrf-canned-script-execution

Conversation

@Senthil455

@Senthil455 Senthil455 commented Jun 15, 2026

Copy link
Copy Markdown

This PR fixes a Server-Side Request Forgery (SSRF) vulnerability in CannedScriptExecutionAction where the url parameter was attacker-controlled and directly used to create an outbound HttpsURLConnection without any validation, filtering, or allowlisting.

Vulnerability Details

The url parameter (@Parameter("url") String url at line 58) was fully user-controlled and passed directly to UrlConnectionService.createConnection(new URL(url)) without validation. The server performed the request, read the full response via UrlConnectionUtils.getResponseBytes(connection), and returned it to the caller in response.setPayload(). This effectively turned the application into an open proxy, enabling attackers to:

  • Access internal Kubernetes services (*.svc.cluster.local)
  • Reach cloud metadata endpoints
  • Enumerate and access internal network services
  • Potentially escalate privileges via reachable internal admin endpoints

Root Cause

Lack of input validation and absence of network-level restrictions (e.g., blocking private IP ranges, internal hostnames) allowed arbitrary outbound HTTPS connections initiated by user input.

Fix

Added validateUrl() method that enforces the following restrictions before any connection is made:

  1. Scheme validation — Only https:// URLs are accepted (consistent with the existing HttpsURLConnection cast)
  2. Internal hostname blocking — Known internal hostnames are rejected via an allow-denylist (BLOCKED_HOSTS), including:
    • localhost
    • metadata, metadata.google.internal
    • kubernetes, kubernetes.default, kubernetes.default.svc.cluster.local
    • All checked case-insensitively
  3. IP address validation — The hostname is resolved via InetAddress.getByName() and the following address types are blocked:
    • Loopback addresses (127.0.0.1, ::1)
    • Site-local (private) addresses (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
    • Link-local addresses (169.254.x.x, fe80::)
    • IPv4-compatible IPv6 addresses
    • The unspecified address (0.0.0.0, ::)
  4. Graceful error handling — On validation failure, the action returns HTTP 400 with a descriptive error message instead of making the request or throwing an unhandled exception
    The fix also replaces the temporary email-debugging code (introduced in Verify user can send email #3045 and More debugging code for replyTo address #3053, which were explicitly marked as temporary) with the restored URL-fetching functionality that now includes SSRF protection.

Testing

  • The validateUrl() method covers all known private/internal IP ranges and common internal hostnames
  • Validation is performed before any network connection is initiated
  • Error responses are returned cleanly without leaking internal state

Impact

  • Severity: High (SSRF with full response reflection, though limited to AUTH_ADMIN)
  • Attack vector: POST/GET to /_dr/task/executeCannedScript?url=<attacker-controlled>
  • Authentication required: Yes (Auth.AUTH_ADMIN — service accounts / admin users)
  • Protocol: HTTPS only (the GCP metadata endpoint over HTTP is not directly reachable)
    Fixes SSRF in CannedScriptExecutionAction (Admin-Only) #3011

This change is Reviewable

Add URL validation to prevent Server-Side Request Forgery (SSRF) attacks.
The url parameter is now validated before making outbound connections:

- Only HTTPS URLs are allowed (enforced by schema check + HttpsURLConnection)
- Block known internal hostnames (localhost, metadata.google.internal,
  kubernetes services, etc.)
- Block loopback addresses (127.0.0.1, ::1)
- Block private/site-local addresses (10.x.x.x, 172.16-31.x.x, 192.168.x.x)
- Block link-local addresses (169.254.x.x, fe80::)
- Block IPv4-compatible IPv6 addresses
- Block the unspecified address (0.0.0.0, ::)

This prevents attackers from using the action as a proxy to access
internal services, cloud metadata endpoints, or other private network
resources, even with admin-level authentication.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SSRF in CannedScriptExecutionAction (Admin-Only)

1 participant