The Payment Handler API [[payment-handler]] is one of several technologies (along with the Payment Request API [[payment-request]]) designed to streamline Web payments and make them more secure. It is an important design goal that the Payment Handler API not introduce new vulnerabilities that an attacker can exploit to infringe on a user’s privacy. This document describes a threat model for evaluating the design choices of the Payment Handler API against this privacy goal.
This is a living document that aims to capture an up-to-date view of the privacy threat model to drive discussion of mitigations, for example within the Web Payments Working Group. It will be updated regularly to match the current state of Payment Request API and Payment Handler API.

Terminology

These definitions are imported from other sources.

origin
An origin is the tuple of a scheme, host, and port that provides the main security boundary on the web.
context
A context is a set of resources (e.g. websites, applications) that are controlled by the same party or jointly controlled by a set of parties.
user ID
A user ID is a pair of a site and a (potentially-large) integer allocated by that site that is used to identify a user on that site.
first party
A first party for a user action is the party that controls the origin of the top-most browsing context or application under which the action happened.
tracking
Tracking is the collection of data regarding a particular user’s identity or activity across one or more contexts and the retention, use, or sharing of data derived from that activity outside the context in which it occurred.
cross-site tracking
Cross-site tracking is tracking by a third-party across multiple first-party contexts.
browser fingerprinting
Browser fingerprinting is the capability of a site to identify or re-identify a visiting user, user agent or device via configuration settings or other observable characteristics.
super-cookie
A super-cookie uses fingerprinting to recreate state and track users, even after a user has expunged their browsing history and storage.
payment handler
A payment handler is a web or native application that handles requests for payment. A payment handler can be implemented in different ways:
  • As a Service Worker that implements the Payment Handler API; we call this a “Web-based payment handler”.
  • As a native mobile app that integrates with a browser.
  • As a built-in capability of a user agent.
merchant
A merchant is a website requests payment credentials via, for example, the Payment Request API.

Assumptions

Principles

We use the following principles to help evaluate the quality of design decisions.

User Consent

Without seeking to precisely define “user consent” in this document, users should have control over the sharing of information. User control may manifest itself in a variety of ways, including:

Least Power

The protocols should not disclose private details of the user’s identity or other sensitive information unless required for operational purposes or by legal or jurisdictional rules.

Minimal Friction

In general, we seek to minimize friction in the user experience. However, “minimal” does not always mean “none,” especially in the pursuit of user privacy and security.

Priority of Constituencies

See priority of constituencies.

No Regression

The payments APIs should provide privacy and security protection that is at least on par with —and in general better than— existing approaches.

Scope

In Scope Scenarios

This threat model focuses on the following privacy threats that a merchant, a payment handler, or both in collusion, may exploit against a user:

In Scope Technologies

Although this document focused primarily on Web-based payment handlers, it does include some discussion of native payment handlers as well (specifically, on Android).

Out of Scope

This threat model does not address the following:

Capability Review

The Payment Request API and Payment Handler API provide a set of capabilities to merchants and payment handlers. The Chrome implementation provides additional capabilities. In the descriptions below we label the former "Spec" and the latter "Chrome".

Installation

Use Case(s)
  • The provider of a new payment method wants to make it as easy as possible for a user to access a payment handler. The browser can facilitate "just-in-time installation" of a payment handler during a transaction, making the installation process seamless.
Capabilities (Chrome)
  • C1: A merchant can cause a web-based payment handler from a specific origin to be just-in-time installed. In this case, the service worker is only installed (1) upon request.show() followed by (2) user selection of this payment handler for this payment request.
  • C2: A first-party website can install a service worker without any user gesture or visible UI —an existing capability of Service Workers— and register it as a payment handler.
Discussion

Communication between origins

Use Case(s)
  • Each payment method defines a data model, including information provided by the merchant to the payment handler, and response data from the payment handler to the merchant (e.g., card information, a status report after a credit transfer). In addition, payment methods may include data used by the browser as part of determining whether a payment handler can be used for a particular set of merchant conditions.
  • For many merchants, the decision to use Payment Request API for a particular transaction will depend in part on knowing whether the user is "ready to pay" with a minimum of friction. Merchants may choose to fall back to forms or other techniques if they cannot determine that the Payment Request path will likely result in successful payment.
Capabilities (Spec)
  • C3: A merchant can send arbitrary data to an installed payment handler (either Web-based or native Android) without any user action or visible UI, via method-specific data and hasEnrolledInstrument
  • C4: A merchant can receive arbitrary data from an installed payment handler (either web-based or native Android) after request.show(), either repeatedly via method-specific details or the final PaymentResponse.
Discussion

Merchant knowledge of user environment

Use Case(s)
  • As mentioned above, merchants may choose to fall back to forms or other techniques if they cannot determine that the Payment Request path will likely result in successful payment.
Capabilities
  • C5: A merchant can know that payment handlers (matching the payment method identifiers provided by the merchant) are installed or just-in-time installable in the user’s browser without any user gesture or visible UI, by calling request.canMakePayment(). Note: canMakePayment() is a specification capability; just-in-time installation is a Chrome capability.
  • C6: A merchant can check whether the user has at least one enrolled instrument for a given set of payment method identifiers without any user gesture or visible UI, by calling request.hasEnrolledInstrument(). For a web-based payment handler, this triggers a canMakePaymentEvent in the service worker (to be renamed to "hasEnrolledInstrumentEvent"). Note: hasEnrolledInstrument() is a specification capability. The corresponding capability is not currently provided for native Android payment handlers.
Discussion

Payment Handler browsing context (and its capabilities)

Use Case(s)
  • The redirection of users to other Web sites during a transaction is cited as one reason for cart abandonment. Thus, there is a desire to facilitate payment without "leaving the merchant context."
  • Payment handlers can, but are not required to, provide for user input. Use cases such as micropayments or seeking a cryptogram from a token service provider for a card-on-file payment may not necessitate user interaction.
  • Payment handler distributors will want to leverage all or most capabilities of the Web platform, including access to device capabilities, Web authentication, OAUTH, iframes, redirects, etc..
Capabilities (Spec)
  • C7: Following request.show(), a web-based payment handler can create a new top-level browsing context, presented in Chrome as a modal overlay over the merchant context called the payment handler window. This window prevents the user from interacting with the merchant context until the overlay is dismissed. Note: We believe the experience of maintaining the checkout context under the modal window is superior to a redirect.
  • C8: A payment handler (both web-based and native Android) can complete a payment request without showing any user interface. Note: It may be impossible to mandate that a native Android payment app show a user interface.
  • C9: Inside its payment handler window a web-based payment handler can access most Web APIs that are available in a top-level context, including storage (e.g. IndexedDB, but not document.cookies), navigating its payment handler window to any origin, embedding iframes, and triggering APIs such as WebAuthn, geolocation, etc. Note: Some functionalities are limited: e.g. window.open is ignored.
Discussion

Attack Analysis

The attack vectors enumerated below can be grouped into several themes:

SilentPersistentStorage
This refers to the ability of the payment handler to persist data into local or remote storage without explicit user consent to interact with this payment handler, i.e. during hasEnrolledInstrument and canMakePayment.
OpaqueDataTransfer
This is especially bad when combined with SilentPersistentStorage or InvisibleTransaction.
1PStorageAccess
This refers to the risks associated with opening a payment handler by default in a first party context.
InvisibleTransaction
This refers to the payment handler’s ability to complete a transaction without explicit user confirmation. This is particularly harmful if coupled with skip-the-sheet.

Note:Risk may be lower if user explicitly allowed “no-UI flow” for some use cases. Also consider cross-device payment sheet.

NativeAppAs1PStorage
TODO: investigate if native app can push some data to the browser so that browser can use this to answer HEI and CMP w/o sending intent to native app.
NonPaymentUsage
A successful exploit of this surface requires the merchant to phish a user gesture without revealing to the user that a payment request is triggered. See ideas for payment handlers from Adrian Hope-Bailie.

In the detailed analysis below we relate the threats to these themes.

Cross-Site Tracking

Web-based payment handler as a zero-click tracker

badph.example hosts a badph.js file that does the following:

  • Creates a PaymentRequest that specifies badph.example as a supported method
  • Adds the full URL, i.e. location.href, to the method-specific data of the request (C3)
  • Calls request.hasEnrolledInstrument()
    • badph.example convinces merchant1.example and merchant2.example to serve badph.js via a <script> tag
    • User visits badph.example, which installs its service worker and registers it as a payment handler (C2)
  • The service worker records a user ID in IndexedDB
    • User visits merchant1.example. The code from badph.js runs, and request.hasEnrolledInstrument() causes a CanMakePaymentEvent to be triggered in badph.example’s service worker (C5)
    • The service worker extracts the full URL from CanMakePaymentEvent.methodData (C3), and sends that and the user ID from IndexedDB (C9) to badph.example server.
    • Similarly, when a user visits merchant2.example, badph.example can reidentify the same user.
Failure points
  • merchant1.example is able to send data to a third party, badph.example, without a clear intention for the user to interact with badph.example. (OpaqueDataTransfer)
  • badph.example’s service worker is able to access its global storage without receiving clear user consent to interact. (1PStorageAccess)
  • A user cannot be reasonably expected to know that their visit to badph.example enables badph.example to record their history across colluding websites, which can be a large set. badph.example can be masquerade itself behind other useful utility that a merchant may want to include: e.g. socialnetwork.example, usefullibrary.example. (SilentPersistentStorage)
  • Payment Request API is used when no clear payment intention is established. (NonPaymentUsage)
Mitigations

Chrome already implements the following limits on hasEnrolledInstrument():

  • CanMakePaymentEvent is not triggered in incognito mode
  • hasEnrolledInstrument() is throttled to 1 call per 30 minutes per merchant origin. However, this breaks a legitimate use case: a merchant wants to show payment buttons from two legitimate payment methods side-by-side.
  • Chrome offers a setting that allows user to opt-into short-circuiting hasEnrolledInstrument() for all payment handlers

Additional strategy ideas:

  • Require user to opt-in for each payment handler that wants to respond to hasEnrolledInstrument() as part of explicit payment handler installation experience
    • This should eliminate most non-payment websites from being able to exploit Payment Request API.
    • Still won’t be able to prevent real payment handlers to track user’s browsing history on shopping websites.
  • Remove hasEnrolledInstrument()
    • Breaks legitimate use case of showing payment buttons. The fundamental tension is that the data passed between merchant and payment handler is not standardized (and may be hard to) and is opaque to the browser, so it is very difficult for the browser to determine which calls are only passing legitimate data and which ones are sneaking in tracking data.
  • Service worker can only access 3P storage before request.show(), which requires a user gesture which may serve as an intent to interact
    • Breaks legitimate use case of showing payment buttons because hasEnrolledInstrument() no longer has access to a user ID that it can use to check instrument availability.
  • Per-method quota
  • Prompt user on hasEnrolledInstrument, e.g. “merchant.example wants to check if you can pay with ph.example: Allow Once, Disallow, Always Allow on merchant.example, Always Disallow on merchant.example”
    • Very intrusive. May discourage the use of hasEnrolledInstrument()
  • Browser uses telemetry to detect origins that call hasEnrolledInstrument() but never call request.show() and black list known bad behaviors
    • Caveat: easy to blacklist merchant\*.example but harder to blacklist badph.example because telemetry records main resource origin, not subresource origin.

Native Android app based payment handler as a zero-click tracker

Same steps as for a web-based payment handler regarding a Web-based zero-click track attack, except:

  • User installs an Android app published by badph.example (possibly masquerading as a useful tool, a game, etc.)
  • The hasEnrolledInstrument() call triggers an IS_READY_TO_PAY intent to badph.example’s Android app.
  • The Android app links the full URL and user identity within the app, and either saves it locally or sends to badph.example server.
Failure points
  • A locally installed Android app acts as its own global storage across contexts (NativeAppAs1PStorage)
  • A user cannot be reasonably expected to know that any Android app can be a tracker of their web browsing activities. (SilentPersistentStorage)
Mitigations
  • Require explicit user opt-in for native Android app to act as payment handler in browser
    • This should eliminate most non-payment apps from being able to exploit Payment Request API
    • Remaining gap: payment apps can still track users across shopping websites.

One-click tracking by payment handler

badph.example hosts a badph.js file that does the following:

  • Creates a PaymentRequest that specifies badph.example as a supported method
  • Adds the full URL, i.e. location.href, to the method-specific data of the request (C3)
  • Creates a button that calls request.show() when clicked

