fix: keep tenant config out of config.php - #3
Open
YvesCesar wants to merge 15 commits into
Open
Conversation
YvesCesar
marked this pull request as draft
August 20, 2026 12:18
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
…channel Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
It inferred admin intent by diffing files after the fact, but OC\Config::set() and delete() decide against writing by comparing to the instance-wide cache, so a tenant write can leave no trace on disk for the reconciler to find. Reconciliation also used the merged cache as its baseline, which corrupted the matrix on a plain read when another *.config.php defined the same key. Tenant config stays read-only from the module: writes are matrix edits. Signed-off-by: Yves César <yvesamorim73@gmail.com>
Reading straight from envCache returned the tenant value whole, so a tenant overriding redis.port lost redis.host and the connection broke. Restores the array_replace_recursive semantics tenants had before the channel switch. Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
Signed-off-by: Yves César <yvesamorim73@gmail.com>
YvesCesar
force-pushed
the
fix/prevent-tenant-config-leak
branch
from
August 20, 2026 13:01
0e858d2 to
b5f9356
Compare
Signed-off-by: Yves César <yvesamorim73@gmail.com>
YvesCesar
force-pushed
the
fix/prevent-tenant-config-leak
branch
from
August 21, 2026 15:55
da01c62 to
f140a75
Compare
vitormattos
reviewed
Aug 24, 2026
…ixed path Signed-off-by: Yves César <yvesamorim73@gmail.com>
YvesCesar
marked this pull request as ready for review
August 25, 2026 21:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a multi-tenant instance, any system config write flattened the current tenant's values into the instance-wide
config.php, permanently.OC\Config::readData()merges everyconfig/*.config.phpinto$this->cachewithout recording where each key came from, andwriteData()dumps that whole cache withvar_export(). So a singleocc config:system:set foo barservedunder a tenant host also rewrote
mail_smtphost,trusted_domainsand every other key the tenant defined — as global config.Writing config is not something an admin has to ask for: an upgrade alone writes
config.phpabout six times (Updatersetsmaintenance,loglevel,installed,version), andmaintenance:repair, the admin mail form and background jobs such asupdatenotification/ResetTokendo the same. A cron running under one tenant was enough to overwrite the base config for everyone.What changes
The loader body moves to
src/loader.php, included fromconfig/multitenancy.config.phpinsideOC\Config::readData(), so it runs in the config class scope ($thisis theOC\Configinstance).Tenant values are injected into
$this->envCache— the channel behind theNC_*environment variables. Nextcloud reads it with priority andwriteData()never persists it, so tenant config cannot reachconfig.phpat all. Unlike realNC_*variables, whichgetenv()only delivers as strings, this channel accepts arrays and booleans.Array values are merged over the base with
array_replace_recursive, the same rule Nextcloud applies to every*.config.php. Lists merge by index, so tenanttrusted_domainsmust be written in full.