Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4

Hi,

In the app I’m working on, we rely on SecKeychainUnlock to verify that a password can be used to unlock the login keychain. When macOS 26.4 rolled out, we started getting bug reports that led me to a discovery that makes me think SecKeychainUnlock behavior was changed. I’m going to illustrate my findings with a sample code:

#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <Security/SecKeychain.h>

#pragma clang diagnostic ignored "-Wdeprecated-declarations"

int
main(void)
{
	char password[100];
	printf("password: ");
	scanf("%s", password);

	struct passwd *home = getpwuid(getuid());
	if (!(home && home->pw_dir))
		return 1;

	char path[1024];
	strcat(path, home->pw_dir);
	strcat(path, "/Library/Keychains/login.keychain-db");

	SecKeychainRef keychain = NULL;
	OSStatus result = SecKeychainOpen(path, &keychain);
	if (result != errSecSuccess) {
		fprintf(stderr, "SecKeychainOpen failed (error %d)\n", result);
		return 1;
	}

	SecKeychainStatus status = 0;
	result = SecKeychainGetStatus(keychain, &status);
	if (result != errSecSuccess) {
		fprintf(stderr, "SecKeychainGetStatus failed (error %d)\n", result);
		return 1;
	}

	if (status & kSecUnlockStateStatus) {
		printf("keychain is unlocked, will try to lock first\n");
		result = SecKeychainLock(keychain);
		if (result != errSecSuccess) {
			fprintf(stderr, "SecKeychainLock failed (error %d)\n", result);
			return 1;
		}
		printf("SecKeychainLock succeeded\n");
	} else {
		printf("keychain is locked\n");
	}

	result = SecKeychainUnlock(keychain, strlen(password), password, TRUE);
	if (result == errSecSuccess) {
		printf("SecKeychainUnlock succeeded\n");
		printf("password '%s' appears to be valid\n", password);
	} else {
		printf("SecKeychainUnlock failed (error %d)\n", result);
		printf("password '%s' appears to be invalid\n", password);
	}

	return 0;
}

Here are the outputs of this program on a machine running macOS 26.3 when provided with a correct password deadbeef and with an incorrect password foobar:

testuser1@tahoe1 kcdebug % ./kcdebug
password: deadbeef
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock succeeded
password 'deadbeef' appears to be valid

testuser1@tahoe1 kcdebug % ./kcdebug
password: foobar
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock failed (error -25293)
password 'foobar' appears to be invalid

And here are the outputs of this program on a machine running macOS 26.4:

testuser1@tahoe2 kcdebug % ./kcdebug
password: deadbeef
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock succeeded
password 'deadbeef' appears to be valid

testuser1@tahoe2 kcdebug % ./kcdebug
password: foobar
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock succeeded
password 'foobar' appears to be valid

I’m prepared to send a feedback with Feedback Assistant, but I would like to get a confirmation that this is indeed a bug and not an intended change in behavior. I would also like to know what are my options now. SecKeychainUnlock is just a means to an end; what I really need is the ability to keep the keychain password in sync with the user password when the latter is changed by our program.

Thanks in advance.

Calling SecKeychainUnlock with a locked keychain and an invalid password returns errSecSuccess on macOS 26.4
 
 
Q