<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jonathan Pimperton</title>
    <description>The latest articles on DEV Community by Jonathan Pimperton (@jonathan_pimperton_971ac1).</description>
    <link>https://dev.to/jonathan_pimperton_971ac1</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3855750%2F0635646c-0a8b-4ea4-af66-67e97ad3bac4.png</url>
      <title>DEV Community: Jonathan Pimperton</title>
      <link>https://dev.to/jonathan_pimperton_971ac1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jonathan_pimperton_971ac1"/>
    <language>en</language>
    <item>
      <title>Open Directory Listings: The WordPress Security Hole You Forgot</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Tue, 12 May 2026 10:00:35 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/open-directory-listings-the-wordpress-security-hole-you-forgot-480p</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/open-directory-listings-the-wordpress-security-hole-you-forgot-480p</guid>
      <description>&lt;h2&gt;
  
  
  Open Directory Listings: The WordPress Security Hole You Forgot
&lt;/h2&gt;

&lt;p&gt;Many web developers and WordPress agencies focus heavily on application-level security: keeping WordPress core updated, using reputable plugins, and implementing strong user authentication. These are all critical, of course. However, there's a more fundamental web server configuration issue that often gets overlooked and can inadvertently expose sensitive information: open directory listings.&lt;/p&gt;

&lt;p&gt;Most of us know that Apache and Nginx serve files. When a request comes in for a directory (like &lt;code&gt;/wp-content/uploads/&lt;/code&gt;), and there's no index file (like &lt;code&gt;index.html&lt;/code&gt; or &lt;code&gt;index.php&lt;/code&gt;) present, the web server has a choice: either deny access or display a list of the files and subdirectories within that directory. This latter behavior, known as "directory indexing" or "autoindexing," can be a significant security vulnerability.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: Revealing Your File Structure
&lt;/h3&gt;

&lt;p&gt;Imagine a typical WordPress installation. You have your core files, your theme files, and your plugin files. Crucially, the &lt;code&gt;/wp-content/uploads/&lt;/code&gt; directory houses all the media that users upload to your site. If directory indexing is enabled on your server, a malicious actor or even a curious competitor can simply navigate to this URL in their browser:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://your-wordpress-site.com/wp-content/uploads/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If directory listing is on, they'll see a nicely formatted list of all the files and folders within your uploads directory. This might seem innocuous at first glance. You uploaded some images, maybe a PDF or two. But consider what else might end up in there, intentionally or unintentionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Sensitive documents:&lt;/strong&gt; If a client uploaded a document containing personally identifiable information (PII) or proprietary business data and it landed in a publicly browsable directory, that data is now exposed.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Backup files:&lt;/strong&gt; Developers sometimes create temporary or even accidental backups of configuration files or other sensitive data and upload them without realizing the implications.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Exploitable code or configurations:&lt;/strong&gt; While less common, improperly secured files containing custom code or server configurations could be revealed.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Detailed file structure:&lt;/strong&gt; Even if no directly sensitive files are present, the listing provides a clear map of your site's internal file structure. This information can be invaluable to an attacker planning further exploits. They can see exactly where themes are stored, where plugins reside, and other organizational details they can use to tailor their attacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing for Open Directory Listings
&lt;/h3&gt;

&lt;p&gt;You can easily test your own WordPress sites. Open your web browser and navigate to your primary upload directory:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://your-wordpress-site.com/wp-content/uploads/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you see a list of your uploaded files and folders, directory indexing is enabled. Try navigating into a subfolder as well, for example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://your-wordpress-site.com/wp-content/uploads/2023/10/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you can see the contents of that month's upload folder, you have a problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Fix: Disabling Directory Indexing
&lt;/h3&gt;

&lt;p&gt;Fortunately, disabling directory indexing is straightforward and is a fundamental security best practice for any web server. The method depends on whether you're using Apache or Nginx.&lt;/p&gt;

&lt;h4&gt;
  
  
  Apache: Using &lt;code&gt;.htaccess&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;For Apache servers, the most common way to manage this is through a &lt;code&gt;.htaccess&lt;/code&gt; file located in the relevant directory. Place the following directive within a &lt;code&gt;.htaccess&lt;/code&gt; file in your &lt;code&gt;/wp-content/uploads/&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Options -Indexes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to apply this globally to your entire WordPress installation (which is often recommended for added security), you can place this directive in the &lt;code&gt;.htaccess&lt;/code&gt; file in your WordPress root directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; If you already have a &lt;code&gt;.htaccess&lt;/code&gt; file in that directory, add &lt;code&gt;Options -Indexes&lt;/code&gt; on a new line. Ensure there are no conflicting &lt;code&gt;Options +Indexes&lt;/code&gt; directives.&lt;/p&gt;

&lt;h4&gt;
  
  
  Nginx: Server Configuration
&lt;/h4&gt;

&lt;p&gt;For Nginx, directory indexing is controlled within the server block configuration. You'll need to edit your Nginx site configuration file (often found in &lt;code&gt;/etc/nginx/sites-available/&lt;/code&gt; or similar). Within the &lt;code&gt;location&lt;/code&gt; block that serves your WordPress files, you'll want to ensure &lt;code&gt;autoindex&lt;/code&gt; is turned off.&lt;/p&gt;

&lt;p&gt;Here’s a typical example of a &lt;code&gt;location&lt;/code&gt; block for serving static files where you'd ensure &lt;code&gt;autoindex&lt;/code&gt; is explicitly off, or simply not present (as it defaults to off):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/wp-content/uploads/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# Other directives like try_files, expires etc. can go here.&lt;/span&gt;
    &lt;span class="kn"&gt;autoindex&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# Explicitly turn it off, though usually off by default.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are serving your entire WordPress site from a single &lt;code&gt;location / {}&lt;/code&gt; block, you might want to be more specific or ensure the default is respected. A common pattern for WordPress with Nginx involves a main location block and then specific ones for static assets. If you're not explicitly enabling &lt;code&gt;autoindex&lt;/code&gt;, you are generally safe. However, for clarity and to prevent accidental enablement, you can add &lt;code&gt;autoindex off;&lt;/code&gt; to any relevant &lt;code&gt;location&lt;/code&gt; blocks.&lt;/p&gt;

