Skip to content

feat(security): scheme + host allowlist on screenshot processor's environment_url #286

@isadeks

Description

@isadeks

Component

Adapters (GitHub) / Security

Problem

environment_url flows from the GitHub deployment_status webhook payload straight into Page.navigate inside the AgentCore Browser session. The path is HMAC-gated and the navigate runs in the managed AgentCore session (not the Lambda VPC), so blast radius is bounded — but a scheme/host allowlist before navigating is cheap defense-in-depth.

Spawned from krokoko's review on PR #241 (non-blocking nit).

Expected behavior

The processor rejects URLs that aren't https:// or whose hostname matches private-IP / loopback patterns, before opening the browser session. Optional per-deployment hostname allowlist for stricter operators.

Current behavior

The processor passes environment_url to captureScreenshot with no validation beyond presence.

Proposed solution

In cdk/src/handlers/github-webhook-processor.ts, before calling captureScreenshot(previewUrl):

  1. Reject anything where new URL(previewUrl).protocol is not https: (block file:, data:, http:, etc.)
  2. Optional environment-variable-driven host allowlist SCREENSHOT_HOST_ALLOWLIST — comma-separated list of hostname suffixes (e.g. vercel.app,amplifyapp.com,netlify.app,github.io). Default empty = allow all https hosts (back-compat).
  3. Reject if hostname matches private-IP / localhost patterns (127.0.0.1, localhost, 10., 192.168., 169.254., ::1, etc.). This is the genuinely new SSRF protection — even without the allowlist, this catches the worst footguns.
  4. Log + skip cleanly on rejection. The receiver already 200'd; no DLQ traffic for invalid URLs.

Acceptance criteria

  • Helper isAllowedScreenshotUrl(url, allowlist) exported for testing
  • Unit tests cover scheme rejection, host allowlist match/miss, private-IP rejection, IPv6 loopback
  • No regression on *.vercel.app / *.amplifyapp.com / *.netlify.app / *.github.io (the providers documented in the screenshot guide)
  • SCREENSHOT_HOST_ALLOWLIST documented in docs/guides/DEPLOY_PREVIEW_SCREENSHOTS_GUIDE.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Priority 2 - medium priorityadaptersThird-party integrations: Linear, Slack, GitHub App, notification/deploy providersenhancementNew feature or requestsecurityCedar/HITL, IAM least-privilege, secrets, PII/DLP, guardrails, supply-chain/CVE

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions