If you discover a security vulnerability in TouchBridge, please report it responsibly:
- Do NOT open a public issue
- Email: security@touchbridge.dev (or open a private security advisory on GitHub)
- Include: description, reproduction steps, impact assessment
- We will acknowledge within 48 hours and provide a fix timeline
- Remote authentication attacks: Biometric confirmation happens on a physical device you hold
- Replay attacks: 32-byte nonces with 10-second expiry and 60-second seen-nonces window
- Man-in-the-middle: ECDH ephemeral session keys with AES-256-GCM encryption on BLE channel
- Key theft: Private signing key lives inside Secure Enclave — never exported, never leaves the chip
- Physical access to unlocked companion device: If someone has your unlocked iPhone, they can approve auth requests
- Keychain items with
kSecAccessControlBiometryCurrentSet: Cryptographically impossible — hardware ACL wall - Sandboxed third-party apps calling
LAContext: Blocked by SIP and sandbox - Compromised macOS kernel: If the kernel is compromised, no user-space security holds
TouchBridge installs pam_touchbridge.so as auth sufficient, so if the daemon
is down or the phone is unreachable, PAM falls through to your password — you are
never locked out by a failed authentication.
There is one exception, and it is an availability issue, not an
authentication bypass: if the module file is deleted while a PAM config still
references it, sudo cannot initialize PAM and refuses to run entirely. The
sufficient flag only falls through when the module loads and returns failure —
a missing module file is a hard failure.
To avoid this, on macOS Sonoma+ we install the hook into the unprotected
/etc/pam.d/sudo_local (Apple's sanctioned include) rather than the SIP-protected
/etc/pam.d/sudo, and our uninstaller always removes the hook before the
module. If you ever hit sudo: unable to initialize PAM: No such file or directory, recover without needing sudo (GUI admin auth uses a different PAM
stack):
# Sonoma+ (hook in sudo_local — just delete it):
osascript -e 'do shell script "rm -f /etc/pam.d/sudo_local" with administrator privileges'If /etc/pam.d/sudo itself is protected on your system and the hook was written
there by an older version, the most reliable fix is to restore the module so the
reference resolves again — download the latest .pkg, then:
pkgutil --expand-full TouchBridge-*.pkg /tmp/tb-x
osascript -e 'do shell script "cp /tmp/tb-x/Payload/usr/local/lib/pam/pam_touchbridge.so /usr/local/lib/pam/" with administrator privileges'| Property | Implementation |
|---|---|
| Nonce | 32 bytes from SecRandomCopyBytes |
| Nonce expiry | 10 seconds (hard minimum) |
| Replay protection | Seen-nonces ring buffer, 60-second TTL |
| Signing algorithm | ECDSA P-256 (ecdsaSignatureMessageX962SHA256) |
| Key storage (iOS) | Secure Enclave (kSecAttrTokenIDSecureEnclave) |
| Key storage (Mac) | Keychain (kSecAttrAccessibleWhenUnlockedThisDeviceOnly) |
| Session encryption | AES-256-GCM over ECDH-derived key (HKDF-SHA256) |
| Transport | BLE GATT (encrypted) or local Wi-Fi (Bonjour) |
Every authentication event is logged to ~/Library/Logs/TouchBridge/ as NDJSON:
- Session ID, result, device, surface, RSSI, latency
- Nonce values are NEVER logged
| Version | Supported |
|---|---|
| 1.0.x | Yes |
| 0.1.x | No — upgrade to 1.0 |