badph.example convinces merchant1.example and merchant2.example to serve badph.js via a <script> tag. Then:

  • User visits merchant1.example and clicks on the button created by badph.js. This triggers request.show() which causes the following to happen:
    • A web-based payment handler from badph.example to be installed (C1)
    • A PaymentRequestEvent to be triggered in badph.example’s service worker. The service worker reads a user ID from IndexedDB (#C9), or writes a new one if there isn’t already one. The service worker extracts the full URL from PaymentRequestEvent.methodData (C3)), and sends that and the user ID to badph.example server.
  • User visits merchant2.example and click on the badph.js button again.
  • badph.example service worker reads user ID from IndexedDB (C9), identifies the user, and records the new merchant2.example URL in this user’s profile.

This attack is less dangerous than a Web-based zero-click track attack because it requires tricking the user to click on something. On the other hand, request.show() is not subject to throttling like hasEnrolledInstrument().

Note: The steps above refer to a Web-based payment handler, but the same attack can be performed with a native Android payment handler.

Failure points
  • The click target may not reveal anything related to badph.example. (NonPaymentUsage)
  • A user cannot be reasonably expected to know that a simple click can enable tracking by a third party, especially that no UI from badph.example is ever shown to the user. (SilentPersistentStorage)
  • The service worker has access to 1P storage without a user’s clear intent to interact. (1PStorageAccess)
Mitigations
  • Storage access mitigation: only grant 1P storage access to payment handler service worker after running the open window algorithm, which implicitly requests Storage Access.
    • This increases the likelihood of user suspicion: user clicks on something and a window pops up. If browsers do a good job explaining what this UI is meant for (e.g. by add a “What is this?” info to the UI), and potentially offer the user an option to report surprises, then it should disincentivize the use of this attack.
  • Insert browser UI to ask the user, “Do you want to proceed to pay with ph.example?” with option to “Don’t ask me again for ph.example”

One-click tracking by web-based payment handler under Storage Access Mitigation

Same steps 1-3 as one-click tracking by a payment handler. Because of the storage access mitigation, badph.example’s service worker only has access to 3P storage at this point. Then:

  • badph.example’s service worker calls paymentrequestevent.openWindow() (C7) to request 1P access. Browser has the discretion to grant this without explicit prompting, depending on prior settings (e.g. user did not opt-out of “stay signed in” when badph.example’s payment handler was installed).
  • badph.example’s service worker looks up user’s 1P ID from IndexedDB (C9) and links it to data sent by badph.js, e.g. full URL of the current merchant1.example page user is visiting.
  • badph.example’s service worker quickly closes the payment handler window. So the user only sees a flash.
  • User visits merchant2.example and sees a quick flash because badph.example uses the same technique to gain access to 1P storage and records user’s merchant2.example full URL.
Failure points
  • badph.example’s service worker is able to close a payment handler window without user interaction. This is against the purpose of the payment handler window which is to offer user an opportunity to interact. (SilentPersistentStorage or nearly so)
Mitigation
  • Require a user interaction before closing a payment handler window.

Zero-click joining of stable IDs between merchant and payment handler

  • badph.example convinces merchant.example to host a badph.js (see Web-based payment handler as a zero-click tracker).
  • User visits merchant.example, which runs badph.js that:
    • Inserts user’s ID in merchant.example domain to method-specific data (C3)
    • Transfers it to badph.example’s service worker via request.hasEnrolledInstrument()
  • badph.example’s service worker reads badph.example ID for the user from IndexedDB (C9), and sends that and the merchant.example domain ID to badph.example server.
  • A party with access to the server logs of both merchant.example and badph.example can link the two sets of activities together.

This attack is a minor variation of Web-based payment handler as a zero-click tracker and is less severe because it requires that the attacker to also have access to the server logs of both badph.example and merchant.example. The same mitigation strategies are also effective.

Secondary Use

Zero-click collection of user activity by legitimate payment handlers

  • Legitimate digital wallet provider, wallet.example, integrates with merchant.example, which sources a wallet.js from wallet.example.
  • merchant.example enables one-click purchases via wallet.js as follows:
    • wallet.js creates a PaymentRequest with no information about the product or total payment amounts (assuming merchant.example and wallet.example both follow best practices)
    • wallet.js calls request.hasEnrolledInstrument() to determine if the user is able to complete a seamless transaction.
    • If hasEnrolledInstrument() returns true, wallet.js renders a “Buy now with wallet.example” button.
  • When the user browses to a product page on merchant.example:
    • wallet.example’s service worker receives the CanMakePaymentEvent triggered by hasEnrolledInstrument(). It learns that user is browsing merchant.example origin (though it doesn’t have access to the full URL)It extracts merchant.example origin from CanMakePaymentEvent.topOrigin and sends it to wallet.example’s backend to determine if this is a legitimate merchant that it should support.
    • User decides to not proceed with the purchase. Nevertheless, wallet.example knows that the user considered something on merchant.example.

The same attack can be performed by a native Android app based payment handler.

Failure points
  • merchant.example origin is shared with wallet.example in CanMakePaymentEvent (OpaqueDataTransfer)
  • However, this is required for origin-based merchant validation
Mitigations
  • Reduce the amount of data that is shared with the payment handler.

One-click collection of detailed user information without UI

  • A user creates an account with wallet.example and enters personal information.
  • merchant.example accepts a payment method for which wallet.example can be used.
  • User visits merchant.example and clicks on “get a quote”, which in fact creates a PaymentRequest.
  • merchant.example requests shipping and contact information.
  • merchant.example calls request.show()
  • If “skip-the-sheet” conditions are met (i.e. only one URL-based payment method is requested and a payment handler is already installed), wallet.example’s service worker receives PaymentRequestEvent
  • The service worker looks up user ID from IndexedDB and fetches user information from wallet.example’s backend, e.g. name, address, etc.
  • wallet.example’s service worker sends user information back to merchant.example via PaymentHandlerResponse (#C4) without opening a payment handler window (C8). This step can also be accomplished by the service worker sending data back via PaymentMethodChangeEvent (C4).
  • merchant.example completes the payment using user’s payment information.

Note: The steps above refer to a Web-based payment handler, but the same attack can be performed with a native Android payment handler.

Failure points
  • A user cannot be reasonably expected to know that a single click can enable wallet.example to send sensitive information to merchant.example as there may not be any visible indication that wallet.example is involved at all. (InvisibleTransaction)
Mitigation
  • Insert browser UI upon request.show() to ask “Do you want to proceed to pay with wallet.example?” with option to “Don’t ask in the future for wallet.example”. This works for both web-based and native Android app based payment handlers.
  • Require a user interaction inside of a payment handler window before returning data (e.g. via PaymentMethodChangeEvent or PaymentHandlerResponse). Reject the request otherwise. This doesn’t work for native Android app based payment handlers because the browser cannot mandate UI by a native app.

Browser Fingerprinting

Zero-click collection of of payment method / instrument support as fingerprinting bits

  • merchant.example iterates over each known payment method and method-specific instrument filter. For each configuration, creates a PaymentRequest and calls request.hasEnrolledInstrument().
  • merchant.example builds a bitvector using results from the previous step and use it as additional signals to fingerprint the user.

The effectiveness of this attack to uniquely identify a user depends on three factors:

  1. The number of bits that can be collected, which is a function of the existing payment methods and filter configurations (e.g. filter by credit card networks)
  2. The speed of collection, which depends on browser’s throttling of hasEnrolledInstrument() calls.
  3. The population size of PaymentRequest users: fewer users means a given bitvector is more uniquely identifying.

At the time of writing, the total number of configurations that exists today is C = M \* N + P, where:

  • M = # of payment methods backed by credit cards = 3 (i.e. basic-card, https://google.com/pay, https://apple.com/apple-pay)
  • N = # of credit card networks ~= 8 (See list.)
  • P = # of non-credit-card backed payment methods ~= 0

This gives a rough estimate of C = 24, i.e. merchant.example can build a 24-bit vector to fingerprint the user, as an upper bound. The actual information should be less because:

  • Some bits are correlated: e.g. basic-card and https://apple.com/apple-pay bits are mutually exclusive due to browser support. So M in practice is likely 2
  • The credit card network bits probably correlate strongly with country, so actual unique networks per country is probably N ~= 3-4 (e.g. visa, mastercard, amex, discover)

So a more realistic estimate may be C = 8 bits of actual information. C will also grow as more payment methods become available (e.g. src, other URL-based payment methods), i.e. increasing P value.

Identifying power as a function of population size and C

The table below is a model of the “identifying power” of this fingerprinting vector, measured by the number of uses per bucket, as a function of C and Payment Request API user population size (P):

Payment Request API Unique Users (P)
P = 100K P = 1M P = 100M
C = 8 (today) 400 4000 400K
C = 9 200 2000 200K
C = 10 100 1000 100K
C = 11 50 500 50K

This means that today, when Payment Request API is not yet widely used, with C = 8, hasEnrolledInstrument() can narrow users down to 400-person buckets. This may be small enough to be worrisome.

Impact of throttling on fingerprinting

Chrome throttles hasEnrolledInstrument() to 1 call every 30 minutes per merchant origin. This makes the attack not very useful for websites that a user only visits occasionally because they wouldn’t be able to build up a full bitvector without reasonable amount time.

Time required to build a full bitvector:

  • If the user stays on a website: 128 hours = 5 days
  • If the user visits a website for 1 hour/day: 128 days
  • If the user visits a website for 2 hours/day: 64 days

Adding more payment methods will make the bitvector longer, increasing its identifying power for a given population size, but increases the time required to build up the vector.

Our conclusion is that, as is, hasEnrolledInstrument() is not a very useful fingerprinting tool.

Impact of per-method quota for hasEnrolledInstrument()

The hasEnrolledInstrument() quota creates a problem for merchants: if a legitimate merchant wants to offer a “Buy now with wallet1.example” button side by side with a “Buy now with wallet2.example” button, the quota will cause one of the calls to reject and hence not display the button. A proposed solution is to change the quota to allow 1 call per payment method per 30 minutes per merchant origin. Currently page visibility is not used as part of the time quota, so a user who leaves a tab open in the background is prone to this attack.

With per method quota, the limiting factor for a merchant to collect all the bits is only N, which is ~4 in a given country (because M & P can be computed in parallel). Time required to build a full bitvector of equivalent identifying power as C=8 above:

  • If user stays on a website: 4 bits / ( 1 bit / 0.5 hours) ~= 2 hours
  • If user visits a website for 1 hour/day: 2 days
  • If user visits a website for 2 hours/day: 1 day

A possible attack:

  • merchant.example sees a new user (i.e. no merchantUserID in local storage), assigns merchantUserID and starts iterating over the bits
  • After 4 days, merchant.example looks up bitvector in their DB and found 400 users with the same bitvector. So merchantUserID is likely one of the 400 users.
  • If the user clears their local storage, merchant.example can reidentify the user to within a 400-people group after 4 days.
Failure Points
  • hasEnrolledInstrument() reveals identifying bits about a user without user gesture or any visible UI.
  • The payment handler is able to persist data points across multiple visits. (SilentPersistentStorage)
Mitigations
  • Prevent a payment handler from persisting data to storage when it has not been explicitly selected by the user.

FAQ

Who can install a payment handler without user interaction?

The origin that hosts a payment handler (e.g. ph.example) can install a service worker and register it as payment handler when a user visits ph.example as a first party. See C6.

Mitigation:

Can origin X trigger payment handler installation from origin Y without user awareness?

Yes, in the current implementation of Chrome:

Mitigation:

Note: At their 1 April 2020 meeting, WPWG participants expressed strong support for providing consistent skip-the-sheet behavior across browsers.

How can illegitimate seamlessly-installed payment handlers be filtered out?

With some difficulty. So current thought is to move away from seamlessly installed payment handlers and rely on user’s brand recognition to filter out most of illegitimate payment handlers. Longer term, we can also imagine using a safe-browsing type approach: filter out any known bad origins, and use telemetry to detect likely bad actors (e.g. high trigger frequency with zero completion rate, never showing UI, etc.)

TODO: Definition of illegitimate PH, possibly based on behavior that falls within the identified scope.

Are there payment handlers where canMakePayment is always true?

In Chrome there are currently two cases where the payment handler is not pinged and canmakepayment event returns true:

Going forward, it may be useful to allow user to configure this per payment handler (perhaps as part of the onboarding process) and make this setting more visible. See the payment handler availability clarified proposal.

Can there be a distinction made between payment handlers that can share sensitive info and those that cannot?

Possibly. The shipping delegation feature adds ability for payment handler to declare that they handle shipping addresses and/or contact information. But there are two challenges: 1) ultimately all payment information is sensitive 2) a uncooperating payment handler can hide arbitrary data using the method-specific data blob, which is opaque to the browser.

Dependencies

Target Privacy Threat Model
Target Privacy Threat Model defines the following: user ID, super-cookie, secondary use.
Tracking Preference Expression (DNT)
[[tracking-dnt]] defines the following: context, first party, tracking.
HTML
[[html]] defines the following: origin, top-level browsing context.
Mitigating Browser Fingerprinting in Web Specifications
[[fingerprinting-guidance]] defines the following: browser fingerprinting.
Payment Method Identifiers
[[payment-method-id]] defines the following: payment method identifier.
Payment Handler API
[[payment-handler]] defines the following: payment handler.
A Potential Privacy Model for the Web
A Potential Privacy Model for the Web defines the following: global static identifier.

Additional Resources