Summary
On the master CLI side, high-security actions should require biometric confirmation (Touch ID / Windows Hello / fprintd) before proceeding. This applies to actions that have irreversible or high-blast-radius consequences. On the child/agent side, all operations stay silent (no biometric prompts — agents run unattended).
Actions that should be biometric-gated
| Action |
Why it's high-security |
Current auth |
Proposed auth |
agentkeys approve <pair-code> |
Creates a new child session with credential access. A social-engineering attack could trick the user into approving a malicious daemon. |
Interactive y/N prompt |
Biometric + y/N |
agentkeys revoke <agent> |
Immediately kills an agent's session. Irreversible — the agent loses all access. Accidental revocation is disruptive. |
Session bearer only |
Biometric confirmation |
agentkeys teardown <agent> |
Deletes all credentials and revokes all sessions for an agent. Destructive and irreversible. |
Session bearer only |
Biometric confirmation |
agentkeys init --force |
Replaces the current master session. If done accidentally, the old session is orphaned. |
Session bearer only |
Biometric confirmation |
| Recovery flow (future) |
Re-associates credentials with a new daemon. High-value because it grants access to all previously-stored credentials. |
TBD |
Biometric required |
Actions that stay silent (no biometric)
| Action |
Why it's OK to stay silent |
agentkeys store |
Writing a credential — the user is actively providing the value |
agentkeys read |
Reading a credential — gated by session scope + rate limit + audit |
agentkeys run |
Injecting credentials into a child process — same as read |
agentkeys usage |
Read-only audit query |
agentkeys whoami |
Read-only session metadata |
agentkeys link |
Adding an alias — low blast radius |
| All daemon/agent MCP operations |
Must be silent for unattended agent execution |
Implementation
macOS
Use kSecAttrAccessControl = kSecAccessControlUserPresence or LocalAuthentication framework (LAContext.evaluatePolicy(.deviceOwnerAuthentication)). Touch ID prompt with fallback to device passcode.
Linux
Use fprintd via D-Bus, or polkit for password-based confirmation. Gracefully degrade to interactive password prompt if fingerprint reader is not available.
Windows
Use Windows Hello via KeyCredentialManager API. Fallback to PIN.
Cross-platform abstraction
The biometric check should be a single function: require_biometric(reason: &str) -> Result<()> that:
- Returns
Ok(()) if the user confirms
- Returns
Err if denied or unavailable
- On unsupported platforms or in
--yes / CI mode: skips with a warning
Child/agent side
No biometric. Period. Agents run unattended. The daemon authenticates via its session bearer token (TEE-verified). Biometric gating is master-CLI-only.
Priority
This is a post-MVP hardening item, not required for v0 or v0.1 initial deployment. Should ship before the master CLI is used by non-technical users in production, where social engineering attacks (fake pair codes, accidental revocations) become a real risk.
Dependencies
- Requires
LocalAuthentication framework on macOS (Rust bindings via security-framework or core-foundation)
- Requires
fprintd / polkit on Linux
- Can be implemented as a standalone crate (
agentkeys-biometric) to keep platform-specific code isolated
References
Summary
On the master CLI side, high-security actions should require biometric confirmation (Touch ID / Windows Hello / fprintd) before proceeding. This applies to actions that have irreversible or high-blast-radius consequences. On the child/agent side, all operations stay silent (no biometric prompts — agents run unattended).
Actions that should be biometric-gated
agentkeys approve <pair-code>agentkeys revoke <agent>agentkeys teardown <agent>agentkeys init --forceActions that stay silent (no biometric)
agentkeys storeagentkeys readagentkeys runagentkeys usageagentkeys whoamiagentkeys linkImplementation
macOS
Use
kSecAttrAccessControl = kSecAccessControlUserPresenceorLocalAuthenticationframework (LAContext.evaluatePolicy(.deviceOwnerAuthentication)). Touch ID prompt with fallback to device passcode.Linux
Use
fprintdvia D-Bus, orpolkitfor password-based confirmation. Gracefully degrade to interactive password prompt if fingerprint reader is not available.Windows
Use Windows Hello via
KeyCredentialManagerAPI. Fallback to PIN.Cross-platform abstraction
The biometric check should be a single function:
require_biometric(reason: &str) -> Result<()>that:Ok(())if the user confirmsErrif denied or unavailable--yes/ CI mode: skips with a warningChild/agent side
No biometric. Period. Agents run unattended. The daemon authenticates via its session bearer token (TEE-verified). Biometric gating is master-CLI-only.
Priority
This is a post-MVP hardening item, not required for v0 or v0.1 initial deployment. Should ship before the master CLI is used by non-technical users in production, where social engineering attacks (fake pair codes, accidental revocations) become a real risk.
Dependencies
LocalAuthenticationframework on macOS (Rust bindings viasecurity-frameworkorcore-foundation)fprintd/polkiton Linuxagentkeys-biometric) to keep platform-specific code isolatedReferences
wiki/blockchain-tee-architecture.mdSection 6 — rule Stage 8: Production hardening — daemon memory hygiene + CLI defensive features #3 (master CLI stores bearer, keychain recommended)wiki/key-security.mdSection 2 — auth token storage, keychain as defaultdocs/spec/1-step-analysis.mdSection 3.2 — session tiers (master = biometric-gated, agent = silent)