Skip to content

feat(procaptcha-frictionless): record iframe URL alongside top-frame URL#2818

Merged
forgetso merged 4 commits into
mainfrom
feat/frictionless-iframe-url
Jul 9, 2026
Merged

feat(procaptcha-frictionless): record iframe URL alongside top-frame URL#2818
forgetso merged 4 commits into
mainfrom
feat/frictionless-iframe-url

Conversation

@forgetso

@forgetso forgetso commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary

  • Widget now sends both currentUrl (top-frame URL — same resolution rules as before) and iframeUrl (widget's own frame URL when embedded, undefined when the widget IS the top frame).
  • Both fields are sanitised client- and server-side (origin + path only; query string, fragment and credentials stripped). Provider persists both on the Session record and forwards them onto post-PoW escalation sessions.
  • Only currentUrl is gated in the decision machine — unchanged. iframeUrl is recorded for analytics so we can distinguish "Protect's site-wide iframe endpoint" from "the page the user was actually on".

Follow-up to #2813, which resolved currentUrl to the top frame but dropped the iframe URL — this restores the iframe URL as a separate field rather than replacing one with the other.

Test plan

  • Verify a same-origin embed sends both fields (top-frame URL as currentUrl, iframe URL as iframeUrl).
  • Verify a cross-origin embed with a Referrer-Policy that leaks the top URL sends the referrer as currentUrl and iframe URL as iframeUrl.
  • Verify a top-frame widget sends currentUrl only (no iframeUrl).
  • Verify sessions in Mongo have both fields where applicable, and that post-PoW escalation sessions inherit both.

🤖 Generated with Claude Code

Widget now reports both the top-frame URL and the widget's own iframe URL on
frictionless sessions. `currentUrl` remains the top-frame URL (resolution
rules unchanged); `iframeUrl` carries the widget's own frame URL when
embedded so analytics can distinguish the site-wide iframe endpoint from the
page the user was actually on. Both fields are sanitised client- and
server-side; only `currentUrl` is gated in the decision machine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
forgetso and others added 3 commits July 9, 2026 10:58
…machines

Extends the previous commit: iframeUrl is now available alongside currentUrl
on RoutingMachineRawSignals (route + postPow + dedup replay paths) and on
the frictionless decision machine input, so a machine can key on the
distinction between the widget's own frame URL and the top-frame URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
At session-creation time, derive a boolean `isProtect` from the (currentUrl,
iframeUrl) pair — true when the widget iframe was served from
`protect.<tenant>` and embedded in a page on the same tenant. New
`isProtectDeployment` helper in `@prosopo/util` does the check with strict
dot-boundary matching (rejects `attackerclient.com` vs `protect.client.com`)
and is case-insensitive.

Persisted only when true (matches the `isEscalation` pattern); a sparse
`{isProtect, createdAt}` index on the session collection makes retrieval by
boolean cheap. Post-PoW escalation sessions inherit the flag from the
origin session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Auto-fix from `biome check --write` — CI biome lint was failing on
line-wrap style in the new isProtectDeployment tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@forgetso forgetso enabled auto-merge (squash) July 9, 2026 10:12
@forgetso forgetso merged commit 85e8857 into main Jul 9, 2026
11 checks passed
@forgetso forgetso deleted the feat/frictionless-iframe-url branch July 9, 2026 10:18
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.

1 participant