Skip to content

Restrict File Provider Keychain Scope - #10981

Open
i2h3 wants to merge 4 commits into
masterfrom
i2h3/9865-keychain-scope
Open

i2h3 wants to merge 4 commits into
masterfrom
i2h3/9865-keychain-scope

Conversation

@i2h3

@i2h3 i2h3 commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Intentionally skipping 34.0.5 and 35.0.0 and to be ported back later! Fixes #10976. Replaces #10858. Relates to #9865.

Thanks to @stuckj for clearing this issue up and taking the initiative! I probably would not have seen the problem here without their help and first draft.

Checklist

AI (if applicable)

@i2h3 i2h3 added this to the 35.0.1 milestone Oct 1, 2026
@i2h3 i2h3 self-assigned this Oct 1, 2026
@i2h3 i2h3 added bug os: 🍎 macOS Apple macOS, formerly also known as OS X feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. labels Oct 1, 2026
@i2h3

i2h3 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

/backport to stable-34.0

@i2h3

i2h3 commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator Author

/backport to stable-35.0

@i2h3 i2h3 changed the title Constrain File Provider Keychain Scope Restrict File Provider Keychain Scope Oct 1, 2026
@i2h3
i2h3 marked this pull request as ready for review October 2, 2026 09:23
@i2h3
i2h3 force-pushed the i2h3/9865-keychain-scope branch 2 times, most recently from 1cb5951 to d16fa95 Compare October 2, 2026 14:11
@i2h3
i2h3 force-pushed the i2h3/9865-keychain-scope branch from d16fa95 to 7e665b1 Compare October 4, 2026 11:18
@i2h3
i2h3 force-pushed the i2h3/9865-keychain-scope branch from 7e665b1 to aad263a Compare October 13, 2026 08:53
i2h3 and others added 4 commits October 19, 2026 12:53
The file provider extension stored the account password as a generic
password and scoped it with kSecAttrServer. That attribute belongs to
internet passwords and macOS ignores it on generic passwords, so every
lookup and update matched on the account name alone. Saving the password
overwrote the generic passwords of other applications using the same
account name, as reported in #9865, and a lookup could return one of
them.

Key the item by the file provider domain identifier as service and the
user name as account, and show the domain display name as its label.
Items written by earlier versions are left alone because they cannot be
told apart from the items of other applications.

Refs #9865

Co-authored-by: Jonathan Stucklen <stuckj@gmail.com>
Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
… out

removeAccountConfig now also deletes every keychain item of the domain.
The main app sends it when the account is signed out, needs credentials
again, is redirected or must accept the terms of service. Without this,
Finder could authenticate the domain again with a password the user
signed out of, and every account removed and added again would leave
one more item behind now that items are keyed by domain.

Refs #9865

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
The extension cannot run once its domain is removed, so the password it
stored would stay in the keychain. Add a request through which the main
app asks the extension of a domain to delete its stored password, and
send it as the first step of every domain removal. The main app waits at
most one second for the reply and removes the domain in any case.

The request is a new method instead of a changed removeAccountConfig
because an extension still running an older build drops a selector it
does not know, which would also drop the existing sign-out handling.

Refs #9865

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
…eProviderKit

The keychain regression tests skip themselves when the default keychain
is not usable. In CI that would hide them silently, so require them
there, and limit how long the test job can run in case the keychain
waits for user interaction.

Refs #9865

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Iva Horn <iva.horn@nextcloud.com>
@i2h3
i2h3 force-pushed the i2h3/9865-keychain-scope branch from aad263a to 33a8c62 Compare October 19, 2026 10:53
@sonarqubecloud

Copy link
Copy Markdown

Comment on lines +129 to +132
if (!xpc) {
qCInfo(lcMacFileProvider) << "Not deleting password because XPC is not configured." << fileProviderDomainIdentifier;
return std::nullopt;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Startup orphan removal skips password cleanup -> returns immediately without XPC. The settings controller removes orphaned domains before calling configureXPC(), so that path removes domains without sending a deletion request, leaving scoped credentials behind. It needs to acquire the domain’s service before removal. This finding is based on source inspection.

Comment on lines +45 to 49
public func deletePassword(completionHandler: ((Bool) -> Void)?) {
logger.info("Received request to delete the stored password.")
let deleted = keychain.deletePassword()
completionHandler?(deleted)
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Queued setup can recreate a deleted password -> deletes independently of setupChain. This is reproducible: hold authentication A, queue configuration B, delete successfully, then release A—B stores its password afterward. Deletion needs to invalidate pending setup and coordinate with credential writes. The sign-out path has the same ordering problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-request bug feature: 📁 file provider macOS File Provider Extension, more general also known as virtual file system. os: 🍎 macOS Apple macOS, formerly also known as OS X

Projects

Status: 🏗️ In progress

Development

Successfully merging this pull request may close these issues.

[Bug]: macOS client modifies another app's keychain item on startup (sets partition list to teamid:NKUJUXUJ3B), breaking Claude Code

2 participants