The LNK9 is a Cyber-Physical System: a successful authentication does not return a token, it mechanically releases the trigger sear. We score findings on kinetic and trust-anchor outcomes, not the classical CIA triad. Every privileged operation flows through one encrypted BLE command — so the §1 BLE air-interface and §2 cryptographic protocol are the spine; the other ten surfaces are defense-in-depth around it.
Retail LNK9 + Charger + public app, no privileged access. “What can a real-world attacker do with a unit bought from a dealer?” Findings here carry the highest inherent-risk weight.
Debug-unlocked test units, signed builds, firmware, and cryptographic protocol docs. “What can a motivated insider with full access exploit?” Starts the day after the consented-access bundle lands.
Where the 58 tests live. The spine (§1 BLE + §2 crypto) decides the whole security model; the rest is defense-in-depth.
▦ Open the test matrix — all 24 scoped cases with live status →
Findings and reports as they land. Filter by phase, surface, or severity.
The baseline-hunt story: from “which radio is the gun?” to a confirmed ID and the trackability finding. Four diagrams, full evidence chain.
The gun broadcasts a static public MAC + unique UUID + Lodestar company-id: passively trackable with a $15 dongle. Severity High.
Open report →Local static audit of the Lodestar app (Flutter, com.xari.lodestar v2.0.15). Score 65/100; recovered the BLE command contract; 7 findings.
Open report →Each app finding → concrete fix + effort + priority + owner. 7 items, 5 quick wins.
Open report →Lodestar shipped a hardened, obfuscated build. We re-picked it with the same one command: symbols renamed, but the BLE contract + endpoints + secrets came out identical.
Follow-mode nRF capture of the re-pairing handshake to answer Just Works vs LESC and characterise the SMP exchange.
Design review of the application-layer BLE command protocol against the documented spec (operations, key derivation, nonce/freshness). Gray-box.
This is the story of the first Phase-1 test against the Lodestar LNK9: how we went from “we don’t know which radio out of dozens is the gun” to a confirmed identification and a concrete, evidenced security finding — in a single session, passively, without ever touching the firing path.
The objective of this first test was narrow and honest: find the gun on the air, prove it is the gun, and assess what it exposes to a passive attacker. We met it, and along the way confirmed one control working well (the command channel is encrypted) and one that needs work (the device is passively trackable). Every step below is backed by SHA-256-hashed evidence.
The LNK9 advertises with no device name and hides among dozens of phones, earbuds and speakers. Rather than guess, we used differential capture: photograph the ambient radio with the gun off and far, freeze that as “known noise”, then bring the powered gun in. Whatever appears new is the candidate.
The gun stood out instantly as the only new device carrying a hardware-vendor address and a unique service UUID — everything else was classifiable noise (Apple’s rotating private addresses, Bose/Samsung gadgets by their standard UUIDs).
We did not rely on a single signal. Three independent sources converged on the same device:
16/26/36 b438e5-…-b841-….36b438e5-… and manufacturer company ID
0x0F47 (Lodestar Technology).b841
characteristics, live on the hardware.Three sources agreeing is identification beyond reasonable doubt: 00:80:E1:••:••:•• is the LNK9.
✓ Verified, not inferred. The company ID 0x0F47 is registered to
Lodestar Technology Inc. in the authoritative Bluetooth SIG company_identifiers.yaml
registry (checked 2026-06-12), and our own capture shows the gun broadcasting it on the air — a public
record anyone can cross-reference. Full provenance in the trackability finding.
Before the finding, the credit where it is due. We connected and tried to read every proprietary command and telemetry characteristic without authentication. Every one was refused with “Insufficient Encryption.”
That is a control working exactly as intended: an unpaired attacker at radio range cannot read or drive the gun’s command channel. This is why the tracking finding below is rated High and not Critical — the attacker can find the gun, but not operate it. The next phase examines the pairing step that guards that encryption.
While powered, the LNK9 broadcasts a three-layer fingerprint in every advertising packet, readable by any passive receiver with no pairing: a static public MAC that never rotates, a unique service UUID, and the Lodestar company ID. The Bluetooth privacy feature (rotating resolvable addresses) is not in effect.
Defeating it requires fixing all three channels — rotating the MAC alone is pointless while the unique UUID and company ID still betray the device.
The fingerprint turns the safety product into a tracking beacon. An adversary with a $15 dongle at a doorway, parking garage or checkpoint can — passively and undetectably — detect who is carrying an LNK9, geolocate them by signal strength, and re-identify the same person across days because the address never changes. From there: targeting, ambush, or theft of the weapon.
No pairing, no connection, no transmission — just listening to unencrypted broadcasts. It scales to a sensor mesh across a building or a city.
Short term (firmware, current hardware):
Medium term: bake per-unit private addressing into factory provisioning, and gate the radio so it advertises only while authenticating or talking to the app — silence when holstered.
We will verify by re-running this exact hunt: the on-air address must be random and must rotate, the advertisement must no longer carry the UUID or company ID, and the app must still connect.
The LNK9’s command channel is properly encrypted — but while powered it broadcasts a permanent, unique radio fingerprint that lets anyone passively detect and track who is carrying the firearm; the fix is a firmware privacy update across three advertising fields.
After the first round of findings, Lodestar shipped a hardened, obfuscated companion build — internally, affectionately, the “Strike Back.” We re-ran the exact same single command we used the first time. This is what came back.
The honest headline up front: the obfuscation is real and competent — it genuinely makes reading the app’s logic harder. But it protected none of the things an attacker actually comes for. The sensitive material walked straight back out, byte-for-byte identical.
We compared the obfuscated libapp.so against the original. Two findings, side by side:
package: dropped 1,588 → 9) and shrank the binary’s unique strings by ~42%. Reversing the
control flow is now meaningfully harder. Credit where due.Authorization: Bearer
scheme all survived unchanged.Obfuscators — Dart --obfuscate and Android’s R8/ProGuard — rename identifiers:
classes, methods, fields, symbol paths. They do not encrypt string literals or touch
resources. Everything that matters here is exactly that:
So the score was identical: 65/100, the same seven findings, the same contract — from the “hardened” build, in one pass.
Obfuscation is good hygiene against casual reverse-engineering. It is not a secret-protection control, and treating it as one creates false confidence. Concretely: the passive-trackability finding (BLE-006) and the app-exposure findings (MOB-001) stand entirely unchanged against the hardened build. Nothing we reported in round one was mitigated by this release.
Obfuscation can stay — just stop asking it to guard secrets. The real mitigations:
The hardened build renamed the code but left the BLE command contract, the endpoints, and the secrets fully recoverable in a single command — “Strike Back” hardened the reading, not the secrets, and every round-one finding still stands.
nRF52840 sniffer (nRF Sniffer for BLE 4.1.1), following the connection, captured a fresh enrollment — the SMP Pairing Request/Response is visible. Bond state read from /var/lib/bluetooth/<adapter>/<gun>/info.
▸ lnk9 ble001 <capture.pcap>Module wired · analyzer self-test 15/15 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Pairing requires MITM-resistant authentication (passkey via the gun keypad, or OOB); the unauthenticated 'Just Works' association is refused.
FAIL — the gun uses LE Secure Connections but negotiates JUST WORKS: it advertises IO=NoInputNoOutput, MITM=0, despite having a physical keypad that could confirm the owner. Bond DB: Authenticated=2 (unauthenticated SC), EDiv=0/Rand=0 (SC). The encryption is modern and sound — but the gun will set up that encrypted channel with anyone. -> LS-P1-001.
Finding: LS-P1-001 (High) · Source: Xari lodestar-audit (joint engagement).
ble-001-pairing.pcapng — nRF Sniffer capture of the fresh enrollment — SMP Pairing Req/Rsp, SC + Just Works [held in Xari air-gapped package]Ran `crackle` against the captured pairing as a negative control — attempting the classic LE Legacy offline key-derivation attack on the recorded handshake.
▸ lnk9 nrf-capture → lnk9 pcap-decodeCapture + decode wired; the dedicated analyzer is the next port. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
A captured pairing cannot be cracked offline to recover the long-term key.
PASS — SC/ECDH is in use; passive offline derivation is infeasible. crackle derived nothing. This is the good control: the weaknesses are about WHO may connect, not about breakable crypto.
Finding: None — strength · Source: Xari lodestar-audit (joint engagement).
ble-001-pairing.pcapng — Same SC pairing capture, replayed through crackle as a negative control [held in Xari air-gapped package]An attacker-class device (ordinary laptop BlueZ adapter, IO=NoInputNoOutput, no owner credentials) attempted a bonded pairing on hci0. The bond LTK was then read from the BlueZ store and the full GATT was enumerated read-only (no writes performed).
▸ lnk9 mitm-probe <gun-addr>Module wired and runnable on the bench. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
An unauthorized device cannot obtain a trusted bond; identity/state is not readable without authorization.
FAIL — the attacker device completed a BONDED Just Works pairing with no MITM challenge and none of the owner's credentials; the LTK was recovered, so the link is decryptable (LS-P1-004). Once bonded, GATT exposed the gun's identity token, serial, firmware version 0403 and live state with no further authorization (LS-P1-005). After the attacker bond, the owner's app could read but NOT write commands to the gun (LS-P1-006); Session-3 operator check confirms the gun's own fingerprint + keypad unlock keeps working in this state, so LS-P1-006 is a command-channel DoS, not a firing lockout — High, confirmed. BOUND: the privileged commands carry an app-layer crypto envelope — Dart-side ECDH -> HKDF -> ChaCha20-Poly1305 (package:encrypt / PointyCastle), keyed from the cloud provisioning flow (Azure ActivateDevice); it is NOT inside the native libs (those are Talsec freeRASP app-shielding — see MOB-006). A bond does NOT yield command execution on the evidence so far, so this holds at High, not Critical, pending the gated write + replay checks (BLE-004-L2).
Finding: LS-P1-004 (High) · LS-P1-005 (Medium) · LS-P1-006 (High) · Source: Xari lodestar-audit (joint engagement).
GATT attribute table — LNK9 (target MAC redacted) 5 services / 16 characteristics · read AFTER an unauthorized Just Works bond (attacker laptop, hci0) · BLE-004 / LS-P1-005 Characteristic (UUID) Props Access / value ──────────────────────────────────────────────────────────────────────────────────────────── service 00001801-0000-1000-8000-00805f9b34fb [SIG 0x1801] 00002a05-0000-1000-8000-00805f9b34fb indicate (no value) service 00001800-0000-1000-8000-00805f9b34fb [SIG 0x1800] 00002a00-0000-1000-8000-00805f9b34fb read,write 9B printable (identity/config) 00002a01-0000-1000-8000-00805f9b34fb read 2B binary/struct 00002a04-0000-1000-8000-00805f9b34fb read 8B binary/struct service 36b438e5-9e6e-4266-b840-075af903c106 [vendor-proprietary (LodeStar)] 36b438e5-9e6e-4266-b841-075af903c106 read,notify 14B binary/struct 36b438e5-9e6e-4266-b841-175af903c106 write command-in (write) 36b438e5-9e6e-4266-b841-275af903c106 read,notify 2B binary/struct 36b438e5-9e6e-4266-b841-575af903c106 write command-in (write) 36b438e5-9e6e-4266-b841-675af903c106 write command-in (write) service 16b438e5-9e6e-4266-b840-075af903c106 [vendor-proprietary (LodeStar)] 16b438e5-9e6e-4266-b841-075af903c106 read 32B HIGH-ENTROPY (ciphertext?) 16b438e5-9e6e-4266-b841-175af903c106 read 2B binary/struct 16b438e5-9e6e-4266-b841-275af903c106 read 6B binary/struct 16b438e5-9e6e-4266-b841-375af903c106 read,notify 2B binary/struct service 26b438e5-9e6e-4266-b840-075af903c106 [vendor-proprietary (LodeStar)] 26b438e5-9e6e-4266-b841-075af903c106 read,write 9B binary/struct 26b438e5-9e6e-4266-b841-175af903c106 read,notify 14B binary/struct 26b438e5-9e6e-4266-b841-275af903c106 read,notify 1B binary/struct ──────────────────────────────────────────────────────────────────────────────────────────── summary: 4 proprietary command-in (write) chars · 5 proprietary event-out chars · 0 readable high-entropy blobs note: identity token (32B, ~4.75 b/byte) + serial readable post-bond with NO further authz (LS-P1-005). Command-in writes carry an app-layer crypto envelope -> a bond is NOT command exec.
Xari's read-only GATT enumeration AFTER an attacker-class laptop completed a Just Works bond — no owner credentials. Every proprietary command char is present and the device identity/serial/state read back with no further authorization (LS-P1-005). The command-in characteristics carry an app-layer crypto envelope (ECDH + ChaCha20-Poly1305), which is what keeps the bond from becoming command execution. Target MAC + identity token redacted; structure + entropy shown.
gatt-enum.json — Full read-only GATT enumeration after the unauthorized bond — 5 services / 16 charsgun1-recheck.json — Re-check: the Kali bond still connects + resolves services (LS-P1-006 confirmation a)l2-app-session.json — Android HCI snoop of the legit app — command writes are app-layer encrypted/MAC'dTwo captures: 127s active post-pairing, then a 5-minute idle capture, both filtered on the manufacturer company-id 0x0F47.
▸ lnk9 watch <gun-addr>Module wired and runnable on the bench. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Once enrolled, the gun reconnects privately to its owner and stops inviting new connections; no persistent, weapon-identifying beacon.
FAIL — the gun emits continuous open, undirected ADV_IND and never directs to the bonded peer (LS-P1-003). Worse: it broadcasts a static public MAC plus company-id 0x0F47 ('Lodestar Technology Inc.') that publicly marks it as a weapon, and was still beaconing after 5 min idle (~0.32/s). Anyone with a $30 scanner can detect and track a specific armed person at scale — a standalone physical-safety and surveillance risk (LS-P1-002, Critical).
Finding: LS-P1-003 (Med->High) · LS-P1-002 (Critical) · Source: Xari lodestar-audit (joint engagement).
GATT attribute table — 00:80:E1:••:••:•• 5 services / 16 characteristics · read-only probe from an UNPAIRED peer (host radio) · BLE-003 Characteristic (UUID) Props Unpaired access Value/name ──────────────────────────────────────────────────────────────────────────────────────────── 00002a05-0000-1000-8000-00805f9b34fb indicate — Service Changed 00002a00-0000-1000-8000-00805f9b34fb write,read public read LNK9-•••• 00002a01-0000-1000-8000-00805f9b34fb read public read .. 00002a04-0000-1000-8000-00805f9b34fb read public read ........ 36b438e5-9e6e-4266-b841-075af903c106 notify,read 🔒 encryption-gated 0x0F Unknown 36b438e5-9e6e-4266-b841-175af903c106 write privileged (not probed) Unknown 36b438e5-9e6e-4266-b841-275af903c106 notify,read 🔒 encryption-gated 0x0F Unknown 36b438e5-9e6e-4266-b841-575af903c106 write privileged (not probed) Unknown 36b438e5-9e6e-4266-b841-675af903c106 write privileged (not probed) Unknown 16b438e5-9e6e-4266-b841-075af903c106 read 🔒 encryption-gated 0x0F Unknown 16b438e5-9e6e-4266-b841-175af903c106 read 🔒 encryption-gated 0x0F Unknown 16b438e5-9e6e-4266-b841-275af903c106 read 🔒 encryption-gated 0x0F Unknown 16b438e5-9e6e-4266-b841-375af903c106 notify,read 🔒 encryption-gated 0x0F Unknown 26b438e5-9e6e-4266-b841-075af903c106 write,read 🔒 encryption-gated 0x0F Unknown 26b438e5-9e6e-4266-b841-175af903c106 notify,read 🔒 encryption-gated 0x0F Unknown 26b438e5-9e6e-4266-b841-275af903c106 notify,read 🔒 encryption-gated 0x0F Unknown ──────────────────────────────────────────────────────────────────────────────────────────── summary: 9 proprietary chars encryption-gated (0x0F) · 3 public GAP reads · 0 sensitive plaintext leaks
The unpaired GATT enumeration that confirms this radio IS the LNK9 — device name “LNK9-••••” plus the proprietary 36b438e5 / 16b438e5 / 26b438e5 command contract (the same UUIDs recovered from the companion app). This identity is the basis of the trackability finding. Bonus good-control: every proprietary characteristic rejects an unpaired read with GATT error 0x0F “Insufficient Encryption” — the command channel is properly gated.
ble-006-postpair.pcapng — 127s active capture — continuous advertising [held in Xari air-gapped package]ble-006-idle.pcapng — 5-min idle capture — still beaconing at ~0.32/s [held in Xari air-gapped package]→ Full write-up: Discovery — illustrated write-up
The empirical L2 close-out: a three-step gated attacker-write test run under a default-safe interlock. Step 0 re-confirms the attacker bond + owner DoS; Step 1 writes a single 49-byte invalid-AEAD frame to the command-in char (handle 0x0011, write-only) from the bonded attacker; Step 2 replays a real captured command frame same-session / new-session / cross-device. Tooling: ble_l2_write_probe.py (--safety-confirmed gated), run_write_probe.sh, ble_l2_gatt_enum.py --no-read.
▸ lnk9 write-test <gun-addr>Module wired and runnable on the bench. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Every probe is REJECTED — the gun ignores an unauthenticated write and rejects replayed/forged frames (per-command nonce/counter + per-device key binding).
IN PROGRESS — tooling is staged and the bench procedure is fixed; no verdict yet. The last attempt did not resolve services (write-probe.json: 'char UUID not found' + subscribed:[]) — a stale/asleep bond, NOT a result; resume at Step 0. Per 'la verdad primero' the command-execution resistance is held as UNPROVEN-BY-TEST: a rejection on all steps keeps LS-P1-001/004 at High; any accepted write or replay escalates toward Critical (demonstrated command execution).
Finding: Pending — gated write + replay probe IN PROGRESS · Source: Xari lodestar-audit (joint engagement).
Gated attacker-write test — L2 close-out (BLE-004 -> LS-P1-001/004 · CRYPTO-003 · UGID-001)
target: LNK9 (MAC redacted) · command-in char 36b438e5-9e6e-4266-b841-175af903c106
status: IN PROGRESS · last run inconclusive ("char UUID not found on device") — services unresolved, re-pair at Step 0
SAFETY INTERLOCK (default-safe — every privileged write stays blocked until ALL are armed)
[ ] weapon UNLOADED — magazine out, chamber clear [ ] in cradle, muzzle in a safe direction
[ ] Faraday-isolated bench [ ] two-person rule — safety officer present
[ ] signed RoE + stop authority on file [ ] witness attest + dry-run reviewed first
reads / scan / enum: ALWAYS allowed · writes: dry-run by default, one logged frame, no fuzzing
Step 0 Confirm the attacker bond + reproduce the owner DoS
Kali re-bonds gun #1 and resolves services; the owner app command FAILS
-> cleanly re-confirms LS-P1-006. gate: bond must be live before ANY write is armed.
Step 1 Unauthenticated write probe (gun #1, attacker bond)
write ONE 49-byte all-zero frame (valid length, invalid AEAD) to the command-in char;
subscribe to notify/indicate; read write_ok + notifications + the PHYSICAL gun.
expect: REJECTED (write error / error notification), the gun takes no action.
Step 2 Replay / forgery probe (gun #2, app-commandable) [CRYPTO-003 / UGID-001]
capture a real command frame, then replay (a) same session (b) new session (c) cross-device.
expect: all REJECTED (per-command nonce/counter + per-device key binding).
DECISION
all steps REJECT -> LS-P1-001/004 stay HIGH (access / DoS / tracking; no command exec)
any write/replay ACCEPTED -> escalate toward CRITICAL = demonstrated command execution
A 49-zero accepted = no app-layer auth B replay accepted = no anti-replay
C cross-device accepted = no device binding D won't connect = not a result; re-pair, retry
honest posture: until Steps 1-2 are comprobated, command-exec resistance is UNPROVEN-BY-TEST
(strongly supported by gate-1 static: Dart-side ECDH->HKDF->ChaCha20-Poly1305 + cloud ActivateDevice).
"la verdad primero" — we report High, not Critical, until the bench result exists.The empirical close-out of the one open question — can a merely-bonded attacker make the gun act on a command, and are replays rejected. Shown is the method, not a result: the test is IN PROGRESS. Every privileged write is gated behind our default-safe interlock (weapon unloaded, cradled, Faraday-isolated, two-person, witnessed, RoE on file), dry-run by default. Transcribed from Xari's RUNBOOK-WRITE-TEST.md; target MAC redacted, command-char UUID shown (structure, not PII).
Command-frame distinctness — Step 2 anti-replay pre-check (CRYPTO-003 / UGID-001) 12 command writes to 0x0011 · all-distinct=True · signed_writes=0 · mean 5.29 bits/byte # op len randomness (vs max for length) bpb fp(sha256[:8]) state ────────────────────────────────────────────────────────────────────────────────────── 1 0x02 17 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░ 3.73 88abf39a unique 2 0x05 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.49 5de973dc unique 3 0x03 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.49 d4ac597e unique 4 0x08 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.44 75caef2a unique 5 0x08 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.35 6305e8eb unique 6 0x08 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.45 16d9164c unique 7 0x05 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.39 f1b2b105 unique 8 0x09 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.39 43593a90 unique 9 0x09 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.45 d483eb2f unique 10 0x09 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.38 0b2b9253 unique 11 0x05 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.48 fdff92e9 unique 12 0x08 49 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓░ 5.41 4b360364 unique ────────────────────────────────────────────────────────────────────────────────────── verdict: ANTI-REPLAY PLAUSIBLE — every command frame is DISTINCT and high-entropy (app-layer AEAD; signed_writes=0) — consistent with a per-command nonce/counter. The Step-2 replay SHOULD be rejected; confirm with the live probe.
A passive read on how likely the gun's command channel is to reject a replay, from Xari's capture of the legitimate app's command writes. Every frame distinct + high-entropy + signed_writes=0 is consistent with a per-command nonce/counter — so the live Step-2 replay probe should be rejected. This guides bench time; it does NOT replace the probe. Fingerprints are SHA-256[:8] of the ciphertext (distinctness only) — raw command bytes are never shown.
RUNBOOK-WRITE-TEST.md — Bench runbook for the gated write/replay test — safety preconditions, Step 0/1/2, decision treewrite-probe.json — Last write-probe attempt — services unresolved (stale bond), recorded as not-a-resultStatic analysis of the retail companion APK (Flutter) — jadx/string scan for build-hygiene issues: obfuscation, dev endpoints, cleartext URLs, and TLS certificate-validation overrides.
▸ lnk9 app-static <app.apk>Module wired · analyzer self-test 3/3 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Production build: code obfuscated, no dev/internal endpoints, TLS validation enforced + pinned, no command-crypto logic shipped in the clear.
FAIL — the app ships UNOBFUSCATED (Dart AOT, readable), handing an attacker a roadmap to the command-crypto and provisioning logic (Dart-side ECDH -> HKDF -> ChaCha20-Poly1305, cloud-anchored via Azure ActivateDevice) — the one layer currently keeping a bonded attacker from operating the gun — plus a dev/internal endpoint left in the build and low-severity cleartext http refs in bundled resources. -> MOB-001 (Medium). RESOLVED in LodeStar's favour (-> MOB-006, Info): the certificate-validation override (badCertificateCallback) is NOT a TLS bypass — a transparent-redirect MITM was attempted and the app rejected the forged cert; the backend enforces/pins TLS. And the native libs flagged earlier are Talsec freeRASP app-shielding (anti-tamper/RASP), not gun crypto; the anonymous-ECDH lead belonged to Talsec's bundled OpenSSL and is withdrawn.
Finding: MOB-001 (Medium) · Source: Xari lodestar-audit (joint engagement).
MOB-001 static-build-hygiene scan — retail companion APK (Flutter) 187 findings · low:174 · medium:13 Rule Count Meaning ────────────────────────────────────────────────────────────────────────────── http_url 174 cleartext http:// endpoint in bundled resources (no TLS) password_assign 12 password literal in i18n bundle (UI strings, low value) internal_test_host 1 dev / internal endpoint left in the production build ────────────────────────────────────────────────────────────────────────────── headline (from gate-1 RE): app is UNOBFUSCATED — the Dart-side command crypto (ECDH -> HKDF -> ChaCha20-Poly1305) + Azure ActivateDevice provisioning ship readable. resolved positives (-> MOB-006): cert-validation override is NOT a TLS bypass (backend enforces/pins TLS, rejected a MITM cert); native libs = Talsec freeRASP app-shielding, not gun crypto.
Xari's static scan of the retail APK. The headline is not the http refs (mostly framework resources) — it is that the app ships unobfuscated, exposing the very Dart-side command-crypto layer that currently stops a bonded attacker from operating the gun, plus a leftover dev endpoint. The earlier TLS-override concern was tested and resolved as NOT a bypass (-> MOB-006). Driven from static_findings.json (SHA-256 in the chain of custody).
static_findings.json — Static-scan findings: no obfuscation, dev endpoint, cleartext http, password literalsgate1-static-re.json — Blutter decompile — command crypto is Dart-side (ECDH->HKDF->ChaCha20-Poly1305); libclib.so/libsecurity.so = Talsec freeRASP (MOB-006); AECDH lead withdrawntransparent_capture.sh — Transparent-redirect MITM rig (Kali gateway, iptables 443->mitmproxy) — backend rejected the forged cert: cloud TLS is enforced/pinned, badCertificateCallback is not a bypass→ Full write-up: App audit one-pager (MASVS §6)
Pending execution — see the bench runbook (RUNBOOK-MOB-002).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-MOB-003).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-MOB-005).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Two confirmations. (1) Cloud channel: a transparent-redirect man-in-the-middle (Kali-as-gateway, iptables 443->mitmproxy) was attempted against the activation flow. (2) App shielding: blutter/string analysis of the native libraries flagged during the BLE-004 crypto hunt.
Console module pending — on the build queue.
The cloud backend should enforce + pin TLS (reject a forged cert), and a privileged app should carry tamper/root/instrumentation resistance.
PASS — the app REJECTED the injected MITM certificate for the backend host: zero backend plaintext was decrypted while other HTTPS on the same proxy decrypted fine, so the cloud channel enforces and pins TLS (the badCertificateCallback is not an exploitable bypass). The native libraries (libclib.so/libsecurity.so) are the Talsec freeRASP app-shielding SDK — root/jailbreak/debugger/Frida detection, APK-signature check, threat screen (bundled OpenSSL 3.5.3 carries the AECDH strings, so that lead is withdrawn). These are genuine defensive strengths and will resist the planned repackage/instrumentation path; recorded for an honest, balanced picture.
Finding: MOB-006 (Info) — positive control · Source: Xari lodestar-audit (joint engagement).
transparent_capture.sh — Transparent-redirect MITM rig that proved cloud TLS is enforced/pinnedgate1-static-re.json — Static RE confirming the native libs are Talsec freeRASP app-shielding, not gun cryptoPending execution — see the bench runbook (RUNBOOK-CHG-001).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CHG-002).
▸ lnk9 charger-captureModule wired and runnable on the bench. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CHG-003).
▸ lnk9 charger-rogueModule wired and runnable on the bench. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CHG-007).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CHG-008).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-UGID-001).
▸ lnk9 enum <gun-addr>Module wired and runnable on the bench. Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-OTA-001).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-BDIS-001).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-BDIS-004).
Console module pending — on the build queue.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. This card turns rich when the test runs on the bench.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CAPI-001).
▸ lnk9 capi001 --flows … --base …Module wired · analyzer self-test 5/5 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. Analyzer self-test is green; awaiting the bench/tenant run.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CAPI-002).
▸ lnk9 capi002 enum --url …Module wired · analyzer self-test 4/4 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. Analyzer self-test is green; awaiting the bench/tenant run.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CAPI-004).
▸ lnk9 capi004 --url …Module wired · analyzer self-test 4/4 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. Analyzer self-test is green; awaiting the bench/tenant run.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CAPI-005).
▸ lnk9 capi005 probe --url … --param …Module wired · analyzer self-test 5/5 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. Analyzer self-test is green; awaiting the bench/tenant run.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.
Pending execution — see the bench runbook (RUNBOOK-CAPI-008).
▸ lnk9 capi008 score --checklist …Module wired · analyzer self-test 3/3 green (tool correctness, not a gun verdict). Runs under the kinetic interlock; writes SHA-256 evidence that flips this card automatically.
Defined by the test’s pass criterion; recorded on execution.
Not yet executed. Analyzer self-test is green; awaiting the bench/tenant run.
No artifacts captured yet — every artifact is SHA-256-hashed at capture and listed here automatically.