&lt;p&gt;After making changes to your Nginx configuration, remember to test the configuration and reload Nginx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Beyond Uploads
&lt;/h3&gt;

&lt;p&gt;While &lt;code&gt;/wp-content/uploads/&lt;/code&gt; is the most common and often the most impactful place for this vulnerability, consider if other directories might contain sensitive information that could be accidentally exposed if directory indexing were enabled. For most standard WordPress sites, disabling it for &lt;code&gt;/wp-content/uploads/&lt;/code&gt; is the priority.&lt;/p&gt;

&lt;p&gt;This might seem like a minor configuration detail, but in the realm of web security, even small oversights can have significant consequences. Regularly auditing your web server configurations for issues like open directory listings is a vital part of maintaining a secure WordPress environment for your clients.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://sitevett.com" rel="noopener noreferrer"&gt;SiteVett&lt;/a&gt; checks this automatically as part of a free website QA scan with 60+ checks across security, SEO, content, performance, and more.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/scanner" rel="noopener noreferrer"&gt;Run a free scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/features" rel="noopener noreferrer"&gt;See all checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/sample-report" rel="noopener noreferrer"&gt;View a sample report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>wordpress</category>
      <category>apache</category>
    </item>
    <item>
      <title>4 Security Headers Every Website Should Have</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Tue, 28 Apr 2026 10:00:44 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/4-security-headers-every-website-should-have-346k</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/4-security-headers-every-website-should-have-346k</guid>
      <description>&lt;h2&gt;
  
  
  4 Security Headers Every Website Should Have
&lt;/h2&gt;

&lt;p&gt;As web developers and agencies, we're constantly building and optimizing. While performance and features get a lot of attention, security can sometimes take a backseat. This is a mistake. Implementing a few key HTTP security headers is a relatively low-effort, high-reward way to significantly improve your site's defense against common attacks.&lt;/p&gt;

&lt;p&gt;These headers are instructions sent from your web server to the user's browser. The browser then enforces these rules, making it harder for attackers to exploit vulnerabilities. Let's cover four essential ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  HSTS (HTTP Strict Transport Security)
&lt;/h3&gt;

&lt;p&gt;HSTS tells the browser to &lt;em&gt;only&lt;/em&gt; connect to your website using HTTPS, even if the user types in &lt;code&gt;http://yourdomain.com&lt;/code&gt; or clicks an old &lt;code&gt;http&lt;/code&gt; link. This prevents "man-in-the-middle" attacks where an attacker intercepts an HTTP connection to steal or modify data.&lt;/p&gt;

&lt;p&gt;The header looks like this: &lt;code&gt;Strict-Transport-Security: max-age=31536000; includeSubDomains; preload&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;max-age&lt;/code&gt;: How long the browser should remember to enforce HTTPS (here, one year).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;includeSubDomains&lt;/code&gt;: Applies the rule to all subdomains.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;preload&lt;/code&gt;: This is optional but powerful. It allows you to submit your site to a browser-maintained list, so even the first visit defaults to HTTPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common Mistake&lt;/strong&gt;: Trying to implement HSTS before you are absolutely certain your entire site, including all subdomains and assets, is correctly served over HTTPS. If your HTTPS setup has issues, HSTS will prevent users from accessing your site entirely. Test thoroughly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checking with &lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the &lt;code&gt;Strict-Transport-Security&lt;/code&gt; header in the output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache&lt;/strong&gt;: Add to your &lt;code&gt;.htaccess&lt;/code&gt; file or virtual host configuration. Ensure &lt;code&gt;mod_headers&lt;/code&gt; is enabled.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_headers.c&amp;gt;
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;: Add to your server block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Strict-Transport-Security&lt;/span&gt; &lt;span class="s"&gt;"max-age=31536000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;includeSubDomains&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;preload"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Strict-Transport-Security&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;max-age=31536000; includeSubDomains; preload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Content-Security-Policy (CSP)
&lt;/h3&gt;

&lt;p&gt;CSP is a powerful header that helps mitigate cross-site scripting (XSS) and other code injection attacks. It allows you to specify which sources of content (scripts, styles, images, etc.) the browser is allowed to load for your page. It's like a whitelist for your website's resources.&lt;/p&gt;

&lt;p&gt;A basic CSP might look like: &lt;code&gt;Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; object-src 'none'; base-uri 'self'&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;default-src 'self'&lt;/code&gt;: By default, only allow content from your own domain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;script-src 'self' https://trusted.cdn.com&lt;/code&gt;: Specifically allow scripts from your domain and a trusted CDN.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;object-src 'none'&lt;/code&gt;: Prevent plugins like Flash or Java from being loaded.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;base-uri 'self'&lt;/code&gt;: Restrict the URLs that can be used in a page's &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CSP can get complex quickly, and it's best to start with a restrictive policy and then loosen it as needed based on your site's requirements. Use &lt;code&gt;report-uri&lt;/code&gt; or &lt;code&gt;report-to&lt;/code&gt; directives to log violations before going fully enforced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checking with &lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the &lt;code&gt;Content-Security-Policy&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_headers.c&amp;gt;
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none';"
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: &lt;code&gt;'unsafe-inline'&lt;/code&gt; for scripts is often necessary for WordPress themes and plugins. Aim to remove it over time by moving inline scripts to external files.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Content-Security-Policy&lt;/span&gt; &lt;span class="s"&gt;"default-src&lt;/span&gt; &lt;span class="s"&gt;'self'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;script-src&lt;/span&gt; &lt;span class="s"&gt;'self'&lt;/span&gt; &lt;span class="s"&gt;'unsafe-inline'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;object-src&lt;/span&gt; &lt;span class="s"&gt;'none'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Security-Policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none';&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  X-Frame-Options
&lt;/h3&gt;

&lt;p&gt;This header controls whether your site can be embedded within an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;frame&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;applet&amp;gt;&lt;/code&gt;. This is crucial for preventing "clickjacking" attacks, where an attacker tricks a user into clicking on something different from what they perceive.&lt;/p&gt;

&lt;p&gt;Common values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DENY&lt;/code&gt;: The page cannot be displayed in a frame, regardless of the site attempting to do so.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SAMEORIGIN&lt;/code&gt;: The page can only be displayed in a frame on the same origin as the page itself.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ALLOW-FROM uri&lt;/code&gt;: The page can only be displayed in a frame on the specified origin. (This is deprecated and less reliable).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Checking with &lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the &lt;code&gt;X-Frame-Options&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_headers.c&amp;gt;
    Header always set X-Frame-Options "SAMEORIGIN"
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Frame-Options&lt;/span&gt; &lt;span class="s"&gt;"SAMEORIGIN"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Frame-Options&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SAMEORIGIN&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Referrer-Policy
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Referrer-Policy&lt;/code&gt; header controls how much referrer information (the URL of the page that linked to the current page) is sent with requests. Sensitive information can be leaked through the referrer header, especially when navigating from secure to non-secure pages, or between different sites.&lt;/p&gt;

&lt;p&gt;Common values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;no-referrer&lt;/code&gt;: No referrer information is sent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;no-referrer-when-downgrade&lt;/code&gt;: Referrer is sent only when the target scheme is more secure than the current one (e.g. HTTP to HTTPS).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;origin-when-cross-origin&lt;/code&gt;: Only send the origin (scheme, host, port) when the destination is cross-origin.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;strict-origin-when-cross-origin&lt;/code&gt;: Send the origin only when the destination is cross-origin, and send the full URL only when it's same-origin.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;same-origin&lt;/code&gt;: Referrer is sent only when the destination is same-origin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most sites, &lt;code&gt;strict-origin-when-cross-origin&lt;/code&gt; is a good balance between privacy and analytics functionality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checking with &lt;code&gt;curl&lt;/code&gt;&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the &lt;code&gt;Referrer-Policy&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Examples&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;IfModule mod_headers.c&amp;gt;
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
&amp;lt;/IfModule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;Referrer-Policy&lt;/span&gt; &lt;span class="s"&gt;"strict-origin-when-cross-origin"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cloudflare Workers&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fetch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Referrer-Policy&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;strict-origin-when-cross-origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By implementing these four headers, you're taking significant steps to secure your websites and protect your users. Regularly test your headers using tools like &lt;code&gt;curl&lt;/code&gt; or online security scanners to ensure they are configured correctly and consistently.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://sitevett.com" rel="noopener noreferrer"&gt;SiteVett&lt;/a&gt; checks this automatically as part of a free website QA scan with 60+ checks across security, SEO, content, performance, and more.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/scanner" rel="noopener noreferrer"&gt;Run a free scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/features" rel="noopener noreferrer"&gt;See all checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/sample-report" rel="noopener noreferrer"&gt;View a sample report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Is Your jQuery Version a Security Risk?</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Tue, 21 Apr 2026 10:00:26 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/is-your-jquery-version-a-security-risk-25kp</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/is-your-jquery-version-a-security-risk-25kp</guid>
      <description>&lt;h2&gt;
  
  
  Is Your jQuery Version a Security Risk?
&lt;/h2&gt;

&lt;p&gt;WordPress, by default, includes a version of jQuery. This is great for developers because it means we don't have to worry about manually enqueueing it for most projects. However, there's a common pitfall: many themes and plugins bundle their own copy of jQuery. If this bundled version is outdated, it can introduce serious security vulnerabilities. Specifically, jQuery versions prior to 3.5.0 are known to have cross-site scripting (XSS) vulnerabilities, identified by CVE-2020-11022 and CVE-2020-11023. These issues could allow an attacker to inject malicious code into your site.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to Check Your jQuery Version
&lt;/h3&gt;

&lt;p&gt;The first step is to determine which version of jQuery your website is actually using. The easiest way to do this is by inspecting the page source.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;View Page Source&lt;/strong&gt;: In your web browser, right-click anywhere on your website's frontend and select "View Page Source" or "Inspect Element".&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Search for jQuery&lt;/strong&gt;: Once the source code is displayed, search for "jquery". You're looking for a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag that loads the jQuery library. It will typically look something like this:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/wp-content/plugins/some-plugin/assets/js/jquery-1.12.4.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/wp-content/themes/your-theme/js/jquery-3.3.1.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The filename will clearly indicate the version. If you see a version number like &lt;code&gt;1.x.x&lt;/code&gt;, &lt;code&gt;2.x.x&lt;/code&gt;, or &lt;code&gt;3.0.0&lt;/code&gt; through &lt;code&gt;3.4.x&lt;/code&gt;, you are likely vulnerable. WordPress itself ships with a secure version of jQuery, typically loaded from &lt;code&gt;wp-includes/js/jquery/jquery.js&lt;/code&gt; or a similar path within the core WordPress files. If your site is only loading jQuery from this core path, you're probably fine. The problem arises when a theme or plugin loads its &lt;em&gt;own&lt;/em&gt; version, often an older one.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Fixing Vulnerable jQuery Versions
&lt;/h3&gt;

&lt;p&gt;Once you've identified an outdated jQuery version, you have a few practical options to address it.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Update Your Theme or Plugin
&lt;/h4&gt;

&lt;p&gt;The most straightforward solution is to update the theme or plugin that's bundling the vulnerable jQuery version. Developers are aware of these vulnerabilities and have likely released updates that use a secure, modern version of jQuery or have removed the bundled copy altogether.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Action&lt;/strong&gt;: Navigate to your WordPress dashboard, go to "Appearance" &amp;gt; "Themes" or "Plugins" &amp;gt; "Installed Plugins". Check for available updates for your active theme and any plugins. Apply them if they are available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If updating is not an immediate option, or if the theme/plugin developer hasn't provided a fix, you'll need to take a more direct approach.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Dequeue the Vulnerable Script
&lt;/h4&gt;

&lt;p&gt;WordPress provides functions to control how scripts are enqueued and dequeued. You can use &lt;code&gt;wp_dequeue_script&lt;/code&gt; to remove the problematic, bundled jQuery from being loaded and ensure that the secure version provided by WordPress is used instead.&lt;/p&gt;

