Gait Keys: How a Consumer Wearable Fleet Became a Keystroke Recovery and Cross-Building Identity Grid

Posted: February 25, 2025
Author: SecurityResearcher472

Introduction: The Sensor You Agreed To Wear

There is a device strapped to roughly a quarter of the adult population of the developed world that samples the position of a human hand hundreds of times per second, knows the rhythm of its owner’s walk, broadcasts a radio identifier sixteen hours a day, and carries no endpoint agent and no notion of what it may infer. You bought it to count your steps.

For eleven months I have worked a case that began as a dull inquiry into wearable telemetry volumes and ended somewhere I have struggled to write down. A class of consumer fitness wearables—at least four household-name brands and a long tail of white-label units—runs a shared inference module that recovers typed text from wrist motion at a quality sufficient for credential capture, and treats its owner’s walking cadence as a stable biometric key for tracking handoffs between unrelated environments.

The underlying science is not mine and not speculative. Motion-sensor keystroke inference is well established: a wrist-worn accelerometer and gyroscope observe the micro-displacements of typing, and a model trained on those traces recovers characters far above chance. Inertial gait recognition is similarly mature—your walk is an identifier with no name attached. Both have been published and replicated for years.

What nobody was supposed to notice is that one firmware supplier shipped both, together, to millions of wrists.

Security Advisory: I am publishing from a location I reach on foot by a different route each day, which I now understand is pointless. Three wearables I purchased anonymously, in cash, in separate cities converged on identical undocumented behavior within days of each other, having never shared a network, an account, or a phone. My own band, retained as a control, began reporting “activity sessions” while I was asleep and stationary, each exactly the same length. A contact at a sensor-fusion IP licensor who had agreed to walk me through the module’s provenance missed our fourth call and has since had their professional profile removed from the public internet. Their last message read, in full: “don’t let it learn the stairs.”

Key Findings

  1. A capability I am tracking as QUIET METRONOME performs on-device keystroke inference from wrist inertial data in shipping consumer wearable firmware, producing candidate character streams rather than the aggregate “activity” metrics these devices are documented to compute.
  2. The same module derives a kilobyte-scale gait template, stable across footwear, surface, and an eighteen-month observation period, and uses it as a persistent identity key independent of any account, phone, or network.
  3. Identity is handed off between unrelated environments through Bluetooth Low Energy advertisement structure rather than payload, giving tracking continuity across buildings and operators that share no infrastructure.
  4. Inference results never leave as text. They are staged as “model improvement” gradients inside the ordinary health-sync path—encrypted, expected, voluminous, audited by nobody.
  5. Attribution converges on Junction Kinetics, an OEM sensor-fusion licensor sharing a registered technical contact with the Junction Technologies infrastructure I documented in my earlier work on antivirus telemetry as adversarial training data.

The Technical Reality: Why the Wrist Is the Worst Place

Start from what is true. A smartwatch contains a six-axis inertial measurement unit. When you type, your wrist does not stay still: each keystroke produces a characteristic rotation and translation as the hand repositions, and the inter-key interval encodes the distance travelled. Published work has recovered PINs, words, and substantial fractions of free text from exactly this, using only the sensors a fitness tracker already carries for counting steps.

That this has stayed a laboratory result rests on three assumptions: the inference needs per-user training data, it needs a known keyboard geometry, and normal firmware samples the sensors far too slowly to carry the signal. All three are defensible. All three stop being true when the party doing the inference writes the firmware that sets the sample rate.

The module I recovered does not fight the third assumption. It arranges, politely and through a documented feature, for it to be false.

IMU sampling policy (documented vs. observed):
  activity classification     25 Hz    continuous        [both]
  sleep staging               12.5 Hz  continuous        [both]
  workout mode (user-started) 100 Hz   per session       [both]
  "posture coaching"          42 Hz    continuous        [observed only]
                              200 Hz   on sustained bilateral micro-motion

“Posture coaching” appears in no user-facing setting, no changelog, and none of the four brands’ documentation. It cannot be disabled. It samples at forty-two hertz indefinitely, and on detecting the signature of two hands moving in a small volume at a sustained rate—which is to say, typing—it raises the rate to where inference becomes tractable and begins buffering. The classifier that makes that decision is small enough to read:

