Skip to content

fix: harden peer pinning, same-name discovery, and full-set switch guard#53

Merged
MegaManSec merged 3 commits into
mainfrom
fix/peer-pinning-discovery-switch-guard
Jun 9, 2026
Merged

fix: harden peer pinning, same-name discovery, and full-set switch guard#53
MegaManSec merged 3 commits into
mainfrom
fix/peer-pinning-discovery-switch-guard

Conversation

@MegaManSec

Copy link
Copy Markdown
Owner

Summary

A round of correctness/security hardening from a code review of the discovery, pairing, and switch paths, plus a small UX guard. Three concern-grouped commits.

Changes

Security — peer identity pinning (NetworkDevice.update(with:))
Once a fingerprint is pinned (TOFU), only an advertisement carrying that same fingerprint updates routing. Previously a mismatch was caught only when the incoming advertisement had a different fingerprint — one with no fp fell through and overwrote host/port/isActive, so a LAN attacker advertising the peer's Bonjour name with no fingerprint could silently re-point routing at their machine. A missing fingerprint is now ignored entirely.

Discovery — same-named Macs (NetworkDeviceStore / ServiceBrowser)

  • Identify "self" by interface address (getifaddrs) instead of Host.current().localizedName. When two Macs share a device name, mDNS renames one service, so the old name check made the renamed Mac hide its real peer (same name) and list itself.
  • Prefer an IPv4 address when resolving a peer; a link-local IPv6 (fe80::…%enX) often won't round-trip through NWEndpoint.Host.

UX — block "send all" while a peripheral is switching (DropdownContentView / AppDelegate / BluetoothPeripheralStore)
The full-set switch (clicking a Mac row) greys out while any peripheral is .connecting/.releasing, with an explanatory tooltip, and performSwitch guards the click-race — preventing a re-entrant connect/release on a peripheral already mid pair/handoff.

Testing

  • xcodebuild … -configuration Debug build succeeds; sources formatted with swift format.
  • No test target exists in this project, so verification is the build plus manual review. The duplicate-name and IPv6 paths are hard to exercise without two specific machines.

Note

The fingerprint is advertised in cleartext in the Bonjour TXT record, so a LAN attacker who reads it can replay the matching value to re-point routing — but that only yields a DoS (the reachability ping fails and the row greys out); it can't steal peripherals, since the command channel still requires completing the PSK handshake. Fully hardening the advertisement would be a larger change.

Once a fingerprint is pinned (TOFU), update(with:) only treated a
*different* incoming fingerprint as a mismatch. An advertisement carrying
no fingerprint at all fell through and overwrote host/port/isActive, so a
LAN attacker advertising the peer's Bonjour name with no `fp` TXT record
could silently re-point routing at a machine they control.

Now a pinned device only accepts a routing update from an advertisement
carrying the same fingerprint; a missing one is ignored entirely.
- Identify "self" by interface address (getifaddrs), not by
  Host.current().localizedName. When two Macs share a device name mDNS
  renames one service, so the name-based check made the renamed Mac hide
  its real peer (same name) and list itself instead.

- Prefer an IPv4 address when resolving a peer. A link-local IPv6 address
  (fe80::...%enX) often won't round-trip through NWEndpoint.Host, so taking
  whichever address resolved first could yield an unusable host.
A full-set switch fired while a per-peripheral pair/handoff was in flight
would issue a re-entrant connect/release on a peripheral that's already
transitioning. The dropdown Mac row now greys out while any peripheral is
.connecting/.releasing (with an explanatory tooltip), and performSwitch
guards against the brief click-race before the row re-renders.
@MegaManSec MegaManSec merged commit f40a205 into main Jun 9, 2026
2 checks passed
@MegaManSec MegaManSec deleted the fix/peer-pinning-discovery-switch-guard branch June 9, 2026 23:11
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 2.16.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant