[Bug][macOS] Killing a blocked `security` Keychain read after 5s crashes securityd and causes an endless login-keychain prompt loop
Los mantenedores suelen responder en 1 día
@lidge-jun ya está trabajando en esto.
Desde el 8/11/2026.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 55/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- macos, typescript
- Área
- authentication
Línea de trabajo
Start with src/oauth/local-token-detect.ts and src/claude/auth-detect.ts, then trace how their security child processes handle the 5 s timeout. Reproduce with a locked login keychain and check whether the reads trigger repeated prompts or securityd crashes. Done when these reads avoid the reported crash loop and retain their existing fallback behavior.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Client or integration
Claude Code
Area
Authentication and account pool
Summary
On macOS 27.0, the Claude Code Keychain reads in src/oauth/local-token-detect.ts (readClaudeKeychain, readClaudeKeychainAsync) and the probe in src/claude/auth-detect.ts (keychainProbe) run /usr/bin/security with a 5 s timeout. When the login keychain is locked, security blocks on the SecurityAgent unlock prompt, and the timeout kills it while the prompt is still open.
Killing a security process while its SecurityAgent query is pending hits a race in Apple's securityd: it logs Probable bug: error destroying Mutex: 16 / UNIX error exception: 16 and aborts (SIGABRT, std::terminate). When securityd restarts, the login keychain is locked again. The next request reads the keychain, gets killed after 5 s, and crashes securityd again, so the user sees an endless "security wants to use the login keychain" password prompt.
I expected OpenCodex not to kill a security that is blocked on a prompt, or to skip the read when the login keychain is locked.
The securityd race itself is Apple's bug, but other tools have hit the same trigger and stopped the loop by no longer killing blocked security calls:
- https://github.com/realiti4/claude-swap/issues/496
- https://github.com/sirmalloc/ccstatusline/issues/740
- https://developer.apple.com/forums/thread/844097
Reproduction
Intermittent, because it needs the login keychain to be locked first (one securityd crash, or a keychain whose password doesn't match the login password).
- Run
ocxas the launchd service with Claude Code signed in through the macOS Keychain. - Get the login keychain locked (for example after one
securitydcrash). - Send Claude requests through the proxy. Each read spawns
security find-generic-password -s "Claude Code-credentials" -w, which blocks on the unlock prompt and is killed after 5 s. securitydcrashes, the keychain locks again, and the prompts keep coming back.
What I observed: 62 security runs in 7 minutes, 16 of them with no normal exit, and 4 securityd crash reports (/Library/Logs/DiagnosticReports/securityd-*.ips), all with the same faulting MachServer stack.
Version
2.97.0 (2.96.0 behaves the same)
Operating system
macOS 27.0 (26A428), Apple Silicon
Provider and model
Claude (claude-cli adapter, Keychain credentials)
Logs or error output
securityd: [com.apple.securityd:SecurityAgentXPCQuery] SecurityAgentXPCQuery(...) dying
securityd: [com.apple.securityd:SecError] Probable bug: error destroying Mutex: 16
securityd: [com.apple.securityd:security_exception] UNIX error exception: 16
crash: EXC_CRASH (SIGABRT), abort() called, faulting thread "MachServer", std::terminate
Screenshots and supporting files
The prompt that keeps coming back: "security wants to use the 'login' keychain. Enter the keychain password."
Redacted configuration
Default service install; nothing relevant in the config.
Possible fix
The workaround I'm running locally checks the login keychain lock state without showing any UI (SecKeychainOpen + SecKeychainGetStatus through bun:ffi) and skips the security call when it is locked. The read returns null (or "unknown" for the probe) and falls back as it already does on a timeout. If anything fails, it returns "not locked", so the behaviour stays the same as now.
export function loginKeychainLocked(path = join(homedir(), "Library", "Keychains", "login.keychain-db")): boolean {
if (process.platform !== "darwin") return false;
// dlopen Security.framework: SecKeychainOpen, SecKeychainGetStatus; CoreFoundation: CFRelease
// return (status & kSecUnlockStateStatus) === 0; any error -> false
}
Then call it at the start of readClaudeKeychain, readClaudeKeychainAsync and keychainProbe. Another option is to stop killing a blocked child: resolve null after 5 s but let the child exit on its own, and share a single in-flight read.
readMuseKeychain already waits 120 s for an interactive login, so I left it alone.
Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
- Lenguaje dominante
- TypeScript
- Estrellas
- 16.9k
- Forks
- 1.3k
- Merge medio
- 23 h
- PR fusionados (30 d)
- 687
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de lidge-jun/opencodex
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 1 día
-
documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 1 día
-
test(gui): restore Overview test globals exactlyPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abiertobug gui
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
lidge-jun/opencodex#8344 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
[Bug]: Claude account rows no longer show the email (since #8055), so "Account 1, 2, 3" cannot be told apartPosiblemente ocupada @lidge-jun la tomó hoy. Abiertoaccount-pool bug gui
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
lidge-jun/opencodex#8286 · 5 comentarios · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
enhancement provider streaming
Dificultad 4/5 3-5 días Aptitud para principiantes 48/100
lidge-jun/opencodex#8363 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 1 día
Todos los issues de lidge-jun/opencodex
Issues similares
-
documentation good first issue roadmap
Dificultad 1/5 1-3 horas Aptitud para principiantes 68/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
resend/react-email#3876 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
siyuan-note/siyuan#21324 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 74/100
dmno-dev/varlock#1279 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
himynameisdave/bsky-profanity-counter#59 ·
Los mantenedores suelen responder en 1 día