The Tap That Android Can Mistake for a Tap

A tap on a phone usually feels like a complete event. A user brings the device near a card, sticker, setup tag, or another object, and something happens: a payment screen opens, a device begins pairing, a network is configured, or an accessory is recognized. The physical gesture seems to carry its own explanation. The phone was close to the object; therefore the phone received information from that object, and the application is responding to a deliberate act of proximity.

This series examines a narrower and more consequential question: what does Android actually prove when an NFC application handler opens? The subject is Android’s Near Field Communication (NFC) Reader/Writer path, in which the phone reads an external tag and sends the discovery to an app. The central issue is not whether NFC radio communication can be relayed or whether every payment wallet is insecure. It is whether an app can tell that its NFC handler was opened because Android just observed a physical tag, rather than because another app caused the same handler to start with an NFC-shaped request.

That distinction matters because many “tap-to-X” experiences quietly use entry into an app as a proxy for a fact about the physical world. If the app reaches its NFC entry point, it may act as though the user has just tapped the expected object. But an entry point is a software boundary. It can be routed, exposed, and started according to rules that are not the same as proof of where a request came from.

The physical meaning of a tap is stronger than the software event

Android NFC supports different interaction models, and they should not be blended together. In Reader/Writer mode, the phone actively reads from or writes to a nearby tag. A tag may be a sticker, card, key fob, or a component embedded in another device. The phone is the reader, and the tag supplies information. In card-emulation designs, by contrast, the phone behaves like a card to an external reader. Wallet systems and secure-element arrangements commonly follow that other direction of interaction.

The distinction is important because “NFC payment” does not describe one security architecture. A card-emulation payment path may rely on payment protocols, a secure element, or other controls that are not present in the application-level Reader/Writer path considered here. The question in this series is specifically about the phone reading a tag and handing the result to an ordinary Android application. That is the path used by many tap-to-pay, pairing, provisioning, and configuration features built into third-party apps.

For a user, however, the difference is rarely visible. A phone moves near an object, the screen changes, and the user quite reasonably connects the two. The tap appears to establish at least two facts: the phone was physically near the intended source, and the user meant to initiate the action. An application can then use the tap as a low-friction trust signal. It may skip a second selection screen, accept data associated with the tag, or begin a workflow designed around the assumption that a nearby object supplied the request.

The Android security question is whether the application receives a trustworthy statement of those facts or merely a request that has the right shape. The first is provenance: evidence about origin. The second is routing: information used to decide which component should receive a request. A URI, a MIME type, an action name, or a tag-related extra can be useful for routing and parsing. None of those labels, by themselves, explains why the request exists.

Three boundaries separate a real discovery from an app action

A useful way to understand the issue is to separate three boundaries that are easy to collapse in everyday use.

The first is the hardware boundary. A tag comes within range, the NFC controller detects it, and Android’s NFC stack receives a discovery event through the device’s hardware and driver. This is the part that most closely matches the user’s mental model of a tap. It involves a physical object and a near-field interaction.

The second is the system-routing boundary. Android turns the discovery into an application-delivery request and looks for a component whose manifest says it can handle that kind of NFC event. The system may consider an NDEF record, a URI, a MIME type, a tag technology, or a general tag-discovered fallback. It then uses Android’s activity-start machinery to select and launch a handler.

The third is the application-workflow boundary. The target Activity receives an Intent and associated data, parses what it needs, and decides what to do next. It might show a screen, change configuration, contact a server, start pairing, or initiate a transaction. The Activity can observe what the request contains. The harder question is whether it can verify how the request entered the system.

Android’s own API description makes this boundary concrete. When a tag is discovered, Android creates a Tag object representing the tag’s state at that moment and passes it through the NfcAdapter.EXTRA_TAG extra. The object can expose an identifier and the technologies available on the tag. The documentation also notes that identifiers are not uniform: many tags have a stable UID, some produce a random identifier on each discovery, and some have no identifier at all. Those details are useful for an application that needs to interpret a tag, but they are not a general-purpose statement that the receiving Activity has independently authenticated the event’s origin.

