Yandex: A Long-Lived, Configuration-Driven Bridge
The Yandex case in Bridges to Self answers a concrete question: how can a native analytics component keep a web-to-app identity bridge available without making the bridge look like a simple, permanent listener? The paper’s evidence describes a lifecycle in which Yandex Metrica on the web and AppMetrica inside native Android apps coordinate through localhost. Following that lifecycle lets the reader see what state persists, what triggers each transition, and why delayed execution and remote configuration complicate detection.
The lifecycle begins inside the app
The first state is not a browser request. A Yandex-owned Android app containing the AppMetrica SDK starts, contacts Yandex-controlled infrastructure, and receives runtime configuration. That configuration can specify which local ports the app should use. The paper reports HTTP and HTTPS requests on ports including 29009, 29010, 30102, and 30103. It also reports a first_delay_seconds setting that deferred the creation of local listeners for roughly three days.
That delay changes the meaning of an app test. A short test that opens the app, waits for ordinary user interactions, and then closes it may observe no local server at all. The app can appear quiet while it is in a waiting state. Only after the configured delay does it transition to a background state in which the SDK’s local HTTP(S) service is listening. The paper found that this behavior was associated with the AppMetrica SDK embedded in several Yandex applications, rather than being limited to one app’s visible product feature.
The state has an owner at every point. Yandex’s configuration service decides which runtime settings the app receives. The embedded SDK applies those settings and controls the listener. The browser script controls when the web-side request is made. The Yandex back end controls the parameters that authorize and interpret the exchange. This division is easy to miss if the behavior is described as “the app sends a request.” In fact, the app is waiting for a remotely influenced trigger, the web script supplies another trigger, and the back end can use the resulting response. The bridge is a distributed lifecycle even though one of its interfaces is confined to the device.
Remote configuration also separates the listener’s behavior from the app version installed on the phone. If the operator can change a port or other parameter from its server, a browser or security tool that watches only a fixed list of ports has a brittle point of reference. The app does not need a new store update for every configuration change. This does not make every dynamic configuration malicious; it does mean that detection must observe state and network control, not only the code shipped in the original package.
Once the listener is active, the native app has two kinds of state. It has the local server state—whether a process is listening and where—and it has native identity state, such as an Android Advertising ID, an AppMetrica-specific UUID, and other device identifiers available through the app. The browser has separate state: cookies and parameters associated with the page or tracker. The bridge becomes consequential when a message causes these state stores to be related.
A useful way to test the lifecycle is to ask what happens if one transition is missing. Without the startup configuration, the app may not know which listener settings to apply. Without the delay expiring, a short observation sees no endpoint. Without the web script’s request, the listener has no matching page-side value. Without the app’s response, the web script cannot obtain the native-side information. Without the final back-end handoff, the local exchange may not become a durable record. The evidence is strongest when it connects these transitions rather than treating any one of them as the whole behavior.
How the web value met the native value
When a person visits a site carrying the Yandex Metrica script, the script first communicates with Yandex back-end infrastructure to obtain a set of parameters. The paper describes these values as obfuscated and says they included a validation token and other server-generated values. The script then sends the relevant parameters to the native service on localhost over HTTP or HTTPS.
The app validates the token and constructs a response that contains the web-supplied values together with native identifiers. The exact data structure is less important than the ownership change: a value that originated in the browser is now being handled by a native process that can associate it with an app-side identity. The response is encrypted using a hybrid AES–RSA scheme and Base64-encoded before being returned to the browser script. The script then relays the result to Yandex-controlled back-end services, where the web activity and native identity can be matched.
The matching point is therefore not necessarily the local server itself. The local service performs the crucial handoff, but the operator’s back end can create the durable association after it receives the returned data. This matters for privacy analysis. A local listener may not store a readable history of every page, and the browser may discard its temporary request data. The server-side record can still preserve the relationship between a web-side value and a native-side value. State has moved from a transient page interaction into an operator-controlled system.
The state diagram shows why this was not a one-time request. The listener could remain available in the background and return to its listening state after each exchange. The web script could be loaded on many different sites, while the native app retained its own identity state between visits. The cloud upload connected the short local transaction to a longer-lived record. A local request was the mediator, not the final privacy outcome.
The paper also reports that Yandex used a hostname such as yandexmetrica.com that resolved to the loopback address and bundled a certificate for that domain in the app’s private storage. This made the local HTTPS service resemble a normal remote HTTPS endpoint to the browser. The important point is not the certificate’s implementation detail; it is the way familiar browser indicators can be made less informative when a domain name and a local destination are combined. A request that looks like ordinary encrypted web traffic may still terminate inside the phone.
This arrangement also complicates simple origin reasoning. The page remains on the site that embedded the Metrica script; it does not gain the right to read another website’s cookie. The local destination is a different kind of endpoint, however: it is a process on the same device. The web-side value can leave the browser through that endpoint even when ordinary cross-site storage access remains blocked. The fact that the request uses a domain name that resolves locally further separates the visible name from the actual process that receives the data.
Encryption does not change the authorization question. It can protect the response from casual inspection while it travels between the local service and the script. It does not answer whether the script should be allowed to transfer a web identifier into a native identity system, nor does it prevent the operator that controls both ends from using the combined result. Confidentiality and permission are different properties. Nor does Base64 encoding make a message private; it represents data in a transport-friendly form, while the cryptographic protection is supplied by the encryption scheme described in the paper.
Why timing and configuration weakened ordinary observation
The three-day delay is one example of a broader observability problem. Many automated app-analysis pipelines run a package for minutes or hours, exercise common screens, collect network events, and then produce a report. A behavior that activates after days may be absent from that report even though it is present in the installed app’s operating logic. A dynamic listener can also be background-only, so a test that watches the app only while its visible activity is in the foreground can miss it.
The web side creates a reciprocal problem. A crawl can record a request to a loopback address, but the request may be difficult to attribute to a native app unless the crawler runs alongside the relevant app and observes the responding process. Static analysis can reveal strings or network components, but obfuscation, renamed classes, convoluted control flow, and dynamically retrieved parameters can hide the relationship. The paper therefore combined static inspection with runtime instrumentation and network observation. The implementation was established through the end-to-end relationship, not through one indicator in isolation.
The monitoring challenge is also about timing across components. A crawler may load the right page before the app has transitioned to its listening state. An app test may run the right package without loading a site that embeds the matching script. A network trace may see encrypted traffic without immediately showing which values were assembled before encryption. The researchers’ joint design addressed these mismatches by observing browser requests, app processes and sockets, and the values handled by the app at runtime. That is why the evidence can speak about a coordinated flow rather than merely about the coexistence of a tracker and an open port.
The historical timeline adds persistence to the case. The paper’s HTTP Archive analysis first saw Yandex’s HTTP localhost method in February 2017. HTTPS support appeared in May 2018. The two methods were used at the same time for more than eight years, until June 3, 2025, when the observed practice was discontinued after public disclosure. A long period of activity matters because it shows that the gap was not merely a short-lived experiment discovered immediately after deployment. It also shows why a point-in-time scan can understate the lifecycle: the implementation could evolve while retaining the same underlying purpose.
The paper reports additional risks from the early unencrypted HTTP path. Another app listening on the same local ports could inspect the Origin header in a request and infer parts of a person’s browsing history. This is not the same as the intended Yandex matching flow. In the primary flow, Yandex’s own app uses the local exchange to combine web and native identifiers. In the secondary risk, the shared local interface gives an unrelated local app an opportunity to observe traffic. Both problems come from the same design fact: more than one process can be positioned to receive information that a browser page sends locally.
The difference between those risks affects what a defense must verify. A control aimed at stopping identity matching must examine whether a web value reaches a native process and whether the result is forwarded to an operator. A control aimed at preventing local eavesdropping must also consider whether the transport exposes page or origin information to other listeners. Encrypting one response may help with one exposure while leaving the possibility of unauthorized cross-context identity creation untouched.
That distinction helps avoid a common analytical error. The presence of a local listener does not prove that every listener is tracking, and the existence of an encrypted response does not prove that the exchange is harmless. To understand the system, we need to ask four questions: who starts the listener, what wakes it up, what crosses the interface, and where the result is stored or sent afterward. Yandex’s case supplies evidence for each stage, while the paper’s limitations warn against extending the behavior to every Yandex app or every version outside the tested corpus.
The mechanism’s real significance
Yandex’s implementation combined several choices that each weakened a different form of observation. Remote configuration made the listener’s settings changeable. Delayed activation placed the transition outside common test windows. Obfuscation made the browser and app logic harder to interpret statically. HTTPS to a loopback-resolving domain made the destination less obvious from the request’s appearance. The use of background app state meant that testing only the foreground experience could miss the receiving process.
None of those choices alone creates the identity bridge. The bridge requires the complete chain: a web script must be present, the native app must be installed and listening, the message must carry a usable web-side value, the app must add a native-side value, and the operator must receive or retain the association. The choices matter because they help the chain survive the gaps between web crawling, app analysis, browser UI, and user expectations.
The case also clarifies why the native app’s identity is more durable than the browser event that initiated the exchange. A page load is transient. A browser cookie may be cleared or partitioned. The app, however, can hold an account relationship or device identifier and can send the combined information to a back end. Once the server has received that relationship, a later browser reset is no longer guaranteed to restore the separation that existed before the local exchange.
The paper’s attribution remains bounded. It reports the behavior in analyzed Yandex applications and connects the listener to the AppMetrica SDK, using dynamic and static evidence. That supports a strong claim about the tested deployment, but not an assumption that every Yandex product, every AppMetrica integration, or every release behaved in the same way. The discontinuation date also describes the observed practice; it is not evidence that the underlying design space became impossible.
This is the first complete example of the series’ boundary problem. The web context and the native context did not need to share files, memory, or an ordinary app-to-app permission. They shared an exposed local interface and an operator capable of interpreting both sides of the message. The interface remained local; the identity relationship became durable and remote. The stable analytical question is therefore larger than any one port or SDK: which transitions let a transient web value become native state, and which system is responsible for mediating them?