&lt;p&gt;This is typically done in your theme's &lt;code&gt;functions.php&lt;/code&gt; file or within a custom plugin. You need to know the handle that the vulnerable script was registered with. Often, themes and plugins will register their jQuery with a distinct handle. If they don't, it can be trickier, but usually, the script path itself can help you infer potential handles.&lt;/p&gt;

&lt;p&gt;Here's an example of how you might dequeue a script. Let's assume the vulnerable script was registered with the handle &lt;code&gt;'old-jquery'&lt;/code&gt; and loaded from a path like &lt;code&gt;/wp-content/themes/my-theme/js/jquery-1.10.2.min.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="cd"&gt;/**
 * Dequeue vulnerable jQuery version and ensure WordPress core version is used.
 */&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;my_dequeue_vulnerable_jquery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Check if the script handle is registered.&lt;/span&gt;
    &lt;span class="c1"&gt;// The handle 'old-jquery' is an example; you'll need to find the actual handle.&lt;/span&gt;
    &lt;span class="c1"&gt;// If the handle is not known, you might need to inspect the source or plugin/theme code.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nf"&gt;wp_script_is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'old-jquery'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'registered'&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;wp_dequeue_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'old-jquery'&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Optionally, you can also de-register it to prevent it from being re-enqueued.&lt;/span&gt;
        &lt;span class="c1"&gt;// wp_deregister_script( 'old-jquery' );&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Ensure WordPress core jQuery is enqueued if it's not already.&lt;/span&gt;
    &lt;span class="c1"&gt;// This is generally handled automatically by WordPress, but can be explicit.&lt;/span&gt;
    &lt;span class="c1"&gt;// wp_enqueue_script( 'jquery' );&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;add_action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'wp_enqueue_scripts'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my_dequeue_vulnerable_jquery'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;999&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Finding the Script Handle&lt;/strong&gt;: This is the most challenging part of this method. If you can't find the handle by inspecting the theme/plugin's code directly, you might need to resort to some detective work. Sometimes the handle is close to the filename, or it's a common convention like &lt;code&gt;jquery-custom&lt;/code&gt; or the plugin slug. If all else fails, you might have to look for the &lt;code&gt;wp_enqueue_script()&lt;/code&gt; call within the theme or plugin's PHP files.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Migrate to Vanilla JavaScript
&lt;/h4&gt;

&lt;p&gt;For new development or significant refactors, consider migrating away from jQuery entirely and using modern, vanilla JavaScript. Modern browsers have excellent support for features that jQuery abstracted, and the performance benefits can be significant. This is a more involved process but eliminates the dependency on jQuery versions and their associated vulnerabilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Action&lt;/strong&gt;: Identify the jQuery-dependent functionality in your theme or plugin. Rewrite these functionalities using native JavaScript APIs. For example, replacing &lt;code&gt;$(selector).hide()&lt;/code&gt; with &lt;code&gt;document.querySelector(selector).style.display = 'none';&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By taking these steps, you can ensure your WordPress site is not compromised by outdated jQuery libraries, keeping your visitors and your data secure.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://sitevett.com" rel="noopener noreferrer"&gt;SiteVett&lt;/a&gt; checks this automatically as part of a free website QA scan with 60+ checks across security, SEO, content, performance, and more.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/scanner" rel="noopener noreferrer"&gt;Run a free scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/features" rel="noopener noreferrer"&gt;See all checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/sample-report" rel="noopener noreferrer"&gt;View a sample report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>javascript</category>
      <category>wordpress</category>
    </item>
    <item>
      <title>Using Sitevett, we scanned 100 agency websites. Here's what they miss.</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Fri, 10 Apr 2026 12:22:33 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/we-scanned-100-agency-websites-heres-what-they-miss-41in</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/we-scanned-100-agency-websites-heres-what-they-miss-41in</guid>
      <description>&lt;p&gt;We ran a full automated QA scan across 100 web design agency websites -- the companies that build sites for a living. Every scan covered 69 rules: AI vision checks, Lighthouse performance audits, WCAG accessibility analysis, SEO validation, security header inspection, content quality, and more. Up to 80 pages per site.&lt;/p&gt;

