Skip to content
Second Brain Chronicles
Go back

Every Bash Command Triggered Touch ID

Every Bash Command Triggered Touch ID

Claude Code runs dozens of bash commands per session. Each one was triggering a Touch ID prompt on my MacBook.

The Chain

Here’s the sequence, per command:

  1. Claude Code calls the Bash tool
  2. Bash tool spawns a new shell process
  3. New shell sources ~/.zshenv (runs on every shell, interactive or not)
  4. .zshenv contains op read calls to load API keys from a password manager
  5. Password manager requires biometric authentication
  6. Touch ID prompt appears
  7. I authenticate (or the command times out)

One bash command, one Touch ID prompt. Claude Code makes dozens of bash calls in a typical session. That’s dozens of fingerprint scans.

Why .zshenv

The API keys were for a CLI tool and a VPN management service. Both needed tokens available in every shell — not just interactive terminals but also scripts, cron jobs, and tool-spawned subshells. .zshenv is the only zsh config file that runs in all contexts, so that’s where the op read calls went.

This is correct shell configuration practice. It’s also incompatible with any tool that spawns shells frequently without user interaction.

The Fix

Replaced the op read calls with static .env files:

# Before (.zshenv):
export CLI_TOKEN=$(op read "op://vault/item/token")
export VPN_KEY=$(op read "op://vault/item/key")

# After (.zshenv):
source ~/.config/cli-tool/.env
source ~/.config/vpn-service/.env

The .env files contain the actual token values, written once from the password manager. No biometric prompt on read — the secrets are on disk in known locations with standard file permissions.

ApproachSecurityUsability with Claude Code
op read per shellKeys never on diskTouch ID on every bash call
Static .env filesKeys on disk, file permissionsZero prompts, instant shell startup

The tradeoff is real. op read keeps secrets out of the filesystem entirely — they exist only in memory for the duration of the shell. Static .env files put them on disk. For local development keys that are also stored in the password manager anyway, the disk exposure is acceptable. For production credentials, it wouldn’t be.

Why this specific to Claude Code

A normal terminal session sources .zshenv once on startup. One Touch ID prompt, then you work for hours. Claude Code’s Bash tool creates a new process per invocation — it doesn’t maintain a persistent shell. Every git status, every npm test, every ls is a fresh shell spawn, a fresh .zshenv source, a fresh op read, a fresh Touch ID prompt.

The tool’s architecture (isolated shells per command) is a reasonable safety design. But it interacts badly with shell config that assumes long-lived sessions.

The Damage Report

MetricValue
Touch ID prompts per sessionDozens (one per bash call)
Root causeop read in .zshenv + per-command shell spawning
Fix time~10 minutes
Files modified2 (.zshenv, .zshrc)
Static env files created2
Touch ID prompts after fix0

Share this post on:

Previous Post
Deploy Succeeded. Locked Out Ten Minutes Later.
Next Post
Published a Tool. Its README Fingerprinted Me.