Make WordPress Core

Opened 11 months ago

Last modified 5 months ago

#56141 new enhancement

Enhance installer security

Reported by: smitka's profile smitka Owned by:
Milestone: Future Release Priority: high
Severity: major Version:
Component: Security Keywords: dev-feedback
Focuses: Cc:



The WP installer needs to implement security features to prevent unauthorized use. If the attacker finds an unfinished installer, he can finish the installation on behalf of the user and make malicious changes.

It was hard to find these unfinished installers in the past, but from 2018 Google Chrome requires all publicly trusted web certificates to be logged in Certificate Transparency Log. It is possible to parse CT log in realtime and target newly created websites. Usually, the SSL certificate is issued when a new hosting is set up. So, you can learn about most of the newly created websites from the CT log. The CT log is huge and reliable parsing should be challenging, but the methods are improving, and this attack is becoming more common.

With current methods, it can take less than a minute for an attacker to learn of and compromise a new site. The attacker needs only one HTTP request to compromise the site - send valid DB credentials to /wp-admin/setup-config.php?step=2. In this case, the WP installer creates wp-config.php with these DB credentials. The user can then install WP into an external database controlled by the attacker without noticing.

I analyzed a big-scale ongoing attack of this type and got access to the attacker database to further investigation. He can compromise hundreds of sites a day. I made an automated system to notify administrators of compromised sites. During three days, I sent more than 600 notifications and published the details on

Another installer issue, #52544, makes the installer publicly available too, but the possibility of exploitation is rather accidental and more noticeable.


I see two ways how to add additional protection without significant process changes and without bothering the user too much:

1) allow only particular DB hosts
2) add an installation key feature

For the first one, I made a PoC mu-plugin which controls allowed DB hosts via environment variables or configuration file.

Localhost + is allowed by default, so there is no change for many users. A web host can use the env variable to define their DB servers, so the process will be smooth if they use external DB. If the user wants to use any other server, he has an option to define them via constant in the wp-dbhosts.php file (it is not possible to use wp-config because it doesn't exist).

For the second one, you need to modify the installation workflow slightly. I made a modified setup-config.php as PoC:

It combines the first method - if the DB host is localhost or any server allowed by an environment variable, there is no change for users. If you want to use any other DB host, you have to fill "install key". The "install key" is generated into the install-key.php file, and the user can read it via FTP (the same way he uploaded the core files).

Demo how it works:

Change History (10)

#1 @audrasjb
11 months ago

  • Version 6.0 deleted

This ticket was mentioned in Slack in #hosting-community by smitka. View the logs.

11 months ago

#3 @costdev
10 months ago

  • Keywords dev-feedback added
  • Milestone changed from Awaiting Review to 6.1
  • Priority changed from normal to high
  • Severity changed from normal to major

Milestoning for 6.1 and increasing priority/severity to get this ticket more attention.

As the description says, detecting new sites is now quicker and easier, and due to the recent increase in attack numbers (last month, 2000+ hit the honeypot, and many others will have happened to other sites), we should aim for a decision/resolution in this cycle.

#4 @lordgurke
10 months ago

Hi smitka,

For the install key: I would also read it from an environment variable, if it's set. With that, a hoster can generate this key automatically and display it within the customers backend. The installer will be secured by default, without a need for the customers to upload any additional files.
Also, maybe other projects might want to use such a feature and can then simply refer to a (standardized?) environment variable.

I also created such a request a few months ago in the forums, but this has been silently deleted without any reason. Maybe WordPress could provide a reason for this, because I have a feeling many other reports on problems ceased to exist that way.

#5 @smitka
10 months ago

Some updates about the ongoing attack. The main attackers change their strategy and generate unique DB credentials per vulnerable site. The result is that when I get access to their database, I cannot find new hacked sites to notify their admins anymore.

I sent over 2000 notifications last month and detected around 3000 different sites in the attacker's databases. I probably only discovered a fraction of the compromised sites. In some cases, the attacker was quicker than me, and he changed the admin email so I couldn't send the notifications. I only gained access to the database if the attacker attacked my honeypot servers.

@lordgurke, I agree it would be great to have the possibility to override some constants by the environment values. I have to use the Runkit PHP extension to override some values without user intervention. However, we still have to keep in mind that env variables can be listed in different places, such as phpinfo() output. The chances that this file will be available in the unfinished installation are minimal, but I would still prefer to avoid using them for the install key.

I should describe the function of my second proposal in more detail:

The host specifies allowed DB servers via env variable; the localhost and are allowed by default. If you use the allowed DB host during the installation, the install key is not required, and the process is unchanged for the majority of new manual installs.

The situation is different when you want to use an unlisted DB host. In this scenario, the installer will generate the install-key.php file and force the user to use it. The user can read it via FTP/SFTP/SSH, or the host can show it in the administration (maybe it would be a good idea to add another variable to add a link to the host documentation or administration).

There is no need to upload anything, and most users' installation process is the same (even if the host doesn't set the variables).

The flaw with this approach is that there is still a tiny chance that the attacker has set up webhosting with the same provider as the target site and can use the allowed DB host for malicious activity. To prevent this, you can make an "allowed DB names list" too. However, this demands more on the host, as it has to prepare unique env variables for each site.

BTW: it is possible to show the diff between the original setup-config.php and my PoC fix:

I also added some captions to my explainer video to make it clearer what's going on:

#6 follow-up: @desrosj
9 months ago

  • Milestone changed from 6.1 to Future Release

This one still needs more discussion. With 6.1 Beta 1 due out in a few days, it's a bit late to include this so I'm going to punt.

#7 in reply to: ↑ 6 @smitka
9 months ago

Replying to desrosj:

This one still needs more discussion. With 6.1 Beta 1 due out in a few days, it's a bit late to include this so I'm going to punt.

Is there any place to join the discussion?

#8 @audrasjb
9 months ago

@smitka the place to discuss this ticket is the ticket itself: here :)

This ticket was mentioned in Slack in #hosting-community by chaion07. View the logs.

6 months ago

This ticket was mentioned in Slack in #hosting-community by jadonn. View the logs.

5 months ago

Note: See TracTickets for help on using tickets.