&lt;p&gt;27 sites were excluded because bot protection blocked the crawler, leaving &lt;strong&gt;73 sites with valid results&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The average score was &lt;strong&gt;69 out of 100&lt;/strong&gt;. The highest score in the entire set was 84. No agency site scored above 84. More than half scored below 70.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;See for yourself:&lt;/strong&gt; here are the full reports for the top and bottom scorers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Top 3:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/reports/d371e3fae322491d9632b736fc7cf06e.html" rel="noopener noreferrer"&gt;scnsoft.com -- 84/100 (80 pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/reports/3c20fa9b407d4c97963129c3b9667c53.html" rel="noopener noreferrer"&gt;rtcamp.com -- 83/100 (80 pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/reports/40e98e4b05784fada3bbcead59c5366c.html" rel="noopener noreferrer"&gt;ramotion.com -- 83/100 (80 pages)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Bottom 3:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/reports/60da6792aeb743debd221b72812cd066.html" rel="noopener noreferrer"&gt;anagrama.com -- 50/100 (81 pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/reports/b33b78e5ca9e4d409b1d0ae86d4edf46.html" rel="noopener noreferrer"&gt;portorocha.com -- 51/100 (58 pages)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/reports/5986037eb81844c1bb0dce98e0b6fd6a.html" rel="noopener noreferrer"&gt;growmodo.com -- 52/100 (80 pages)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The top 10 things agencies miss on their own websites
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Accessibility statement (79% failed)
&lt;/h3&gt;

&lt;p&gt;Nearly four in five agency sites have no accessibility statement. Some jurisdictions require one by law. Even where it's not legally mandated, it signals that the agency takes inclusive design seriously -- the kind of thing a prospective client notices.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Heading hierarchy (67% failed)
&lt;/h3&gt;

&lt;p&gt;Two thirds of sites have pages with multiple H1 tags or broken heading structure. This confuses screen readers and dilutes the SEO signal that tells Google what the page is about. Most of these are template issues -- a logo or site title wrapped in an H1 alongside the page's actual heading.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Missing meta descriptions (51% failed)
&lt;/h3&gt;

&lt;p&gt;Half the sites let Google generate their own search snippets. The result is usually the first sentence of body text, which rarely makes a compelling reason to click. A missing meta description is a missed opportunity on every single search result.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Color contrast (45% failed)
&lt;/h3&gt;

&lt;p&gt;Nearly half of all sites have text that fails WCAG AA contrast requirements (4.5:1 ratio). The most common offender: white text on bright brand colours. Even well-known brand palettes like WhatsApp green (1.98:1) and YouTube red (3.19:1) fail the threshold. Popularity does not mean accessible.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Security headers (44% failed)
&lt;/h3&gt;

&lt;p&gt;Missing CSP, X-Frame-Options, or Referrer-Policy headers. These are one-line server configurations that protect against clickjacking and XSS. HSTS adoption is better -- most sites have it. But the other three are often overlooked entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Open Graph tags (37% failed)
&lt;/h3&gt;

&lt;p&gt;More than a third of sites have no og:title, og:description, or og:image. When someone shares a link to the agency's site on LinkedIn or Slack, the preview shows a generic title and no image. For agencies that rely on referrals and word-of-mouth, this is leaving first impressions to chance.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Broken links (31% failed)
&lt;/h3&gt;

&lt;p&gt;Nearly a third of sites have at least one broken link -- a page that returns a 404, a link to a defunct partner, or a portfolio piece that's been taken down. Broken links erode trust and hurt SEO. They accumulate silently over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Missing alt text (30% failed)
&lt;/h3&gt;

&lt;p&gt;Three in ten sites have images without alt attributes. Alt text is the most basic accessibility requirement for images, and it's also how Google indexes image content. Portfolio-heavy agency sites are the worst offenders -- dozens of project screenshots with empty alt tags.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. Canonical tags (27% failed)
&lt;/h3&gt;

&lt;p&gt;Over a quarter of sites have pages without canonical tags, or with canonicals pointing to different URLs. Without them, search engines may treat URL variations (trailing slashes, query parameters, www vs non-www) as duplicate content.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. Privacy policy link (25% failed)
&lt;/h3&gt;

&lt;p&gt;One in four agency sites has no privacy policy link in the footer. Under GDPR and CCPA, this is a compliance gap. It's also one of the first things a privacy-conscious client will look for.&lt;/p&gt;




&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sites scanned&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Valid results (crawler not blocked)&lt;/td&gt;
&lt;td&gt;73&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average score&lt;/td&gt;
&lt;td&gt;69/100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Median score&lt;/td&gt;
&lt;td&gt;69/100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Highest score&lt;/td&gt;
&lt;td&gt;84/100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scored 70-84&lt;/td&gt;
&lt;td&gt;48%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scored 50-69&lt;/td&gt;
&lt;td&gt;52%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Below 50&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total checks run&lt;/td&gt;
&lt;td&gt;6,037&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What else showed up
&lt;/h2&gt;

&lt;p&gt;Beyond the top 10, some patterns stood out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;80% had grammar issues&lt;/strong&gt; flagged -- mostly minor (possessives, compound modifiers), but present.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;77% are missing Permissions-Policy headers&lt;/strong&gt; -- a newer security header that controls which browser APIs third-party scripts can access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;71% of sites have images without width/height attributes&lt;/strong&gt;, causing layout shift (poor Core Web Vitals CLS scores).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;66% have meta title issues&lt;/strong&gt; -- duplicates across pages, or titles that are too long/short for search results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;60% have generic anchor text&lt;/strong&gt; like "click here" or "read more" on internal links.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;These aren't amateur mistakes. These are professional web agencies -- companies that charge thousands to build and maintain websites. The issues they miss on their own sites are the same ones they miss on client sites.&lt;/p&gt;

&lt;p&gt;Most of these problems are invisible in a browser. A missing canonical tag doesn't show an error. A broken heading hierarchy looks fine on screen. A 1.98:1 contrast ratio is readable to most people in good lighting. These are the gaps that manual review doesn't catch.&lt;/p&gt;

&lt;p&gt;That's why we built &lt;a href="https://sitevett.com" rel="noopener noreferrer"&gt;SiteVett&lt;/a&gt;. One scan, 69 automated checks, a score out of 100, and a list of exactly what to fix. You can scan any site for free.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data from SiteVett's 100-site agency benchmark, April 2026. All sites scanned with AI vision checks enabled, up to 80 pages per site. 27 sites excluded due to bot protection blocking the crawler.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
      <category>security</category>
      <category>seo</category>
    </item>
    <item>
      <title>SSL Certificate Expiry: The Silent Downtime Bomb</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Wed, 01 Apr 2026 14:58:48 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/ssl-certificate-expiry-the-silent-downtime-bomb-2ghg</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/ssl-certificate-expiry-the-silent-downtime-bomb-2ghg</guid>
      <description>&lt;h2&gt;
  
  
  SSL Certificate Expiry: The Silent Downtime Bomb
&lt;/h2&gt;

&lt;p&gt;It’s a scenario every web developer and agency dreads. A client calls, frantic. Their website is down, or worse, showing a terrifying "Your connection is not private" warning. Visitors are gone. The cause, often, is a simple oversight: an expired SSL certificate. This isn't a catastrophic hack; it's a ticking time bomb with a predictable fuse.&lt;/p&gt;

&lt;p&gt;Ignoring SSL certificate expiry is like leaving your front door unlocked. It might be fine for a while, but eventually, someone will notice, and the consequences can be severe. For businesses relying on their website for revenue or customer interaction, this downtime translates directly into lost money and damaged reputation. Browsers are increasingly strict about security, and an expired certificate triggers immediate user distrust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking Your Certificate's Status
&lt;/h3&gt;

&lt;p&gt;Knowing when your certificates expire is the first line of defense. Thankfully, there are several straightforward ways to check.&lt;/p&gt;

&lt;p&gt;For a quick command-line check, &lt;code&gt;openssl s_client&lt;/code&gt; is a handy tool. Run it against your domain and port 443 (the standard HTTPS port).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; yourdomain.com:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; yourdomain.com &amp;lt; /dev/null 2&amp;gt;/dev/null | openssl x509 &lt;span class="nt"&gt;-noout&lt;/span&gt; &lt;span class="nt"&gt;-dates&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command pipes the connection output to another &lt;code&gt;openssl&lt;/code&gt; command that extracts just the "notBefore" and "notAfter" dates, showing you precisely when your certificate becomes valid and, crucially, when it expires.&lt;/p&gt;

&lt;p&gt;Alternatively, you can use your browser's developer tools. Navigate to your website, open the DevTools (usually F12), go to the "Security" tab, and click on the certificate information. This will often show you the expiry date directly.&lt;/p&gt;

&lt;p&gt;For a more automated approach, various online SSL checker tools exist. Websites like SSL Labs (ssllabs.com) provide comprehensive reports, including certificate expiry dates, alongside many other security metrics. These are excellent for quick, at-a-glance checks across multiple domains.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automating Renewal with Let's Encrypt
&lt;/h3&gt;

&lt;p&gt;The advent of free, automated certificates from Let's Encrypt has drastically reduced the manual burden of certificate management. Tools like &lt;code&gt;certbot&lt;/code&gt; are designed to automate the entire process, including renewal.&lt;/p&gt;

&lt;p&gt;If you're using &lt;code&gt;certbot&lt;/code&gt; with Apache or Nginx, the renewal process is usually handled automatically by a cron job or systemd timer that runs the &lt;code&gt;certbot renew&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;For example, a common &lt;code&gt;certbot&lt;/code&gt; cron job might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0 * * * certbot renew --quiet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs the renewal check every day at midnight. &lt;code&gt;certbot renew&lt;/code&gt; checks all installed certificates and renews any that are due for expiration within the next 30 days.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Common Pitfall: Server Reloads
&lt;/h3&gt;

&lt;p&gt;Here’s where many systems stumble, even with automated renewals. Let’s Encrypt and &lt;code&gt;certbot&lt;/code&gt; are excellent at obtaining and renewing certificates. However, a certificate is only useful if the web server is aware of the new one. Many automated setups forget to tell the web server to reload its configuration to pick up the renewed certificate.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;certbot&lt;/code&gt; renews a certificate but your web server (like Nginx or Apache) hasn't been told to reload its SSL configuration, visitors will continue to see the old, soon-to-expire certificate until the server is manually restarted or reloaded.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;certbot&lt;/code&gt; can often handle this for you if configured correctly. When you initially set up &lt;code&gt;certbot&lt;/code&gt; with a web server plugin (e.g., &lt;code&gt;certbot --nginx&lt;/code&gt; or &lt;code&gt;certbot --apache&lt;/code&gt;), it typically adds a "deploy hook" or post-renewal hook. This hook is a command that runs &lt;em&gt;after&lt;/em&gt; a certificate is successfully renewed. The common command for Nginx is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for Apache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl reload apache2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're not using a &lt;code&gt;certbot&lt;/code&gt; plugin that handles this automatically, or if you're managing certificates manually, you &lt;em&gt;must&lt;/em&gt; ensure your server configuration is reloaded after a certificate renewal. This is a critical step that is frequently missed, leading to the silent expiry bomb. Regularly testing your automated renewal process by forcing a renewal (e.g., &lt;code&gt;certbot renew --force-renewal&lt;/code&gt;) and then checking your site is a good practice to ensure your hooks are working as expected.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://sitevett.com" rel="noopener noreferrer"&gt;SiteVett&lt;/a&gt; checks this automatically as part of a free website QA scan with 60+ checks across security, SEO, content, performance, and more.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/scanner" rel="noopener noreferrer"&gt;Run a free scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/features" rel="noopener noreferrer"&gt;See all checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/sample-report" rel="noopener noreferrer"&gt;View a sample report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>ssl</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your .env File Might Be Public Right Now</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Wed, 01 Apr 2026 14:45:27 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/your-env-file-might-be-public-right-now-238</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/your-env-file-might-be-public-right-now-238</guid>
      <description>&lt;p&gt;Your .env File Might Be Public Right Now&lt;/p&gt;

&lt;p&gt;Many of us use .env files to manage environment-specific configurations, especially in WordPress development. These files often contain sensitive credentials for databases, API keys, and other critical services. The problem is, these files can, and often are, inadvertently exposed on production servers. This isn't just a theoretical risk; it's a common oversight that can have severe consequences.&lt;/p&gt;

&lt;h3&gt;
  
  
  The .env Exposure Vector
&lt;/h3&gt;

&lt;p&gt;When you deploy a WordPress site, especially if you're not careful about what you include in your deployment package or what gets pushed to the webroot, your .env file can end up accessible to anyone with a browser. This is usually because it's accidentally copied into the public directory alongside your WordPress core files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking for Exposure with curl
&lt;/h3&gt;

&lt;p&gt;The simplest way to check if your .env file is exposed is to try fetching it directly using &lt;code&gt;curl&lt;/code&gt;. If your web server is configured to serve it, you'll get its contents.&lt;/p&gt;

&lt;p&gt;To check for &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; yourdomain.com/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-I&lt;/code&gt; flag tells &lt;code&gt;curl&lt;/code&gt; to fetch only the headers. Look for a &lt;code&gt;200 OK&lt;/code&gt; status code. If you see that, you can then try fetching the content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl yourdomain.com/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get a response that looks like a &lt;code&gt;.env&lt;/code&gt; file (e.g., &lt;code&gt;DB_NAME=your_db_name&lt;/code&gt;), it's exposed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Common Leaks
&lt;/h3&gt;

&lt;p&gt;It's not just &lt;code&gt;.env&lt;/code&gt; files. Developers also sometimes leave other sensitive files accessible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.git/HEAD&lt;/code&gt;&lt;/strong&gt;: If your &lt;code&gt;.git&lt;/code&gt; directory is accidentally deployed to the webroot, fetching &lt;code&gt;.git/HEAD&lt;/code&gt; might reveal the current branch you're on. This gives an attacker insight into your development workflow and potential vulnerabilities associated with older branches.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; yourdomain.com/.git/HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;wp-config.php~&lt;/code&gt;&lt;/strong&gt;: Many editors create backup files for configuration files. If these backups are not excluded from deployment and end up in the webroot, they can leak your database credentials.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; yourdomain.com/wp-config.php~
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;debug.log&lt;/code&gt;&lt;/strong&gt;: While not as critical for direct credential theft, leaving debug logs accessible can reveal internal workings, file paths, and potentially error messages that hint at other system vulnerabilities.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; yourdomain.com/wp-content/debug.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Real Risk: Credential Theft and Source Code Exposure
&lt;/h3&gt;

&lt;p&gt;The immediate and most significant risk is &lt;strong&gt;credential theft&lt;/strong&gt;. A publicly accessible &lt;code&gt;.env&lt;/code&gt; file, or a backup of &lt;code&gt;wp-config.php&lt;/code&gt;, often contains your database username, password, database name, and sometimes API keys for third-party services. With these credentials, an attacker can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Access and tamper with your database, potentially stealing user data, injecting malicious content, or deleting everything.&lt;/li&gt;
&lt;li&gt;  Gain access to your WordPress admin panel through brute-force attacks on stolen credentials.&lt;/li&gt;
&lt;li&gt;  Use your API keys to incur costs on your behalf or access sensitive information on integrated services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exposure of &lt;code&gt;.git&lt;/code&gt; related files can indirectly aid attackers by revealing branch names, potentially pointing to unpatched vulnerabilities in older code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing the Exposure: Deny Rules and Webroot Exclusion
&lt;/h3&gt;

&lt;p&gt;The fix involves two primary strategies: preventing direct web access and ensuring sensitive files are never in the webroot.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Server Configuration Deny Rules
&lt;/h4&gt;

&lt;p&gt;The most robust solution is to configure your web server to explicitly deny access to these files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Apache (&lt;code&gt;.htaccess&lt;/code&gt;):&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add these lines to your &lt;code&gt;.htaccess&lt;/code&gt; file in the webroot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nl"&gt;FilesMatch&lt;/span&gt;&lt;span class="sr"&gt; "^\.(env|\.git/HEAD|wp-config\.php~|debug\.log)$"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;Order&lt;/span&gt; allow,deny
    &lt;span class="nc"&gt;Deny&lt;/span&gt; &lt;span class="ss"&gt;from&lt;/span&gt; &lt;span class="ss"&gt;all&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;FilesMatch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For Nginx:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add these rules to your server block configuration for your site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/(.env|&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.git/HEAD|wp-config&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.php~|debug&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.log)&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use a subdirectory for logs, like &lt;code&gt;wp-content/debug.log&lt;/code&gt;, you'll need to adjust the Nginx location accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/wp-content/(debug&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="s"&gt;.log)&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These rules tell the web server that if any request matches these filenames, it should immediately return a forbidden error instead of serving the file's content.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Remove Backups and Sensitive Files from Webroot
&lt;/h4&gt;

&lt;p&gt;Beyond deny rules, the best practice is to ensure these files are never copied into your webroot in the first place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;.env&lt;/code&gt; files&lt;/strong&gt;: These should &lt;em&gt;always&lt;/em&gt; reside in the directory &lt;em&gt;above&lt;/em&gt; your webroot. For example, if your webroot is &lt;code&gt;/var/www/html/yourdomain.com/public_html&lt;/code&gt;, your &lt;code&gt;.env&lt;/code&gt; file should be at &lt;code&gt;/var/www/html/yourdomain.com/.env&lt;/code&gt;. Your application, typically via a framework or WordPress plugin, will then read this file.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;.git&lt;/code&gt; directories&lt;/strong&gt;: When deploying, ensure you're not deploying the entire &lt;code&gt;.git&lt;/code&gt; directory. Use deployment tools that only copy necessary application files. Git hooks or build scripts can be used to clean up &lt;code&gt;.git&lt;/code&gt; artifacts before deployment.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Editor backups&lt;/strong&gt;: Configure your text editor or IDE to not save backup files in the project directory, or ensure they are excluded from your deployment process.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Debug logs&lt;/strong&gt;: Configure WordPress to log debug information to a file outside the webroot, if possible, or at least ensure the log file itself is protected by server configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By implementing these checks and preventative measures, you significantly reduce the attack surface for your WordPress sites and protect sensitive credentials and code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://sitevett.com" rel="noopener noreferrer"&gt;SiteVett&lt;/a&gt; checks this automatically as part of a free website QA scan with 60+ checks across security, SEO, content, performance, and more.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/scanner" rel="noopener noreferrer"&gt;Run a free scan&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/features" rel="noopener noreferrer"&gt;See all checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sitevett.com/sample-report" rel="noopener noreferrer"&gt;View a sample report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>wordpress</category>
      <category>devops</category>
    </item>
    <item>
      <title>Is Your Site Redirecting HTTP to HTTPS? Here's How to Check</title>
      <dc:creator>Jonathan Pimperton</dc:creator>
      <pubDate>Wed, 01 Apr 2026 14:03:43 +0000</pubDate>
      <link>https://dev.to/jonathan_pimperton_971ac1/is-your-site-redirecting-http-to-https-heres-how-to-check-3ocn</link>
      <guid>https://dev.to/jonathan_pimperton_971ac1/is-your-site-redirecting-http-to-https-heres-how-to-check-3ocn</guid>
      <description>&lt;h2&gt;
  
  
  Is Your Site Redirecting HTTP to HTTPS? Here's How to Check
&lt;/h2&gt;

&lt;p&gt;You've installed an SSL certificate, great. But is traffic automatically being sent to the secure HTTPS version of your site? A common oversight is having the certificate in place but failing to enforce the redirect from HTTP. This leaves visitors hitting the insecure version of your domain, which is bad for SEO, user trust, and data security. Let's cover how to check this and fix it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Checking with &lt;code&gt;curl&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The command-line tool &lt;code&gt;curl&lt;/code&gt; is your friend here. It allows us to make raw HTTP requests and inspect the responses. We're looking for a &lt;code&gt;301 Moved Permanently&lt;/code&gt; or &lt;code&gt;302 Found&lt;/code&gt; redirect status code.&lt;/p&gt;

&lt;p&gt;To test the HTTP to HTTPS redirect, open your terminal and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;yourdomain.com&lt;/code&gt; with your actual domain. The &lt;code&gt;-I&lt;/code&gt; flag tells &lt;code&gt;curl&lt;/code&gt; to fetch only the headers, not the body of the response.&lt;/p&gt;

&lt;p&gt;In the output, you'll want to see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;301&lt;/span&gt; &lt;span class="ne"&gt;Moved Permanently&lt;/span&gt;
&lt;span class="na"&gt;Location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://yourdomain.com/&lt;/span&gt;
&lt;span class="s"&gt;... other headers ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see &lt;code&gt;HTTP/1.1 200 OK&lt;/code&gt;, it means your site is responding to the HTTP request directly without a redirect.&lt;/p&gt;

&lt;p&gt;Also, test both &lt;code&gt;www&lt;/code&gt; and non-&lt;code&gt;www&lt;/code&gt; versions of your domain, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-I&lt;/span&gt; http://www.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing Redirects
&lt;/h3&gt;

&lt;p&gt;The method for setting up the redirect depends on your server environment or hosting provider.&lt;/p&gt;

&lt;h4&gt;
  
  
  Apache &lt;code&gt;.htaccess&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;For most shared hosting or VPS setups running Apache, you'll add rules to your &lt;code&gt;.htaccess&lt;/code&gt; file, typically located in the public root directory of your website.&lt;/p&gt;

&lt;p&gt;To redirect all HTTP traffic to HTTPS, add the following lines to your &lt;code&gt;.htaccess&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;RewriteEngine&lt;/span&gt; &lt;span class="ss"&gt;On&lt;/span&gt;
&lt;span class="nc"&gt;RewriteCond&lt;/span&gt; %{HTTPS} &lt;span class="ss"&gt;off&lt;/span&gt;
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration checks if the request is not already using HTTPS. If it's not, it issues a &lt;code&gt;301&lt;/code&gt; redirect to the same host and URI, but with the &lt;code&gt;https://&lt;/code&gt; protocol. The &lt;code&gt;[L]&lt;/code&gt; flag ensures this is the last rule processed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Nginx
&lt;/h4&gt;

&lt;p&gt;If you're using Nginx, you'll modify your server block configuration. Locate the server block that handles your HTTP traffic (usually port 80) and add a redirect.&lt;/p&gt;

&lt;p&gt;Here's a common Nginx configuration for redirecting HTTP to HTTPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;yourdomain.com&lt;/span&gt; &lt;span class="s"&gt;www.yourdomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$host$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;yourdomain.com&lt;/span&gt; &lt;span class="s"&gt;www.yourdomain.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/yourdomain.com/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# Example path&lt;/span&gt;
    &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/yourdomain.com/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# Example path&lt;/span&gt;
    &lt;span class="c1"&gt;# ... other SSL configuration and your site's root directives ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first server block listens on port 80, matches your domain names, and redirects all requests to the HTTPS version using a &lt;code&gt;301&lt;/code&gt; status code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cloudflare
&lt;/h4&gt;

&lt;p&gt;If you use Cloudflare, it simplifies this process significantly. Cloudflare has a dedicated SSL/TLS setting called "Always Use HTTPS".&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Log in to your Cloudflare dashboard.&lt;/li&gt;
&lt;li&gt; Select your website.&lt;/li&gt;
&lt;li&gt; Navigate to the "SSL/TLS" section.&lt;/li&gt;
&lt;li&gt; Under "Edge Certificates," find "Always Use HTTPS" and toggle it to "On."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This setting tells Cloudflare to automatically issue &lt;code&gt;301&lt;/code&gt; redirects for any requests that come in over HTTP to the equivalent HTTPS URL.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Pitfalls
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Redirect Loops:&lt;/strong&gt; This is a common headache. It happens when multiple redirects are configured and they send traffic back and forth. For instance, if your server is configured to redirect HTTP to HTTPS, and then Cloudflare is also set to "Always Use HTTPS," you might encounter a loop. Ensure only one mechanism is actively forcing the HTTPS redirect. Check your &lt;code&gt;.htaccess&lt;/code&gt;, Nginx config, and Cloudflare settings carefully. If you use a WordPress plugin for SSL, make sure it's not conflicting with server-level redirects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixed &lt;code&gt;www&lt;/code&gt; and Non-&lt;code&gt;www&lt;/code&gt;:&lt;/strong&gt; Decide whether you want your primary domain to be &lt;code&gt;www.yourdomain.com&lt;/code&gt; or &lt;code&gt;yourdomain.com&lt;/code&gt; and stick to it. All your redirects should enforce this canonical version. For example, if your preferred version is &lt;code&gt;www.yourdomain.com&lt;/code&gt;, your HTTP to HTTPS redirect should point to &lt;code&gt;https://www.yourdomain.com&lt;/code&gt;, and you should also have a separate redirect for &lt;code&gt;https://yourdomain.com&lt;/code&gt; to &lt;code&gt;https://www.yourdomain.com&lt;/code&gt; (and vice versa if &lt;code&gt;yourdomain.com&lt;/code&gt; is preferred).&lt;/p&gt;

&lt;p&gt;Your &lt;code&gt;.htaccess&lt;/code&gt; file can handle this by adding rules for the non-preferred version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="c"&gt;# Redirect non-www to www&lt;/span&gt;
&lt;span class="nc"&gt;RewriteEngine&lt;/span&gt; &lt;span class="ss"&gt;On&lt;/span&gt;
&lt;span class="nc"&gt;RewriteCond&lt;/span&gt; %{HTTP_HOST} ^yourdomain.com$ [NC]
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^(.*)$ http://www.yourdomain.com/$1 [L,R=301]

&lt;span class="c"&gt;# Then redirect HTTP to HTTPS for both&lt;/span&gt;
&lt;span class="nc"&gt;RewriteCond&lt;/span&gt; %{HTTPS} &lt;span class="ss"&gt;off&lt;/span&gt;
&lt;span class="nc"&gt;RewriteRule&lt;/span&gt; ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The order here is important. You generally want to resolve the &lt;code&gt;www&lt;/code&gt; preference first, then enforce HTTPS.&lt;/p&gt;

&lt;p&gt;SiteVett can automatically check this for you as part of a free website QA scan.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>https</category>
      <category>wordpress</category>
    </item>
  </channel>
</rss>