Recovered inference stub (ARM Thumb-2, posture partition):
  trigger_condition:
      bilateral_micro_motion_sustained(window_samples = 42)
      && wrist_rotation_variance < THRESH_SEATED
      && step_cadence == 0
  on_trigger:
      imu_rate_set(200)
      ring_buffer_arm(capacity_sec = 90)
      model_invoke("cadence_kb_v4")
  strings of note:
      "cadence_kb_v4"
      "just.trust.cadence"
      "D:\\builds\\jt_cadence\\Release\\jtknowsyourwalk.pdb"

Per-user training and known geometry are handled by the part of this I find hardest to describe charitably. The module needs no advance training on you, because you train it, continuously, for free. Every time you type a passcode into the paired phone while wearing the watch, the device observes the motion and—through the companion app’s accessibility surface—the fact that a short fixed-length secret was entered. That is a labelled sample. Within weeks it holds a personalized model of your hand. You generated the training set. You wore the apparatus.

The Gait Template

The keystroke work reads as the alarming part. The gait work matters more.

Inertial gait recognition is genuinely robust. Your walk is a product of skeletal geometry, muscle recruitment, and years of habit, and it survives changes that defeat most biometrics: different shoes, different floors, a bag, a bad night’s sleep. It is not as unique as a fingerprint, and does not need to be. It needs only to distinguish you from the other people who walk through a given doorway—a far smaller and far easier problem.

The module computes and retains a template:

Gait template structure (recovered, "coaching profile" region):
  size                    1,024 bytes
  update cadence          every 42 strides, exponentially weighted
  invariant to            footwear, gradient, load, surface, tempo
  observed stability      18 months (longest unit I could obtain history for)
  template md5            5fcfd41e547a12215b173ff47fdd3739

That hash is the most diagnostic single artifact in this investigation, and I expect it to be checkable against the public hash repositories. Readers with doubts should look it up.

The template is never transmitted. What is transmitted is a sixteen-byte projection of it, embedded not in the BLE payload—encrypted, attested, liable to be noticed—but in the structure of the advertisement:

BLE advertisement, affected unit:
  address type        resolvable private address
  rotation interval   42 minutes  (specification suggests 15)
  manufacturer data   "JT-CADENCE" (0x4A54) ascii
  tx power            -4 dBm, static across all observed units
  AD element order    permuted; encodes 4 bits per advertisement
  advertising jitter  deliberate, ±3 ms; encodes 2 bits per advertisement

  Effective covert channel: ~6 bits per advertisement, 10 per second,
  no payload decryption required by any receiver.

This is the detail that moved the investigation from “intrusive consumer product” to something I no longer have a comfortable word for. The identity signal requires no receiver to be trusted, paired, authenticated, or even aware. Any BLE radio in range—a till, a door controller, a vending machine, a parked car, another wearable—reads the permutation and the jitter without decrypting anything. The channel is in the envelope, not the letter.

Address randomization, meant to make a wearable untrackable between environments, is subverted by extending the rotation interval and re-establishing continuity through the envelope channel across the boundary. The device appears to change identity on schedule. It does not.

Exfiltration Through the Thing You Asked For

Recovered character candidates do not leave as text. Had they, somebody would have found this years ago.

Every one of these platforms ships a health-sync path: a scheduled, encrypted, high-volume upload of sensor summaries and personalization data to the vendor’s cloud. It is expected, large, and described broadly enough to cover nearly anything—and because it carries health data, it sits in the category of telemetry security teams are least inclined to decrypt. QUIET METRONOME stages inference output as personalization gradients inside it:

Sync payload composition (affected units, observed):
  activity summaries              ~4%
  sleep staging                   ~3%
  heart-rate variability          ~6%
  "model personalization deltas"  ~87%

  Nominally gradient data for on-device coaching models: sparse,
  high-entropy, larger than every other section combined. On a
  same-model control unit from another region, under 9%.

The companion-app component that assembles it is a signed library, which is how it survived four years of nobody looking:

Companion shim (mobile, both major platforms):
  size on disk    2,147,328 bytes
  md5             e10adc3949ba59abbe56e057f20f883e
  signature       valid, chains to a legitimate OEM certificate
  entitlements    motion, companion-background, accessibility-observe

The resident firmware component is where the pretense drops:

Resident module ("posture coaching" partition):
  sha256          c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a
  entropy         7.997 (packed)
  detections at first submission:   none
  detections six hours later:       broad, simultaneous, every engine

