#63316 closed defect (bug) (fixed)
[E_WARNING] Undefined array key "host" in wp-includes/canonical.php on line 717
| Reported by: |
|
Owned by: |
|
|---|---|---|---|
| Milestone: | 6.9 | Priority: | normal |
| Severity: | minor | Version: | 2.3 |
| Component: | Canonical | Keywords: | has-test-info has-patch dev-feedback has-unit-tests commit |
| Focuses: | Cc: |
Description
The error of level E_WARNING was catched by using set_error_handler.
The issue related to requests coming from the IP address 85.142.100.134 (which appears to be a scanner from cyberok.ru) that are triggering warnings in WordPress.
access log records:
domain:443 85.142.100.134 - - [19/Apr/2025:23:18:23 +0300] "GET / HTTP/1.1" 301 3405 "-" "Mozilla/5.0 (compatible; CyberOKInspect/1.0; +https://www.cyberok.ru/policy.html)" domain:443 85.142.100.134 - - [19/Apr/2025:23:18:23 +0300] "GET / HTTP/1.1" 200 21814 "https://91.107.124.26/" "Mozilla/5.0 (compatible; CyberOKInspect/1.0; +https://www.cyberok.ru/policy.html)" domain:443 85.142.100.134 - - [19/Apr/2025:23:19:41 +0300] "HELP" 400 3602 "-" "-" domain:443 85.142.100.134 - - [19/Apr/2025:23:19:41 +0300] "EHLO" 400 3602 "-" "-" domain:443 85.142.100.134 - - [19/Apr/2025:23:19:55 +0300] "GET / HTTP/1.0" 301 3410 "-" "-" domain:443 85.142.100.134 - - [19/Apr/2025:23:19:41 +0300] "GET / HTTP/1.0" 301 3410 "-" "-"
Debug backtrace:
Array
(
[0] => Array
(
[file] => \/var\/www\/domain\/wp-includes\/canonical.php
[line] => 717
[function] => {closure}
)
[1] => Array
(
[file] => \/var\/www\/domain\/wp-includes\/class-wp-hook.php
[line] => 324
[function] => redirect_canonical
)
[2] => Array
(
[file] => \/var\/www\/domain\/wp-includes\/class-wp-hook.php
[line] => 348
[function] => apply_filters
[class] => WP_Hook
[type] => ->
)
[3] => Array
(
[file] => \/var\/www\/domain\/wp-includes\/plugin.php
[line] => 517
[function] => do_action
[class] => WP_Hook
[type] => ->
)
[4] => Array
(
[file] => \/var\/www\/domain\/wp-includes\/template-loader.php
[line] => 13
[function] => do_action
)
[5] => Array
(
[file] => \/var\/www\/domain\/wp-blog-header.php
[line] => 19
[args] => Array
(
[0] => \/var\/www\/domain\/wp-includes\/template-loader.php
)
[function] => require_once
)
[6] => Array
(
[file] => \/var\/www\/domain\/index.php
[line] => 17
[args] => Array
(
[0] => \/var\/www\/domain\/wp-blog-header.php
)
[function] => require
)
)
Attachments (1)
Change History (34)
#2
@
9 months ago
- Keywords reporter-feedback added
@ArtZ91 I'm not 100% confident, but it appears that the scanner is accessing your host without the Host header, which might be triggering that warning.
When you fill this kind of reports, ideally I would recommend you to download this plugin into your site
https://wordpress.org/plugins/test-reports/ and send the environment variables or attach the Site Health > Info report
Which provides some variables of what you are using, php versions, server info, etc...
#3
@
9 months ago
Environment
- WordPress: 6.8
- PHP: 8.3.10
- Server: Apache/2.4.52 (Ubuntu)
- Database: mysqli (Server: 8.0.41-0ubuntu0.22.04.1 / Client: mysqlnd 8.3.10)
- Browser: Chrome 135.0.0.0
- OS: Windows 10/11
- Theme: private 1.0
- MU Plugins:
- aios-firewall-loader.php
- Plugins:
- Admin Columns 4.7.7
- Advanced Custom Fields PRO 6.4.0.1
- All-In-One Security (AIOS) 5.4.0
- Cyr-To-Lat 6.3.0
- Disable Comments 2.4.7
- Redirection 5.5.2
- Show Current Template 0.5.2
- SVG Support 2.5.14
- Test Reports 1.2.0
- UpdraftPlus - Backup/Restore 1.25.5
- WP Crontrol 1.18.0
- WP Mail Logging 1.14.0
- WP Mail SMTP 4.4.0
- Yoast Duplicate Post 4.5
- Yoast SEO 24.9
- User Switching 1.9.2
Steps to Reproduce
Not reproduced yet / Steps unknown
Additional Notes
There is no clear understanding yet which process is causing the problem.
Internal wp-cron requests from 127.0.0.1 are executed suspiciously at the same time as this problem, but the logs only catch a GET request to the site root / from the scanner.
"ERROR_LEVEL":"E_DEPRECATED",
"HTTPS":"on",
"HTTP_HOST":"NULL",
"HTTP_REFERER":"NULL",
"HTTP_USER_AGENT":"NULL",
"IS_WP_CRON":false,
"REMOTE_ADDR":"85.142.100.140",
"REQUEST_METHOD":"GET",
"REQUEST_URI":"\/",
"SCRIPT_FILENAME":"\/var\/www\/<domain>\/index.php",
"SERVER_NAME":"<domain>"
#4
@
9 months ago
- Keywords reporter-feedback removed
@ArtZ91 I need to check, but judging from your environment, my intuition says that the problem is with Apache2, it’s not sanitizing the Host header.
I'm going to see if I can setup an Apache host a try again (wordpress-develop env by default uses nginx reverse proxy with FPM-PHP hosts for WP). Still if this is the problem, host existance should be checked before using it in the informed variable, hence, there is a potential issue to be sorted, just we need some reproduction steps to consistently reproduce this issue until it gets sorted.
#5
@
9 months ago
- Keywords has-testing-info added; needs-testing-info removed
Bug Reproduction Report
Description
✅ This report validates that the issue can be reproduced.
Environment 1
- WordPress: 6.9-alpha-60093-src
- PHP: 8.2.28
- Server: Apache/2.4.63 (Unix)
- Database: mysqli (Server: 8.4.5 / Client: mysqlnd 8.2.28)
- Browser: Chrome 135.0.0.0
- OS: Windows 10/11
- Theme: Minimal Child Theme 1.0.2
- MU Plugins: None activated
- Plugins:
- Test Reports 1.2.0
Environment 2
- WordPress: 6.8.1
- PHP: 8.2.18
- Server: Apache/2.4.59 (Win64) OpenSSL/3.1.5
- Database: mysqli (Server: 11.8.1-MariaDB-log / Client: mysqlnd 8.2.18)
- Browser: Chrome 137.0.0.0
- OS: Windows 10/11
- Theme: Twenty Twenty-Five 1.2
- MU Plugins: None activated
- Plugins:
- Test Reports 1.2.0
Reproduction Steps
- First, you need a server that can accept requests without a Host. I tried to make Nginx do this, but could not find an easy solution. So the only alternative was to use Apache2 (this is why I asked here for the environment vars, I had a suspicion that A2 was the culprit.
- Second, we need to make sure that Apache2 has the guard down. We need to set
HttpProtocolOptions Unsafefor theVirtualHost
- Third, we should issue a request with very low standards. Like this one:
curl --http1.0 -H 'Host:' http://localhost:8889
Note that in my case I'm using the wordpress-develop build, with an slightly modified version to use Apache2 instead of Nginx
If you want to run my config in wordpress-develop you can get my patch with
npm run grunt patch:https://github.com/WordPress/wordpress-develop/pull/8722
If you want to run with other system, like LocalWP, FlyEnv, Laravel Herd check this
- Your PHP Error Logs must be activated, check the logs are being generated before starting (for example, create a file in the wordpress installation called error.php and add something like
error_log("test"); - Your WP installation must be the only host because we are sending a Host without header. Otherwise make sure that your VirtualHost is first in priority (in the Virtualhost file, add something like
000-myhost.conf, Apache priority is based on the filenames) - You should not run HTTPS. Disable HTTPS for the test
Actual Results
- ✅ Error condition occurs (reproduced) in both environments.
Here is the debug log that displays the same error that the reporter is reporting: https://gist.github.com/SirLouen/16ad44e99dbcf9ef7bd932663ba48e2f#file-debug-log
Additional Notes
- Despite A2 being the culprit, I believe that this warning should be handled.
- I'm not 100% confident that it feels that it's complex that this error happens in any modern well configured server, but as always, better safe than sorry.
This ticket was mentioned in PR #8723 on WordPress/wordpress-develop by @SirLouen.
9 months ago
#6
- Keywords has-patch added
Instructions to check this here:
https://core.trac.wordpress.org/ticket/63316#comment:5
Trac ticket: https://core.trac.wordpress.org/ticket/63316
#7
@
9 months ago
- Keywords needs-testing added
Testing instructions and patched provided. Reading for testing.
This ticket was mentioned in Slack in #core-test by sirlouen. View the logs.
8 months ago
This ticket was mentioned in Slack in #core-test by sirlouen. View the logs.
8 months ago
#11
@
7 months ago
More Testing info
It seems that some versions of Curl (over 8.10.x) add automatically a Host despite you set the header with Host: empty explicitely
For this reason an alternative is using another tool like netcat
Create a file called for example request.txt like:
GET / HTTP/1.0
Note the empty line by the end, this is important depending on the OS you are testing this.
And then call this like: nc localhost 8080 < request.txt (or ncat in Windows, you may need nmap tools)
The thing here is that HTTP 1.0 is the key: An Apache server, accepting 1.0 insecure requests, a gift of a server... is the method to trigger these canonical errors.
@ArtZ91 upgrade that prehistoric server!!!
#12
@
7 months ago
I was able to reproduce the warnings and confirm that the patch fixes them. https://github.com/WordPress/wordpress-develop/pull/8723#pullrequestreview-2932045724
This ticket was mentioned in Slack in #core by sirlouen. View the logs.
7 months ago
This ticket was mentioned in Slack in #core by audrasjb. View the logs.
7 months ago
This ticket was mentioned in Slack in #core by sirlouen. View the logs.
7 months ago
#18
@
7 months ago
- Keywords dev-feedback added
6.9.0 Milestone proposed during today's <bug-scrub>
More information
cc @SergeyBiryukov
#19
@
7 months ago
- Severity changed from normal to minor
This is a low priority report but a straightforward easy fix.
This ticket was mentioned in Slack in #core by sirlouen. View the logs.
7 months ago
#21
@
6 months ago
Maybe related: https://core.trac.wordpress.org/ticket/63733
#22
@
6 months ago
I have a few concerns about this patch:
1.
|| ! isset( $original['host'] )
I totally see how it makes sense to not attempt to redirect if $original['host'] is missing, but I found contrary evidence this use-case is/was intended to be supported via #6890.
If $original['host'] really is allowed to be empty, we'll need to make sure it's set like we do for path & query.
2.
|| ! isset( $original['path'] )
Will break for valid & well-formed URLs like: https://example.com?p=100
parse_url() will not set the path key, but query (p=100) is still deserving of canonical redirection.
What if we add...
if ( ! isset( $redirect['host'] ) ) {
$redirect['host'] = '';
}
...below...
// Notice fixing.
...and then let it do what it normally would to figure things out?
#23
@
6 months ago
@johnjamesjacoby I pushed that change to the PR with all the confidence, and then tested with my test report instructions and still is throwing the Warning, that doesn't solve the issue.
#24
follow-up:
↓ 25
@
6 months ago
- Milestone changed from Awaiting Review to 6.9
- Owner set to johnjamesjacoby
- Status changed from new to assigned
@SirLouen I see what you mean. I've dug a bit deeper and I think the patch I just attached should fix all instances where array keys are assumed to exist when they may not. Would love your eyes on it!
#25
in reply to:
↑ 24
@
6 months ago
Replying to johnjamesjacoby:
@SirLouen I see what you mean. I've dug a bit deeper and I think the patch I just attached should fix all instances where array keys are assumed to exist when they may not. Would love your eyes on it!
It seems it has progressed with that patch
[24-Jul-2025 12:23:07 UTC] PHP Warning: Undefined array key "scheme" in /var/www/src/wp-includes/canonical.php on line 766
[24-Jul-2025 12:23:07 UTC] PHP Stack trace:
[24-Jul-2025 12:23:07 UTC] PHP 1. {main}() /var/www/src/index.php:0
[24-Jul-2025 12:23:07 UTC] PHP 2. require_once() /var/www/src/index.php:19
[24-Jul-2025 12:23:07 UTC] PHP 3. require() /var/www/src/_index.php:17
[24-Jul-2025 12:23:07 UTC] PHP 4. require_once() /var/www/src/wp-blog-header.php:19
[24-Jul-2025 12:23:07 UTC] PHP 5. do_action($hook_name = 'template_redirect') /var/www/src/wp-includes/template-loader.php:13
[24-Jul-2025 12:23:07 UTC] PHP 6. WP_Hook->do_action($args = [0 => '']) /var/www/src/wp-includes/plugin.php:517
[24-Jul-2025 12:23:07 UTC] PHP 7. WP_Hook->apply_filters($value = '', $args = [0 => '']) /var/www/src/wp-includes/class-wp-hook.php:348
[24-Jul-2025 12:23:07 UTC] PHP 8. redirect_canonical($requested_url = '', $do_redirect = *uninitialized*) /var/www/src/wp-includes/class-wp-hook.php:324
We can simply use the same strategy adding scheme
This is the current error, still scheme has to be handled.
But I wonder why you think that we should not short-circuit in the absence of the Host. Or I think we should handled those faulty requests with missing elements.
#26
@
6 months ago
- Keywords needs-unit-tests added
Given that there are so many values now, I have implemented a little mod in my PR that is a little simpler than so many conditionals.
Maybe we should be adding tests, but assertCanonical forces example.com so its impossible to trigger empty host and scheme.
I've only added one Unit Test to check for the absence of path and query as in #63733 but handling Host and Scheme is a little bit more tricky (at least with that function that is only testing for canonical paths)
#27
@
6 months ago
I've been doing some debugging, and I've located the issue of why there is an empty host on the error, but there can actually show a port.
Here, with my curl --http1.0 -H 'Host:' http://localhost:8889
$redirect host localhost and port 8889, but $original is port 8889, but host is empty
This is the culprit: $redirect is getting $user_home.
Then ut comes to this line with an empty host then. Even if we remove the port, it will get redirected there with :/// requested_url (no scheme, no host, no port)
As I say, leaving the empty host dangling through the function is not doing any good. Also, we can try to handle that :/// (or ://:port/) somewhere in the middle of redirect_canonical.
I would simply short-circuit, as I said. An Empty host can't be done with HTTP1.1+ and supporting HTTP1.0 doesn't make much sense in 2025, but still a "catch-all" in user_home could also make sense, though.
But if we are willing to let it go through, I'm still trying to figure out how to trigger this with a Unit Test.
#28
@
6 months ago
- Keywords has-unit-tests added; needs-unit-tests removed
Found the workaround for unit testing these properties.
Kind of weird overall this behaviour, but this is what it takes.
#30
@
4 months ago
- Keywords needs-testing removed
@mindctrl more than testing, what this need is Mr @johnjamesjacoby to provide some feedback to my last answer. Any testing attempts can be a waste if we don't reach a conclusion.
#31
@
3 months ago
- Keywords commit added
@SirLouen Thanks for your persistence here.
I'm comfortable committing your PR for 6.9.
It fixes the issue for me, too, and is the most minimally invasive way I can see to address this.
An Empty host can't be done with HTTP1.1+ and supporting HTTP1.0 doesn't make much sense in 2025, but still a "catch-all" in user_home could also make sense
Agree about actively supporting HTTP1.0. That's a larger decision that you can influence via this issue and help communicate more broadly in the future if/when the need arises.
Hey @ArtZ91, Thanks for raising the ticket.
Could you possibly outline the details on how to reproduce this error?
A step-by-step guide or a screencast would be super helpful in identifying the root cause.