2/18/2026
KeePassXC SSH agent: signing fails while authentication works
KeePassXC SSH agent: signing fails while authentication works
Problem: after configuring git to use SSH commit signing (gpg.format = ssh),
ssh-keygen -Y sign fails with “agent refused operation” — yet SSH
authentication to GitHub works fine. The key is visible in ssh-add -l, and
“Require user confirmation” is unchecked in KeePassXC.
echo "test" | ssh-keygen -Y sign -n git -f <(ssh-add -L | grep my-key)
Signing data on standard input
Couldn't sign message (signer): agent refused operation
Signing (stdin) failed: agent refused operation
Why it happens
KeePassXC is a client, not an agent — it adds keys to whatever ssh-agent
is running at SSH_AUTH_SOCK. When adding keys, it speaks the SSH agent protocol
directly (not via ssh-add). The key detail is in
SSHAgent.cpp:
request.write(
(settings.useLifetimeConstraintWhenAdding() ||
settings.useConfirmConstraintWhenAdding() || isSecurityKey)
? SSH_AGENTC_ADD_ID_CONSTRAINED // code 25
: SSH_AGENTC_ADD_IDENTITY); // code 17
If either “Require user confirmation” or “Remove key from agent after X
seconds” is checked, the key gets added with SSH_AGENTC_ADD_ID_CONSTRAINED.
The confirm constraint triggers the agent to call confirm_key(), which invokes
SSH_ASKPASS. macOS doesn’t ship ssh-askpass, so the confirmation silently
fails and the agent returns SSH_AGENT_FAILURE.
SSH authentication still works because the ssh client has its own interactive
TTY path that bypasses askpass. But ssh-keygen -Y sign goes straight through
the agent’s askpass mechanism — so it fails.
The subtle part: ssh-add -l doesn’t show constraints. There’s no way to
know a loaded key has the confirm flag just by listing it. And changing the
checkbox in KeePassXC doesn’t retroactively update keys already in the agent —
it only affects future addIdentity() calls.
Fix
# Remove all keys from the agent
ssh-add -D
# Lock and unlock the KeePassXC database
# (forces re-add with CURRENT settings)
# Verify signing works
ssh-add -l
echo "test" | ssh-keygen -Y sign -n git -f <(ssh-add -L | grep my-key)
Make sure both “Require user confirmation” and “Remove key from agent after X seconds” are unchecked in the entry’s SSH Agent tab.
Debugging
If the fix above doesn’t work, run the agent in debug mode to see exactly why it’s refusing:
kill $(lsof -t ~/.ssh/agent.sock)
ssh-agent -d -a ~/.ssh/agent.sock
# In another terminal, trigger the sign — watch the debug output
Notes
- The same symptom appears over SSH agent forwarding (e.g., Tailscale SSH), making it easy to misdiagnose as a forwarding issue
- macOS Sonoma 14.6+ broke
SSH_ASKPASSinheritance in launchd, which can silently break previously working setups after an OS update - If you need the confirmation feature, install
brew install theseal/ssh-askpass/ssh-askpassand setSSH_ASKPASS_REQUIRE=force