Conversation
Build Branch
Static preview entry points
QR codes (mobile preview)
Integration commandsnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", branch: "pr-releases/fix/captcha-solve-reads-native-profile")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/fix/captcha-solve-reads-native-profile
git -C submodules/content-scope-scripts checkout origin/pr-releases/fix/captcha-solve-reads-native-profilePin to exact commitnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "4264d0b20e0eaafad6f30bb8592513f6fcca68a6")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/fix/captcha-solve-reads-native-profile
git -C submodules/content-scope-scripts checkout 4264d0b20e0eaafad6f30bb8592513f6fcca68a6 |
[Beta] Generated file diffTime updated: Mon, 07 Sep 2026 10:59:07 GMT Android
File has changed AppleFile has changed IntegrationFile has changed WindowsFile has changed |
|
This PR requires a manual review and approval from a member of one of the following teams:
|
2ba1527 to
baf4707
Compare
There was a problem hiding this comment.
Web Compatibility Assessment
| File | Lines | Severity | Finding |
|---|---|---|---|
injected/src/features/broker-protection/captcha-services/captcha.service.js |
72–178 | info | Broker-protection captcha logic runs only during native-driven PIR automation, not on arbitrary third-party pages. No browser API overrides, prototype patches, or general DOM timing changes — no general web-compat surface. |
injected/src/features/broker-protection/captcha-services/captcha.service.js |
137–141 | info | Profile-scoped solve guard is preserved (action.parent && !userData → error). This prevents solving the first widget on a multi-record page, which would remove a stranger's record — the critical compat/safety invariant from the PR description. |
injected/integration-test/broker-protection-tests/broker-protection-captcha.spec.js |
161–169 | info | Replaces the "held profile after page load" scenario with a direct "no profile on solve" test. Aligns with removing module-level state; no web-compat regression. |
injected/integration-test/page-objects/broker-protection.js |
307–309 | info | Test helper now returns only response[0] instead of matching by actionID. Test-only; acceptable for sequential flows but would not catch out-of-order multi-action completions. |
Security Assessment
| File | Lines | Severity | Finding |
|---|---|---|---|
injected/src/features/broker-protection/captcha-services/captcha.service.js |
(removed pendingCaptchaContext) |
info | Removing module-level pendingCaptchaContext is a security improvement: eliminates stale profile/token retention across navigations, failed solves, and retries. Client now supplies profile and token explicitly on each solveCaptcha, tightening the trust boundary. |
injected/src/features/broker-protection/captcha-services/captcha.service.js |
137–138 | info | Profile scoping error path retained. Prevents captcha token injection into the wrong DOM subtree when multiple user records exist on a broker page. |
injected/src/features/broker-protection/captcha-services/captcha.service.js |
160–165 | warning | The explicit no token available to solve the captcha guard was removed. A null/undefined token now flows into injectToken, which coerces to an empty input value and may return success with an empty token instead of a clear error. Low exploitability (native-controlled input), but weaker fail-closed behavior. |
| (all changed files) | — | info | No changes to messaging transports, nativeData handling, captured globals, message-bridge checks, or postMessage usage. |
Risk Level
Low Risk — Broker-protection captcha state-management refactor only; no API shims, messaging, or captured-globals changes; profile scoping guard preserved.
Recommendations
- (warning) Consider restoring an explicit
if (!token)early return insolveCaptchafor clearer fail-closed behavior and better native-client diagnostics. - (info) Honor the PR's merge gate: ship only after Apple/Android clients send
userProfilewith every scopedsolveCaptcha, or all scoped solves will fail with "no profile available". - (info) Optionally add an integration test for a missing/empty
tokenonsolveCaptchato lock in expected error behavior.
Sent by Cursor Automation: Web compat and sec
| } | ||
|
|
||
| const callback = captchaSolveProvider.getSolveCallback(captchaContainer, captchaToken); | ||
| const callback = captchaSolveProvider.getSolveCallback(captchaContainer, token); |
There was a problem hiding this comment.
Security (warning): The previous if (!captchaToken) return createError('no token available to solve the captcha') guard was removed along with pendingCaptchaContext. A missing token now reaches injectToken / getSolveCallback, which may coerce null to an empty input value rather than failing fast. Consider restoring an explicit token check for clearer, fail-closed behavior.
…ead of a held context
baf4707 to
daf1ae9
Compare


Summary
Asana: https://app.asana.com/1/137249556945/task/1217611870578214
This PR:
getCaptchaInfoandsolveCaptcha, because Apple and Android now send it with the token and the held copy was only standing in for that.Merge this only after the Apple and Android changes that send the profile reach a release. Until then both clients send the token alone and every scoped solve would fail.