The same is true of the dispatch order. Android first gives priority to a foreground activity that has registered for foreground dispatch. If that does not decide the recipient, NDEF content can be matched, with a URI or MIME type placed into the Intent in the relevant cases. Technology matching and a general tag-discovered fallback follow. This is a practical routing strategy: it lets a transient interaction reach the most appropriate Activity without forcing the user to choose an app while the phone is still near the tag. It also means that the reader-facing result is organized around a sequence of actions, data fields, and extras that the target app can inspect.

Those fields explain what Android intends the app to handle. They do not, on their own, answer the separate question of who initiated the delivery. A URI can be a correct description of tag content and still be supplied to a handler through a software-created request. A tag-related extra can be meaningful data and still lack an application-verifiable link to a fresh hardware observation. The distinction is subtle because normal operation supplies both content and origin together. Security-sensitive code must not assume that the convenience of their normal alignment is itself a guarantee.

These boundaries normally line up so neatly that they feel like one event. A physical tag produces a discovery; the system routes it; the app responds. That alignment creates a powerful but potentially unsafe shortcut in application design: “If I am in the NFC handler, a real tap must have happened.” The research examined in this series argues that, in Android’s Reader/Writer dispatch path, that conclusion is not guaranteed for every externally reachable handler.

The issue is not that Android fails to read tags. The issue is that the final handoff to an app can look like an ordinary cross-application Activity launch. If the receiving app sees only an action, data, and extras, it may have no application-facing signal that uniquely binds those fields to a fresh hardware discovery. The request can describe an NFC event without proving that NFC hardware caused it.

flowchart LR T["Physical NFC tag nearby"] --> H["NFC controller and Android driver detect tag"] H --> D["Android NFC stack creates discovery Intent"] D --> R["Intent resolver routes by action, data, or technology"] R --> A["Application NFC handler"] A --> W["Tap-to-X workflow"] S["Software-created NFC-shaped request"] -.-> R P{{"Routing answers where it goes; provenance answers why it arrived"}} R -.-> P P -.-> A

The diagram’s dashed path is the important warning. It does not mean that every app can be started, that every payload will be accepted, or that every downstream action will succeed. It means that the software route and the physical route can converge at the same application boundary when the handler is exposed to ordinary cross-app starts and the request satisfies its routing conditions.

Why the distinction has practical stakes

The consequences depend on what an app does after entry. A handler that merely displays information may produce an unexpected screen. A handler that assumes a tap authorizes a state change can do more. The same platform-level condition could therefore appear as a payment problem in one app, a network-provisioning problem in another, a device-pairing problem in a third, or a persistent configuration problem elsewhere. Those outcomes cannot be inferred from the existence of an NFC filter alone; they depend on application logic, payload requirements, user confirmation, and server-side checks.

That is why the right subject is not “NFC is fake” or “all tap-to-pay is broken.” The subject is Android’s post-discovery tag dispatch and its relationship to app handlers that treat entry as proximity evidence. The key theme is narrower: routing is not provenance. Keeping that theme attached to Android’s actual components makes it possible to ask useful questions without turning a platform finding into a universal claim.

The scope also matters in the other direction. The central claim concerns launching an NFC handler without a physical tag at trigger time. It does not automatically mean that a local app can complete every workflow, silently change every device, or bypass every later authorization step. A handler may be non-exported, protected by a caller permission, blocked by runtime checks, or dependent on data that is not available. A visible user confirmation may still interrupt the chain. A payment service may apply additional risk controls. These are not reasons to dismiss the origin problem; they are reasons to describe it accurately.

The research is consequently useful at two levels. At the platform level, it asks whether Android’s delivery boundary gives an app a reliable way to distinguish system-originated NFC discovery from a software-constructed request. At the application level, it asks what developers have allowed that entry point to mean. A weak boundary becomes significant when a downstream workflow treats it as a security decision rather than as a convenient route into the app.

The next step is to replace the everyday phrase “NFC happened” with a concrete account of what Android creates and delivers. Android’s official documentation describes a Tag object, a set of dispatch stages, and an Intent sent to an Activity. Understanding those pieces is necessary before judging whether the final Activity launch carries the meaning users and developers may attach to it. Only then can the central question be answered precisely: when an NFC handler opens, is that evidence of a physical tap—or only evidence that Android found a route to the handler?

References