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):
- Reject anything where
new URL(previewUrl).protocol is not https: (block file:, data:, http:, etc.)
- 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).
- 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.
- Log + skip cleanly on rejection. The receiver already 200'd; no DLQ traffic for invalid URLs.
Acceptance criteria
Component
Adapters (GitHub) / Security
Problem
environment_urlflows from the GitHubdeployment_statuswebhook payload straight intoPage.navigateinside 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_urltocaptureScreenshotwith no validation beyond presence.Proposed solution
In
cdk/src/handlers/github-webhook-processor.ts, before callingcaptureScreenshot(previewUrl):new URL(previewUrl).protocolis nothttps:(blockfile:,data:,http:, etc.)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).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.Acceptance criteria
isAllowedScreenshotUrl(url, allowlist)exported for testing*.vercel.app/*.amplifyapp.com/*.netlify.app/*.github.io(the providers documented in the screenshot guide)SCREENSHOT_HOST_ALLOWLISTdocumented indocs/guides/DEPLOY_PREVIEW_SCREENSHOTS_GUIDE.md