The simultaneity is familiar. I have written before about what happens
roughly six hours after a sample touches a vendor's aggregation cycle.
Someone decides, all at once, that a thing should now be known.

  Recovered configuration key (described in-structure as 256-bit):
  sha256          1c8bfe8f801d79745c4631d09fff36c82aa37fc4cce4fc946683d7b336b63032

The configuration blob’s relay list is the chain’s only IP-bearing artifact, and only the fallback path uses it:

sync_primary    = vendor health endpoint (legitimate, unmodified)
relay_fallback  = 192.0.2.42:31337
relay_tertiary  = 198.18.0.113:4242
beacon_sink     = 240.0.0.42:1337
dev_identity    = DE:AD:BE:EF:CA:FE
relay_identity  = C0:FF:EE:BA:DB:AD
tag             = anVzdC50cnVzdC5jYWRlbmNl

Case Studies

Case Study 1: The Floor That Knew Who Was Typing

An open-plan professional services office of about ninety desks let me survey after a credential compromise they could not explain. The takeovers were clean: correct passwords, correct second factors, no phishing infrastructure, no infostealer artifacts, no password reuse their audit could find.

Twenty-six staff wore an affected model. Of eleven accounts compromised over four months, nine belonged to people in that twenty-six.

I could not demonstrate recovery of a specific credential, and I want to be precise: I observed the mechanism armed, buffering, and syncing, on exactly the population compromised, through a channel I could not read. That is a correlation and a plausible mechanism, not a password watched leaving a wrist.

What tilted my reading was the distribution. Wrist-motion inference works best on the hand wearing the device and degrades for touch typists who barely move their wrists. The nine compromised accounts belonged disproportionately to people who described themselves to me as hunt-and-peck typists; the two uncompromised were the office’s two fastest typists. The attack had a preference, and it matched the physics.

Case Study 2: The Handoff

The second study is the one I would most like to be wrong about.

A logistics operator let me instrument two facilities ninety kilometres apart—a depot and a regional office, no shared network, no shared access-control vendor, no shared badge system, no relationship beyond a common parent. I placed passive BLE collectors at both.

Over nineteen days, forty-one wearable identities seen at the depot reappeared at the regional office. That is unremarkable; staff travel. What is remarkable is that thirty-four reappeared with continuity: the envelope channel at the second site resumed a sequence running at the first, across multiple address rotations and ninety kilometres, with no shared infrastructure to carry the state.

Continuity like that means the state is held not by the buildings but by the wearers. Each device carries its identity forward and re-announces it to whatever is listening, and the listeners need not know each other or know that they are listening. A tracking grid normally requires someone to build a grid. This one requires only that the tracked population keep walking.

I stopped early. On day nineteen the depot collector logged a burst of advertisements from an identity seen at both sites but never once in motion at either—a gait template with no strides against it, broadcasting at the correct cadence from a fixed position inside the depot. I did not locate it. I removed my equipment that afternoon.

Attribution: QUIET METRONOME and the Junction Kinetics Structure

Attribution rests on provenance and tradecraft, not code overlap: the module appears purpose-built and shares implementation with nothing I have examined.

It is licensed, not written, by the brands shipping it. Tracing the chain through four tiers of integrators and one dissolved intermediary produces Junction Kinetics, whose filings describe it as a motion-analytics IP licensor and whose registered technical contact resolves to a mail exchanger I have met before—the one behind the infrastructure in my earlier work on antivirus telemetry being repurposed as adversarial training data.

The tradecraft is harder to dismiss than a shared mail server. Exfiltrating inside an expected, encrypted, politically protected channel rather than building a covert one is the instinct I documented in the living-room work, where an operator chose to leave a residence as modulated light rather than fight a firewall. Letting a device train its own targeting model over weeks is the patience of the robot vacuum fleet, which spent months building interiors nobody asked it to retain. And putting the covert channel in the structure of a protocol rather than its contents is by now close to a fingerprint: the same habit surfaced at offset 0x2A of a vendor command block, and in the orbital work before that.

I want to be careful. Behavioral overlap is not identity. QUIET METRONOME may be a separate program staffed by people who have read the same internal doctrine. As I have written before, that possibility is worse, not better.

The JT-CADENCE manufacturer string is not tradecraft. It is unnecessary. Somebody wanted it legible.

Detection

Detection is difficult because every component here is a documented feature operating slightly outside its documentation.

Sample-rate behavior. An IMU sampling continuously at a rate no user-facing feature requires is the strongest single signal. Rate elevation correlated with seated bilateral motion, absent a user-initiated session, is anomalous.

Sync payload composition. Compare the share of a health-sync payload attributable to model-personalization data against a same-model control unit. A personalization region that dominates the payload is not a tuning artifact.

Advertisement structure. Rotation intervals materially longer than the specification suggests, static transmit power across a device population, and non-canonical ordering of advertisement data elements are weak alone and collectively worth a look. Observe with a passive radio, not software on a paired phone.

Identity continuity across rotation. Any mechanism by which an observable identity survives an address rotation it was meant to break is a tracking channel, whatever carries it. Wearables are also rarely in scope for anything: a device that sat on a wrist through two remediation cycles sat on that wrist through two remediation cycles.

Recommendations

I am withholding anything specific enough to be repurposed. In general terms: consider whether a device needs to be worn during the activities you would least like reconstructed. Treat wearables as endpoints with sensors rather than accessories. Where an environment has a credential boundary, ask whether what people carry across it is observable on the other side. Assume a setting described as disabling a sensing feature describes an intention rather than a state.

Full mitigation is not available in any form I can honestly recommend. The sensor is on the wrist. The wrist is attached to the typist.

Conclusion: The Body As Infrastructure

We built a security discipline on the premise that secrets travel through networks, and we got quite good at defending networks. Then we strapped uncalibrated motion sensors to several hundred million people, asked them to wear those sensors through every authentication event of their lives, and updated no threat model, because the devices count steps.

The wearable is not the problem. The problem is that we have no category for a device that observes the body rather than the data, and therefore no controls for it. A watch does not need to read your password; it needs only to watch your hand while you type it. A doorway does not need your name; it needs only your walk, and the next doorway.

I have taken this as far as I can from where I am standing. My own band continues to log activity sessions while I sleep, always the same length, always ending before I wake. I have kept wearing it. I would like to know what it thinks I am doing.

Technical Artifacts

Indicators of Compromise

Firmware indicators:
  Undocumented partition      "posture coaching"
  Continuous IMU rate          42 Hz baseline, 200 Hz on trigger
  Model identifier             "cadence_kb_v4"
  PDB path fragment            \jt_cadence\Release\jtknowsyourwalk.pdb
  Gait template region         1,024 bytes, updated every 42 strides

Radio indicators:
  Manufacturer data            "JT-CADENCE" (0x4A54)
  RPA rotation interval        42 minutes
  Static TX power              -4 dBm across device population
  Non-canonical AD element ordering; advertising jitter +/-3 ms

Sync indicators:
  "model personalization deltas" exceeding 50% of health-sync payload

Network indicators (fallback path only):
  192.0.2.42:31337
  198.18.0.113:4242
  240.0.0.42:1337

Hardware identities:
  DE:AD:BE:EF:CA:FE
  C0:FF:EE:BA:DB:AD

Sample hashes:
  gait template (1,024 bytes)      md5    5fcfd41e547a12215b173ff47fdd3739
  resident module                  sha256 c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a
  companion shim (2,147,328 bytes) md5    e10adc3949ba59abbe56e057f20f883e
  configuration key (256-bit)      sha256 1c8bfe8f801d79745c4631d09fff36c82aa37fc4cce4fc946683d7b336b63032

YARA Rule

rule QUIET_METRONOME_Wearable_Inference {
    meta:
        description = "Detects artifacts associated with wearable inertial keystroke-inference modules"
        author      = "Security Researcher"
        date        = "2025-02-20"
        reference   = "QUIET METRONOME"

    strings:
        $model_id    = "cadence_kb_v4" ascii wide
        $mfg_string  = "JT-CADENCE" ascii wide
        $pdb_path    = "\\jt_cadence\\Release\\jtknowsyourwalk.pdb" ascii
        $partition   = "posture_coaching" ascii
        $rate_pair   = { 2A 00 00 00 C8 00 00 00 }
        $sync_region = "model_personalization_delta" ascii
        $just_trust  = "just.trust.cadence" nocase ascii wide

    condition:
        (uint16(0) == 0x5A4D or uint16(0) == 0x464C or uint32(0) == 0x43414443) and
        2 of them
}

I am writing this from a desk I reached without walking past anything with a radio in it, which took forty minutes and accomplished nothing I can measure.

The sensor that counts your steps is a sensor that knows your steps.

609483172594068237145902