Retain full addresses for broker opt-outs#2872
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/poc/people-search-now-address-anchor")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/poc/people-search-now-address-anchor
git -C submodules/content-scope-scripts checkout origin/pr-releases/poc/people-search-now-address-anchorPin to exact commitnpm (Android / Extension): Swift Package Manager (Apple): .package(url: "https://github.com/duckduckgo/content-scope-scripts.git", revision: "1b83f23e6a3e7fd6595a66e97d8553257297a0ee")git submodule (Windows): git -C submodules/content-scope-scripts fetch origin pr-releases/poc/people-search-now-address-anchor
git -C submodules/content-scope-scripts checkout 1b83f23e6a3e7fd6595a66e97d8553257297a0ee |
[Beta] Generated file diffTime updated: Tue, 21 Jul 2026 02:27:15 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:
|
There was a problem hiding this comment.
Stale comment
Web Compatibility & Security Assessment
Risk Level: Low Risk — Broker-protection-only changes (extract/aggregate/fill-form) with no browser API overrides, messaging transport changes, or global prototype/DOM side effects; impact is confined to config-gated data-broker opt-out flows.
Web Compatibility Assessment
File Lines Severity Finding injected/src/features/broker-protection/extractors/address.js149–152 warning formatStreetAddress()reassembles components viaparse-addressnormalization (e.g.street→St). Opt-out forms that validate against the exact page text may reject the filled value even when extraction succeeded. Consider falling back to the unparsed street line fromfullAddresswhen broker configs require verbatim text.injected/src/features/broker-protection/actions/extract.js391 warning Address deduplication still keys on `${city},${state}`. Two distinct full addresses in the same city/state will collapse to one entry inaddresses[]. More visible now that entries carrystreetAddress/fullAddress.injected/src/features/broker-protection/extractors/address.js138 info fullAddressStrings()protects only the first `viavalue.replace('', marker) . Multi-line addresses with multiple line breaks may still split unexpectedly whenseparator` is set.injected/src/features/broker-protection/actions/extract.js384–416 info currentAddressis taken from pre-sort page order (addressFull[0]/addressFullList[0]) whileaddresses[]is sorted — intentional per unit tests, but broker configs must target the "current" anchor (XPath in PeopleSearchNow test) rather than relying on list position after aggregation.All runtime files — info No API shims, prototype mutations, observers, or viewport/meta changes. Broker protection is remote-config gated and only executes native-orchestrated actions on broker pages — no general third-party site compatibility surface. Tests only — info Integration + unit coverage added (45 specs pass locally). PeopleSearchNow XPath selector correctly scopes to "Current Address:" and excludes "Used to Live:" history.
Security Assessment
File Lines Severity Finding All runtime files — info No changes to captured-globals.js, message bridge, origin validation, ornativeDatahandling. Extracted address data flows only through existingactionCompletedbroker-protection messaging — no new exfiltration vectors.injected/src/features/broker-protection/actions/fill-form.js86–89 info New street/zipCodefield types write page-scraped PII into broker opt-out form inputs — intentional and scoped to broker automation. Falls back to existing generators when data is absent (data.street || generateStreetAddress()).injected/src/features/broker-protection/extractors/address.js116–117 info ...parsedspreads allparse-addressoutput into result objects forwarded to native. Page-controlled DOM text could yield unexpected parser fields, but output stays within the broker-protection trust boundary and is not executed.injected/src/features/broker-protection/actions/fill-form.js171–205 info Pre-existing setValueForInput()uses uncapturedObject.getOwnPropertyDescriptor,window.HTMLInputElement, andEvent— not introduced by this PR; acceptable in broker-protection context where page scripts are already active.
Recommendations
- (warning) Add a unit test where two full addresses share city/state and confirm dedup behaviour is acceptable, or key the
MaponfullAddress/streetAddresswhen present.- (warning) Document in broker config guidance that
formatStreetAddressmay normalize abbreviations; provide a config escape hatch (e.g. fillfullAddressstreet line verbatim) if brokers reject normalized values.- (info) Consider
replaceAll(' ', marker)(or a global regex) infullAddressStringsif multi-line addresses become common.- (info) Coordinate privacy-configuration broker action JSON to use the new
street/zipCodefill types and PeopleSearchNow-styleaddressFullXPath anchor before shipping.
Verdict: Approve from a web-compat/security perspective. Changes are well-scoped, tested, and do not touch security-critical infrastructure. Residual risks are broker-specific extraction/fill fidelity, not general web breakage.
Sent by Cursor Automation: Web compat and sec
| export function formatStreetAddress(address) { | ||
| const unit = [address.sec_unit_type, address.sec_unit_num].filter(Boolean).join(' '); | ||
| const streetAddress = [address.number, address.prefix, address.street, address.type, address.suffix, unit].filter(Boolean).join(' '); | ||
| return streetAddress || null; |
There was a problem hiding this comment.
warning (broker fill fidelity): formatStreetAddress() normalizes via parse-address (e.g. street → St). If an opt-out form validates against the exact scraped span text, the normalized value may be rejected. Consider a verbatim fallback from the street line of fullAddress when available.
| const currentAddress = profile.addressFull?.[0] || profile.addressFullList?.[0]; | ||
| const combinedAddresses = [ | ||
| ...(profile.addressCityState || []), | ||
| ...(profile.addressCityStateList || []), |
There was a problem hiding this comment.
warning (data loss): Dedup key is still `${city},${state}`. With richer address objects, two distinct streets in the same city/state will collapse. Worth a test or switching the key to fullAddress/streetAddress when those fields exist.
| */ | ||
| function fullAddressStrings(value, separator) { | ||
| const lineBreakMarker = '\uE000'; | ||
| const protectedValue = value.replace('\n', lineBreakMarker); |
There was a problem hiding this comment.
info: Only the first is protected before list splitting. Multi-line addresses with several breaks may still split incorrectly when a custom separator is configured.
There was a problem hiding this comment.
Stale comment
Injected PR Evaluation: Web Compatibility & Security
Re-assessed on synchronize (
a9e792496). Latest commit updates an existing integration-test expectation to match the richer address profile — no runtime changes.Web Compatibility Assessment
injected/src/features/broker-protection/extractors/address.js(149–152) — warning:formatStreetAddress()reassembles parsed components with normalized abbreviations (e.g."street"→"St"). Opt-out forms that require verbatim page text may reject the filled value even whenfullAddresspreserves the original string.injected/src/features/broker-protection/actions/extract.js(391) — warning: Address deduplication still keys on`${city},${state}`. With richer full-address objects, distinct streets in the same city/state collapse to one entry inaddresses[].injected/src/features/broker-protection/extractors/address.js(136–139) — info:fullAddressStrings()protects only the firstbefore list splitting; additional newlines are collapsed viareplace(/\s+/g, ' ')at parse time.injected/src/features/broker-protection/actions/fill-form.js(86–89) — info: Newstreet/zipCodefield types fall back to generated values when data is missing (unlikecityState, which errors). Intentional for opt-out resilience, but a partial extraction could submit synthetic address data.- No general web-compat regressions — Changes are scoped to broker-protection extract/fill logic on data-broker pages. No browser API overrides, prototype mutation, observers, or page-wide DOM side effects.
Security Assessment
- No security-critical path changes — No edits to
captured-globals.js, wrapper utilities, message bridge, messaging transports, or origin validation.injected/src/features/broker-protection/actions/extract.js(116–122, 410–416) — info: Extended scrape output (...parsed, top-levelstreet/zipCode) flows through the existingSuccessResponse→ native messaging path. Data is page-derived; no new exfiltration vectors beyond pre-existing broker-protection extraction.injected/src/features/broker-protection/actions/fill-form.js(86–89) — info: Pre-existingsetValueForInputuses uncapturedObject.getOwnPropertyDescriptor/Event(established autofill pattern). No new dynamic code execution,postMessage, or network requests.- Messaging hygiene — No object spreading of unknown payloads; no
nativeDatain outgoing messages.Risk Level
Low Risk — Broker-protection-only changes extending address extraction and form-fill field types, with solid unit/integration coverage and no API-override or security-boundary modifications.
Recommendations
- (warning) When configuring opt-out forms, prefer
fullAddress(verbatim) overstreet/streetAddressif a broker validates against exact page text; document this in broker config guidance.- (warning) Consider dedup keying on
fullAddressorstreetAddresswhen available, not justcity,state, to avoid losing distinct addresses in the same locale.- (info) Add a unit test for multi-line addresses with more than one
if brokers emit that format.- (info) Consider explicit error (not generated fallback) for
street/zipCodewhen extraction is required for a given broker step.Tests: 45/45 broker-protection extract + fill-form unit specs pass locally.
Sent by Cursor Automation: Web compat and sec
Preserve extracted street and ZIP data so broker opt-out forms can use real addresses while retaining generated fallbacks. Co-authored-by: Cursor <[email protected]>
Add a sanitised broker-style fixture to verify the current full address is selected and retained end to end. Co-authored-by: Cursor <[email protected]>
Keep the existing extraction fixture aligned with the richer address profile returned by the extractor. Co-authored-by: Cursor <[email protected]>
Return a clean {streetAddress, city, state, zip, fullAddress} shape from
extractAddressFull instead of leaking all parse-address internals, and split
address lists by delimiter before collapsing intra-address whitespace (dropping
the newline-marker hack). Document the city/state dedup and the street/zipCode
generated fallback, and add an end-to-end opt-out form-fill integration test.
Fixture names follow the existing scenario-based convention (no broker name).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
a9e7924 to
d6922e1
Compare
There was a problem hiding this comment.
Web Compatibility Assessment
| File | Lines | Severity | Finding |
|---|---|---|---|
injected/src/features/broker-protection/extractors/address.js |
160–171 | warning | formatStreetAddress() rebuilds the street line from parse-address tokens, which normalizes abbreviations (e.g. "Street" → "St"). Brokers that validate opt-out forms against verbatim page text may reject the normalized value. fullAddress preserves the original string but is not used by fillForm today. |
injected/src/features/broker-protection/actions/extract.js |
391–395 | warning | Address deduplication still keys on ${city},${state} only. Multiple distinct streets in the same city/state collapse to one entry in addresses. Documented as acceptable for city/state matching, but the surviving entry may not be the user's actual street. Form fill is unaffected because currentAddress is taken from page order separately. |
injected/src/features/broker-protection/extractors/address.js |
144–157 | info | Default list separator for full addresses is `/[ |
injected/src/features/broker-protection/actions/fill-form.js |
90–93 | info | street and zipCode fall back to generated values when extraction is empty (same pattern as existing $generated_*$ types). A generated street/zip that does not match the broker record could cause opt-out validation failure, but prevents leaving required fields blank. |
injected/src/features/broker-protection/actions/extract.js |
382–419 | info | No API overrides, prototype mutations, or global shims. Changes are confined to broker-protection extract/aggregate logic, which only runs when the feature is enabled and native schedules an action on a broker page. |
Security Assessment
| File | Lines | Severity | Finding |
|---|---|---|---|
injected/src/features/broker-protection/actions/extract.js |
408–424 | info | New street/zipCode fields are explicitly constructed from scraped DOM text and returned to native via existing actionCompleted messaging. No nativeData forwarding; no new message schemas or bridge changes. |
injected/src/features/broker-protection/actions/fill-form.js |
90–93 | info | Page-derived address components are written into broker opt-out form fields — intentional, scoped behavior. Values pass through existing setValueForInput() (native setter + synthetic events); no new eval, postMessage, or network requests. |
injected/src/features/broker-protection/extractors/address.js |
120–134 | info | parse-address parses untrusted page text. Output is used only for broker opt-out automation, not for security decisions. Parsing failures are filtered by the parsed.city guard. |
| — | — | info | No changes to captured-globals.js, message-bridge trust boundaries, origin validation, load()-time hooks, or shouldExemptMethod(). Pre-existing uncaptured Object.getOwnPropertyDescriptor / new Event() usage in fill-form.js is unchanged. |
Risk Level
Low Risk — Broker-protection–scoped extraction and form-fill changes only; no browser API overrides, messaging security changes, or cross-site impact. Blast radius is limited to configured broker opt-out flows.
Recommendations
- (warning) Monitor PeopleSearchNow opt-out validation with normalized
streetAddressvalues. If brokers reject abbreviated forms, consider afullAddress-based fill type or a verbatim street-line extractor for the street field. - (warning) Document the city/state dedup limitation in broker config guidance so operators know
addressesis a match aid, not a complete history list. - (info) If newline-separated address lists appear in the wild, add an explicit
separatorto the broker config or extendADDRESS_LIST_SEPARATOR. - (info) 48 broker-protection unit specs pass locally (
broker-protection-extract.js,broker-protection-fill-form.js).
Sent by Cursor Automation: Web compat and sec
| */ | ||
| function formatStreetAddress(address) { | ||
| const unit = [address.sec_unit_type, address.sec_unit_num].filter(Boolean).join(' '); | ||
| const streetAddress = [address.number, address.prefix, address.street, address.type, address.suffix, unit].filter(Boolean).join(' '); |
There was a problem hiding this comment.
warning (web compat): formatStreetAddress() normalizes tokens via parse-address (e.g. "Street" → "St"). If a broker's opt-out form validates against verbatim page text, this normalized value may be rejected even though fullAddress preserves the original. Consider exposing a verbatim street fill path if PeopleSearchNow validation fails in production.
| // Deduped to one entry per city/state: this list is used for matching the user against a | ||
| // profile, which is a city/state-level comparison. The current address (with its street/zip) is | ||
| // flattened separately below, so collapsing same-city history here doesn't lose what fills a form. | ||
| const addressMap = new Map(combinedAddresses.map((addr) => [`${addr.city},${addr.state}`, addr])); |
There was a problem hiding this comment.
warning (web compat): Dedup still keys on city,state only — distinct streets in the same city/state collapse to one addresses entry. Acceptable for city/state matching, but worth noting in broker config docs. Form fill is safe because currentAddress is sourced from page order above.
Add top-of-fixture comments noting the markup is a trimmed subset of a real PeopleSearchNow page (matching the Veripages fixture convention), and replace the real broker-record name with the standard Smith placeholder. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>


Asana Task/Github Issue: N/A
Description
Preserves the full
parse-addressoutput and original address text when scanning broker profiles, then flattens the currentstreetandzipCodeso opt-out actions can reference them. The new field mappings use real extracted values when available and fall back to the existing generated values otherwise.This is a proof of concept for making peoplesearchnow.com the PeopleFinders cluster's opt-out anchor. It includes a sanitised PeopleSearchNow-style HTML fixture which verifies that the current address is selected instead of address history, and that the street, city, state and ZIP survive extraction.
Native persistence and broker-rule schemas live outside this repo and still need verification.
Testing Steps
npm run test-unit -w injected.npm run test-int -w injected -- --project windows --grep "PeopleSearchNow-style" --reporter list.npm run tsc && npm run tsc-strict-core.npm run build -w injected.Checklist
Please tick all that apply: