Skip to content

fix: fall back to the first trusted domain whatever its array key - #41894

Open
openefaadmin wants to merge 1 commit into
owncloud:masterfrom
openefaadmin:fix/trusted-domains-first-entry
Open

openefaadmin wants to merge 1 commit into
owncloud:masterfrom
openefaadmin:fix/trusted-domains-first-entry

Conversation

@openefaadmin

Copy link
Copy Markdown

Request::getServerHost() returns $trustedList[0] for an untrusted Host header.
config.php's trusted_domains is commonly edited by hand or via
occ config:system:delete trusted_domains 0, leaving e.g. [2 => 'host'];
index 0 is then missing, getServerHost() returns null with an "Undefined array
key 0" warning, and callers expecting a string fail. Return the first
configured entry (reset()) instead, cast to string.

Adds testGetServerHostWithUntrustedDomainAndNonSequentialKeys.

How this was tested

New test testGetServerHostWithUntrustedDomainAndNonSequentialKeys errors without the fix and passes with it; RequestTest: 127 tests OK (PHP 8.4, on top of the PHP 8.4 nullable PR so the suite can boot).

A changelog entry is included in changelog/unreleased/; it links pull/TBD and can be renamed to the PR number.

@openefaadmin
openefaadmin requested a review from a team as a code owner October 7, 2026 02:43
@CLAassistant

CLAassistant commented Oct 7, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Request::getServerHost() returns $trustedList[0] for an untrusted Host header.
config.php's trusted_domains is commonly edited by hand or via
`occ config:system:delete trusted_domains 0`, leaving e.g. [2 => 'host'];
index 0 is then missing, getServerHost() returns null with an "Undefined array
key 0" warning, and callers expecting a string fail. Return the first
configured entry (reset()) instead, cast to string.

Adds testGetServerHostWithUntrustedDomainAndNonSequentialKeys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Scott Barbour <scott@efasecurity.com>
@openefaadmin
openefaadmin force-pushed the fix/trusted-domains-first-entry branch from 423a27c to 5322f88 Compare October 7, 2026 17:05
// first configured entry, whatever its key: after entries are removed
// from config.php the list can be e.g. [2 => 'host'], where
// $trustedList[0] would be null
return (string)\reset($trustedList);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note: reset goes to the first element of the array in the order in which they were declared.
If someone does something weird, like setting the keys out of order then:

[2 => 'firsthost.example`, 1 => 'anotherhost.example', 0 => 'hostzero.example']

Then the old code would have returned hostzero.example and this new code will return firsthost.example

I don't think that matters.

@phil-davis
phil-davis self-requested a review October 8, 2026 04:56
@openefaadmin

openefaadmin commented Oct 8, 2026 via email

Copy link
Copy Markdown
Author

@oc-tmueller oc-tmueller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks, this fixes the sparse-list case. One behaviour change and a test gap inline.

Follow-up, not for this PR: the root cause is DeleteConfig::removeSubValue() (core/Command/Config/System/DeleteConfig.php:103), which unset()s the sub-key without renumbering. So after occ config:system:delete trusted_domains 0, every reader of the list sees [1 => …, 2 => …], not just getServerHost(). Renumbering list-shaped arrays there would cover all of them. Happy to have that as a separate PR.

// first configured entry, whatever its key: after entries are removed
// from config.php the list can be e.g. [2 => 'host'], where
// $trustedList[0] would be null
return (string)\reset($trustedList);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

reset() returns the first entry by position, not key 0, which changes the result when key 0 exists but isn't first. For example: occ config:system:delete trusted_domains 0, then occ config:system:set trusted_domains 0 --value=new.example.com. PHP appends the new key 0 at the end, so the list is [1 => 'old.example.com', 0 => 'new.example.com']. Before this PR the fallback was new.example.com; now it's old.example.com.

Keeping key 0 when it exists avoids that:

Suggested change
return (string)\reset($trustedList);
return (string)($trustedList[0] ?? \reset($trustedList));
$this->assertSame('my.trusted.host', $request->getServerHost());
}

public function testGetServerHostWithUntrustedDomainAndNonSequentialKeys() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you add a case for key 0 present but not first, e.g. [1 => 'other.host', 0 => 'my.trusted.host'] expecting my.trusted.host? With [2 => …] alone, both reset() and [0] ?? reset() pass, so the ordering question above isn't pinned down.

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

Labels

None yet

4 participants