Skip to content

security: validate PERCY_SERVER_ADDRESS to loopback (PER-8681, PER-8682)#1165

Open
Shivanshu-07 wants to merge 1 commit into
masterfrom
security/PER-8681-8682-validate-server-address
Open

security: validate PERCY_SERVER_ADDRESS to loopback (PER-8681, PER-8682)#1165
Shivanshu-07 wants to merge 1 commit into
masterfrom
security/PER-8681-8682-validate-server-address

Conversation

@Shivanshu-07

@Shivanshu-07 Shivanshu-07 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Resolves the two runtime component findings behind the percy-ember chains (deadline 2026-06-21).

Ticket CWE Finding
PER-8681 CWE-918 PERCY_SERVER_ADDRESS injected verbatim controls all outbound HTTP targets
PER-8682 CWE-94 eval of network-fetched JS executes arbitrary code in the test browser

Root cause (shared)

addon-test-support/@percy/ember/index.js set utils.percy.address = SDKENV.PERCY_SERVER_ADDRESS with no validation. percySnapshot then eval()s the @percy/dom bundle returned by utils.fetchPercyDOM() — which is fetched from that address. So an attacker-controlled address both redirects all SDK traffic (SSRF) and turns the eval into RCE in the test browser.

Fix

Validate PERCY_SERVER_ADDRESS resolves to a loopback host (localhost/127.0.0.1/::1) before assigning it; otherwise warn and fall back to the @percy/sdk-utils default. The eval now only ever executes code served by the local Percy CLI.

The eval itself is the standard PercyDOM-injection mechanism shared by every Percy SDK and is left in place — this PR secures its source, which is the exploitable part. Documented inline.

Verification

  • Loopback logic unit-checked (localhost/127.0.0.1 accepted; evil.example, 169.254.169.254 rejected).
  • node --check passes.

Closes PER-8681, PER-8682. Together with the CI hardening (#1164) this severs the percy-ember supply-chain → runtime chains (PER-8691/8692/8693).

🤖 Generated with Claude Code

PER-8681 (CWE-918) — PERCY_SERVER_ADDRESS was assigned to utils.percy.address
with no validation, so an attacker who can set it could redirect all outbound
SDK HTTP (healthcheck, snapshot upload) to an arbitrary/internal host.

PER-8682 (CWE-94) — percySnapshot eval()s the @percy/dom bundle returned by
utils.fetchPercyDOM(), which is fetched from utils.percy.address. With an
unvalidated address that eval becomes remote code execution in the test browser.

Both share one root: the address. Validate PERCY_SERVER_ADDRESS resolves to a
loopback host (localhost/127.0.0.1/::1) before assigning it; otherwise warn and
fall back to the @percy/sdk-utils default. The eval now only ever runs code
served by the local Percy CLI. (eval itself is the standard PercyDOM-injection
mechanism shared by all Percy SDKs and is left in place, now sourced safely.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Shivanshu-07 Shivanshu-07 requested a review from a team as a code owner June 15, 2026 05:27
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.

2 participants