<?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: Bug Circuit</title>
    <description>The latest articles on DEV Community by Bug Circuit (@bugcircuit).</description>
    <link>https://dev.to/bugcircuit</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4055584%2Ff7936355-aba9-4105-93b4-28afbc45ea63.png</url>
      <title>DEV Community: Bug Circuit</title>
      <link>https://dev.to/bugcircuit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bugcircuit"/>
    <language>en</language>
    <item>
      <title>Best Free WordPress 2FA Plugin &amp; Setup Guide</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Tue, 08 Sep 2026 23:13:08 +0000</pubDate>
      <link>https://dev.to/bugcircuit/best-free-wordpress-2fa-plugin-setup-guide-3naa</link>
      <guid>https://dev.to/bugcircuit/best-free-wordpress-2fa-plugin-setup-guide-3naa</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/best-free-wordpress-2fa-plugin-setup-guide" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The best way to add 2FA to WordPress is a free, purpose-built plugin — the community-maintained "Two-Factor" plugin or Melapress's "WP 2FA" — set up to offer both an authenticator app &lt;em&gt;and&lt;/em&gt; a no-app fallback like email codes or printed backup codes, so every staff member can actually use it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for you if someone (a client, a security audit, or your own gut) told you to "just turn on 2FA" and you're not sure which plugin to trust, whether you need a fancy authenticator app, or how to set it up without locking your bookkeeper or shop manager out of the site. By the end you'll have a plugin picked, a login protected in under 10 minutes, and a backup option for people who don't want to install anything on their phone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 2FA actually does (in plain English)
&lt;/h2&gt;

&lt;p&gt;Two-factor authentication (2FA) means logging in needs two things: something you know (your password) and something you have (a code from your phone, an email, or a physical key). If a hacker steals or guesses your password — which happens constantly through phishing emails and reused passwords from other data breaches — 2FA stops them cold because they don't have the second piece.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cisa.gov/secure-our-world/turn-on-multifactor-authentication" rel="noopener noreferrer"&gt;CISA&lt;/a&gt;, the U.S. government's cybersecurity agency, and &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Multifactor_Authentication_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP&lt;/a&gt;, the nonprofit that writes the standard reference guides for web security, both list multi-factor authentication as one of the highest-value, lowest-cost defenses any website can add. Neither claims it makes a site "unhackable" — it doesn't stop a vulnerable plugin from being exploited or a server from being misconfigured — but it closes off the single most common way WordPress admin accounts get taken over: a stolen or guessed password.&lt;/p&gt;

&lt;h2&gt;
  
  
  The best free WordPress 2FA plugins
&lt;/h2&gt;

&lt;p&gt;You don't need a paid tool to do this properly. Here's how the three most-installed free options compare:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plugin&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Authenticator app (TOTP)&lt;/th&gt;
&lt;th&gt;No-app option&lt;/th&gt;
&lt;th&gt;Enforce for other users&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Two-Factor&lt;/strong&gt; (WordPress core contributor team)&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes — email code, printed backup codes&lt;/td&gt;
&lt;td&gt;Basic, per-user opt-in&lt;/td&gt;
&lt;td&gt;Simplest setup, zero upsells, built by the people who maintain WordPress core&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;WP 2FA&lt;/strong&gt; (Melapress)&lt;/td&gt;
&lt;td&gt;Free (Pro adds SMS/Duo/policy reporting)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Backup codes&lt;/td&gt;
&lt;td&gt;Yes — can force specific roles (e.g., all Editors and Admins) to set it up within a grace period&lt;/td&gt;
&lt;td&gt;Agencies and site owners managing several staff logins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wordfence Login Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Backup codes&lt;/td&gt;
&lt;td&gt;Yes — can require it per role&lt;/td&gt;
&lt;td&gt;Sites already running the Wordfence firewall plugin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three are actively maintained, have no ads, and are available directly from the official WordPress plugin directory — always install from there or your dashboard's Plugins → Add New search, never from a random download link.&lt;/p&gt;

&lt;p&gt;If you're picking one thing: install &lt;strong&gt;Two-Factor&lt;/strong&gt; for a single-admin site, or &lt;strong&gt;WP 2FA&lt;/strong&gt; if you have several staff accounts and want to force everyone to set it up rather than hoping they will.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add two-factor authentication to WordPress (step by step)
&lt;/h2&gt;

&lt;p&gt;Using the &lt;strong&gt;Two-Factor&lt;/strong&gt; plugin as the example — the steps are nearly identical in WP 2FA and Wordfence Login Security:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your WordPress dashboard, go to &lt;strong&gt;Plugins → Add New Plugin&lt;/strong&gt;, search "Two-Factor," and click &lt;strong&gt;Install Now&lt;/strong&gt;, then &lt;strong&gt;Activate&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Users → Profile&lt;/strong&gt; (or &lt;strong&gt;Users → All Users&lt;/strong&gt; and edit a specific person's account).&lt;/li&gt;
&lt;li&gt;Scroll to the &lt;strong&gt;Two-Factor Options&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Pick a primary method:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authenticator App (TOTP)&lt;/strong&gt; — scan the QR code with Google Authenticator, Authy, or Apple's built-in Passwords app, then enter the 6-digit code it shows to confirm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email&lt;/strong&gt; — codes are sent to the account's email address at login; no app needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup Verification Codes&lt;/strong&gt; — a set of one-time codes you print or save somewhere safe, for when you're offline or your phone is dead.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Update Profile&lt;/strong&gt; to save.&lt;/li&gt;
&lt;li&gt;Log out and log back in to confirm the second step actually appears — don't skip this test.&lt;/li&gt;
&lt;li&gt;Repeat for every account with Administrator or Editor access. A site is only as protected as its least-secured login.&lt;/li&gt;
&lt;li&gt;If you're using WP 2FA instead, go to &lt;strong&gt;WP 2FA → Settings → 2FA Policy&lt;/strong&gt; and set which roles must enable it and how many days they have (7 is reasonable) — the plugin will nag them with an on-screen notice until they comply.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Want to check your login page's other defenses at the same time? Run it through our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; — it flags exposed login pages, missing security headers, and other quick wins alongside 2FA.&lt;/p&gt;

&lt;h2&gt;
  
  
  2FA without an authenticator app: real options for non-technical staff
&lt;/h2&gt;

&lt;p&gt;Not everyone wants to install Google Authenticator, and that's fine — it isn't the only valid form of 2FA:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email one-time codes.&lt;/strong&gt; The plugin emails a 6-digit code at login. Nothing to install; works on any device that can check email. Slightly weaker than an app (if someone's email is also compromised, this layer is bypassed too), but far better than a password alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup/recovery codes.&lt;/strong&gt; A printed list of one-time-use codes, generated once and kept in a drawer or password manager. Good as a fallback for anyone, not just a primary method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Passkeys or security keys (WebAuthn).&lt;/strong&gt; Newer and app-free — the person taps a fingerprint reader, Face ID, or a physical USB key (like a YubiKey) instead of typing a code. The Two-Factor plugin supports FIDO U2F/WebAuthn keys if you want to go this route later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SMS text codes.&lt;/strong&gt; Some paid add-ons offer this. It works without an app, but SMS can be intercepted via SIM-swapping, so OWASP specifically recommends against relying on it as your only method — treat it as a last resort, not a first choice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small team where one person genuinely won't use an app, email-based 2FA on the Two-Factor plugin is the pragmatic answer: it takes zero setup on their end beyond clicking "yes, that's my code."&lt;/p&gt;

&lt;h2&gt;
  
  
  Checklist: is your 2FA setup actually protecting you?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] 2FA is enabled on &lt;strong&gt;every&lt;/strong&gt; Administrator and Editor account, not just the main owner login&lt;/li&gt;
&lt;li&gt;[ ] At least one backup method (backup codes or email) is set up per person, so nobody gets permanently locked out&lt;/li&gt;
&lt;li&gt;[ ] You tested logging out and back in to confirm the code prompt actually shows up&lt;/li&gt;
&lt;li&gt;[ ] Your WordPress admin username isn't literally "admin" (a leftover default that pairs badly with any login weakness)&lt;/li&gt;
&lt;li&gt;[ ] You're still using unique, strong passwords — 2FA is a second layer, not a replacement for &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;good password hygiene&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Security headers and other basic hardening are in place — check with our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers tool&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What 2FA won't fix
&lt;/h2&gt;

&lt;p&gt;2FA protects the login form. It does nothing for a vulnerable plugin, an outdated theme, a leaked database, or a misconfigured file permission — the kinds of issues that show up in most real WordPress compromises. If an audit or a client security questionnaire told you to "add 2FA," treat it as one item on a longer list, not the whole job. A proper site review looks at plugins, user roles, backups, and server configuration too — the difference between that kind of manual check and an automated scanner is explained in our guide to &lt;a href="https://bugcircuit.com/guides/manual-vs-automated-penetration-testing" rel="noopener noreferrer"&gt;manual vs. automated penetration testing&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install a free, official plugin — &lt;strong&gt;Two-Factor&lt;/strong&gt; for simplicity, &lt;strong&gt;WP 2FA&lt;/strong&gt; if you need to enforce it across staff — directly from the WordPress plugin directory.&lt;/li&gt;
&lt;li&gt;You don't need an authenticator app: email codes and printed backup codes are legitimate no-app 2FA options for less technical team members.&lt;/li&gt;
&lt;li&gt;Turn it on for every Admin and Editor account, not just yours, and always set up a backup method so no one gets locked out.&lt;/li&gt;
&lt;li&gt;2FA stops stolen or guessed passwords from being enough to break in, but it doesn't patch vulnerable plugins or fix server misconfigurations — it's one layer, not the whole defense.&lt;/li&gt;
&lt;li&gt;Avoid SMS-only 2FA as your primary method if you have a choice; it's better than nothing but weaker than an app, email, or security key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2FA is a genuinely good half-hour of work, and now you can do it yourself for free. If you want to know what else on your site actually needs fixing — plugins, headers, exposed files, the stuff a checklist alone won't catch — a real person can manually audit your whole site for $49 and hand you a plain-English report with exact fixes. See what's included on our &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;, no pressure either way.&lt;/p&gt;

</description>
      <category>wordpresssecurity</category>
      <category>2fa</category>
      <category>twofactorauthentication</category>
      <category>wordpressplugins</category>
    </item>
    <item>
      <title>Stop WordPress Login Brute-Force Attacks</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Sun, 06 Sep 2026 17:13:55 +0000</pubDate>
      <link>https://dev.to/bugcircuit/stop-wordpress-login-brute-force-attacks-56ei</link>
      <guid>https://dev.to/bugcircuit/stop-wordpress-login-brute-force-attacks-56ei</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/stop-wordpress-login-brute-force-attacks" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fastest fix is to install a login-limiting plugin (like Limit Login Attempts Reloaded) set to lock out an IP after 3-5 failed tries, then add a firewall or &lt;code&gt;.htaccess&lt;/code&gt; rule to block the worst offending IPs outright.&lt;/strong&gt; That stops the automated password-guessing script without you touching a single line of PHP.&lt;/p&gt;

&lt;p&gt;This guide is for WordPress site owners who are getting a stream of "failed login" emails, noticed &lt;code&gt;wp-login.php&lt;/code&gt; in their server logs getting hammered, or just want to lock the front door before it becomes a problem. By the end you'll know exactly which setting to change, which plugin to install, and how to tell WordPress to stop even answering the door for bots.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to tell it's actually a brute-force attack
&lt;/h2&gt;

&lt;p&gt;A brute-force attack is simply a script trying username/password combinations over and over, fast, hoping one works. You'll usually spot it through one or more of these signs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeated "failed login attempt" emails, often several a minute, sometimes for usernames like &lt;code&gt;admin&lt;/code&gt;, &lt;code&gt;administrator&lt;/code&gt;, or your site name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/wp-login.php&lt;/code&gt; or &lt;code&gt;/xmlrpc.php&lt;/code&gt; showing up dozens or hundreds of times in your server's access log within a short window, often from different IPs.&lt;/li&gt;
&lt;li&gt;The admin login page feels slow to load, or your host's CPU/resource usage graph spikes for no reason you can explain.&lt;/li&gt;
&lt;li&gt;A hosting or security-plugin alert naming "brute force" or "credential stuffing" (the same technique, but using stolen username/password pairs instead of random guesses — &lt;a href="https://owasp.org/www-community/attacks/Brute_force_attack" rel="noopener noreferrer"&gt;OWASP explains the distinction&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not sure whether what you're seeing is normal background noise or a real attack, our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; will scan for exposed login endpoints and obvious weaknesses at no cost — no card, no login required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why WordPress logins get targeted so often
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;wp-login.php&lt;/code&gt; is at a predictable URL on every default WordPress install, and &lt;code&gt;xmlrpc.php&lt;/code&gt; (WordPress's legacy remote-publishing API) can be abused to test hundreds of password guesses in a single HTTP request. Automated bots crawl the web for exactly these two paths and throw lists of common passwords at them — this is listed by OWASP as one of the &lt;a href="https://owasp.org/www-project-automated-threats-to-web-applications/" rel="noopener noreferrer"&gt;Automated Threats to Web Applications&lt;/a&gt; (Credential Cracking, OAT-007). It's not personal, and it doesn't mean your site was specifically chosen — it's the same script hitting millions of sites, yours included, because the door is in the same place on every WordPress install.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Limit login attempts (do this first)
&lt;/h2&gt;

&lt;p&gt;This is the single highest-value fix, and it takes about ten minutes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In your WordPress dashboard, go to &lt;strong&gt;Plugins → Add New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Search for and install &lt;strong&gt;Limit Login Attempts Reloaded&lt;/strong&gt; (a free, actively maintained plugin — see its &lt;a href="https://wordpress.org/plugins/limit-login-attempts-reloaded/" rel="noopener noreferrer"&gt;wordpress.org listing&lt;/a&gt;). WP Cerber and Wordfence's brute-force protection also work well if you want a plugin that bundles other security features.&lt;/li&gt;
&lt;li&gt;Activate it, then go to &lt;strong&gt;Settings → Limit Login Attempts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Allowed retries:&lt;/strong&gt; 3-4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lockout time:&lt;/strong&gt; 20-60 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increase lockout after repeated lockouts:&lt;/strong&gt; on (this turns short bans into long ones for persistent attackers)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Turn on email notifications so you get one summary alert per lockout period, not one per attempt.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This alone won't stop determined attackers, but it kills the noise from unsophisticated bots almost immediately and buys you time to add the stronger layers below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Turn on two-factor authentication
&lt;/h2&gt;

&lt;p&gt;Even a perfectly guessed password is useless to an attacker if they also need a rotating six-digit code from your phone. The &lt;a href="https://www.cisa.gov/MFA" rel="noopener noreferrer"&gt;Cybersecurity and Infrastructure Security Agency (CISA) recommends multi-factor authentication&lt;/a&gt; as one of the highest-impact, lowest-cost defenses against account takeover, and it fully neutralizes brute-force attacks on your admin account specifically.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install &lt;strong&gt;Wordfence&lt;/strong&gt; or &lt;strong&gt;WP 2FA&lt;/strong&gt; (both free).&lt;/li&gt;
&lt;li&gt;Require it for every account with an Administrator or Editor role — attackers don't need your account, just any account with publishing or plugin access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Block the attackers, not just the attempts
&lt;/h2&gt;

&lt;p&gt;Limiting attempts slows a script down; blocking its IP address stops it cold. You have three realistic options, in order of effort:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Effort&lt;/th&gt;
&lt;th&gt;Blocks attacker before WordPress loads?&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plugin lockout list (from Step 1)&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;No — WordPress still processes each request&lt;/td&gt;
&lt;td&gt;Small sites, low attack volume&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.htaccess&lt;/code&gt; deny rule for repeat-offender IPs&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Sites on Apache with a fixed list of bad IPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Application Firewall (Cloudflare, Sucuri, host-level WAF)&lt;/td&gt;
&lt;td&gt;Low-Medium&lt;/td&gt;
&lt;td&gt;Yes, at the network edge&lt;/td&gt;
&lt;td&gt;Any site getting sustained or shifting-IP attacks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;To block a specific IP via &lt;code&gt;.htaccess&lt;/code&gt;&lt;/strong&gt; (place near the top of the file in your site root):&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;RequireAll&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="nc"&gt;Require&lt;/span&gt; &lt;span class="ss"&gt;all&lt;/span&gt; granted
    &lt;span class="nc"&gt;Require&lt;/span&gt; not ip 203.0.113.45
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;RequireAll&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;Replace &lt;code&gt;203.0.113.45&lt;/code&gt; with the offending IP from your logs. Repeat the &lt;code&gt;Require not ip&lt;/code&gt; line for each address.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For a firewall-level fix&lt;/strong&gt; (recommended if attacks are ongoing rather than a one-off), turn on a WAF like Cloudflare's free tier or your host's built-in firewall, and add a rate-limiting rule for &lt;code&gt;/wp-login.php&lt;/code&gt; and &lt;code&gt;/xmlrpc.php&lt;/code&gt; — e.g., "block for 1 hour if more than 5 requests to these paths in 1 minute from the same IP." This stops the request before it ever reaches your server, which also saves you hosting resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Reduce what attackers can even reach
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Disable XML-RPC&lt;/strong&gt; if you don't use the WordPress mobile app or Jetpack (which rely on it). Most security plugins have a one-click toggle; otherwise your host or a plugin like Disable XML-RPC can block the endpoint entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change the login URL&lt;/strong&gt; away from the default &lt;code&gt;/wp-login.php&lt;/code&gt; using a plugin like WPS Hide Login. This isn't real security on its own (it's "security through obscurity"), but it removes your site from the pool of URLs that generic bots scan automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restrict wp-admin by IP&lt;/strong&gt; if you or your team always log in from the same office or VPN IP — add an IP allowlist at the server or firewall level.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What not to rely on
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A "strong password" alone.&lt;/strong&gt; It helps, but a brute-force script doesn't get tired — pair it with 2FA and a lockout policy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Renaming the login URL as your only defense.&lt;/strong&gt; It reduces noise, not risk, if XML-RPC and REST API user-enumeration endpoints are still open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A CAPTCHA with no rate limiting behind it.&lt;/strong&gt; Some bots solve CAPTCHAs via cheap human-solving services; it should be one layer, not the whole strategy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Login-limiting plugin installed, set to lock after 3-4 tries&lt;/li&gt;
&lt;li&gt;[ ] Two-factor authentication required for all Admin/Editor accounts&lt;/li&gt;
&lt;li&gt;[ ] Repeat-offender IPs blocked at &lt;code&gt;.htaccess&lt;/code&gt; or firewall level&lt;/li&gt;
&lt;li&gt;[ ] XML-RPC disabled (unless actively used)&lt;/li&gt;
&lt;li&gt;[ ] WAF or host-level rate limiting on &lt;code&gt;/wp-login.php&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Default &lt;code&gt;admin&lt;/code&gt; username removed or renamed if still in use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not sure your fixes actually closed the gap — or you want someone to check the rest of the site while they're in there — a &lt;a href="https://bugcircuit.com/guides/manual-vs-automated-penetration-testing" rel="noopener noreferrer"&gt;manual security audit&lt;/a&gt; catches things automated scanners and default plugin settings miss, like leftover admin accounts or a misconfigured REST API still leaking usernames.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Repeated failed-login emails and &lt;code&gt;wp-login.php&lt;/code&gt; spikes in your logs mean an automated brute-force script has found your login page — this is extremely common and not a sign you've been personally targeted.&lt;/li&gt;
&lt;li&gt;Install a login-limiting plugin (Limit Login Attempts Reloaded, WP Cerber, or Wordfence) and cap failed attempts at 3-4 before a lockout.&lt;/li&gt;
&lt;li&gt;Two-factor authentication neutralizes brute-force attacks on your account even if a password is guessed correctly.&lt;/li&gt;
&lt;li&gt;Block repeat-offender IPs at the &lt;code&gt;.htaccess&lt;/code&gt; or firewall level, and rate-limit &lt;code&gt;/wp-login.php&lt;/code&gt; and &lt;code&gt;/xmlrpc.php&lt;/code&gt; for lasting protection.&lt;/li&gt;
&lt;li&gt;Disabling XML-RPC and hiding the default login URL cut down the noise but should back up the layers above, not replace them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this is complicated once it's set up, but it's easy to miss one open door — an old plugin, a forgotten admin account, an XML-RPC endpoint nobody remembered was on. If you want a second set of eyes, &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit&lt;/a&gt; is a $49 one-time manual audit where a real security engineer checks your whole site, not just the login page, and hands you a plain-English report of anything else worth fixing.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>bruteforce</category>
      <category>loginsecurity</category>
      <category>wploginphp</category>
    </item>
    <item>
      <title>GDPR for Small Websites: No-Legalese Checklist</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Fri, 04 Sep 2026 05:13:30 +0000</pubDate>
      <link>https://dev.to/bugcircuit/gdpr-for-small-websites-no-legalese-checklist-223b</link>
      <guid>https://dev.to/bugcircuit/gdpr-for-small-websites-no-legalese-checklist-223b</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/gdpr-for-small-websites-no-legalese-checklist" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If your website has visitors, a contact form, or even just Google Analytics, and any of them could be in the EU or UK, GDPR applies to you — no matter how small your business is or where you're based.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Who this is for: small business owners, indie SaaS founders, and agencies running a marketing site, online store, or app with a contact form, newsletter signup, or login. What you'll get: a plain-English rundown of the four things that actually matter — cookies, your privacy policy, how you handle form data, and the security duty (Article 32) almost nobody reads — plus a one-page checklist you can work through in an afternoon.&lt;/p&gt;

&lt;p&gt;This isn't legal advice — enforcement depends on your specific data flows, and a lawyer should sign off on anything customer-facing. But most small sites get compliance wrong in the same handful of predictable ways, and those are fixable without a law degree.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does GDPR actually apply to your website?
&lt;/h2&gt;

&lt;p&gt;GDPR (General Data Protection Regulation) is EU law, but it reaches well outside the EU. It applies to you if either is true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You're based in the EU/UK, regardless of who visits your site, or&lt;/li&gt;
&lt;li&gt;You're based anywhere else, but you offer goods or services to people in the EU/UK, or you monitor their behavior (analytics, ad tracking, cookies) — even if you never make a sale there.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice: if your contact form, newsletter, or checkout could realistically be used by someone in Europe, GDPR applies. "We don't think we have EU visitors" stops being a defense the moment you check your analytics and find you do.&lt;/p&gt;

&lt;p&gt;The UK runs a near-identical "UK GDPR" post-Brexit, enforced by the ICO — everything below applies to both. Source: &lt;a href="https://ico.org.uk/for-organisations/advice-for-small-organisations/" rel="noopener noreferrer"&gt;ICO guidance for small organisations&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cookie banner: what you actually need
&lt;/h2&gt;

&lt;p&gt;The banner requirement technically comes from the ePrivacy Directive (the "cookie law"), not GDPR itself — but GDPR defines what counts as valid consent, so regulators enforce them together. The rule is simple once you split cookies into two buckets:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cookie type&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;th&gt;Consent needed?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Strictly necessary&lt;/td&gt;
&lt;td&gt;Session ID, shopping cart, login token, load balancer, CSRF/security token&lt;/td&gt;
&lt;td&gt;No — but disclose them anyway&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Everything else&lt;/td&gt;
&lt;td&gt;Google Analytics, Meta Pixel, ad retargeting, A/B testing tools, embedded YouTube/social widgets&lt;/td&gt;
&lt;td&gt;Yes — prior opt-in consent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Valid consent means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Opt-in, not opt-out.&lt;/strong&gt; No pre-ticked boxes for analytics or marketing cookies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Specific and easy to refuse.&lt;/strong&gt; "Accept all" as the only button isn't compliant without an equally easy "reject" or "manage preferences" option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Before the cookie fires&lt;/strong&gt;, not after. If Analytics loads on page load before anyone clicks anything, that's tracking without consent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;As easy to withdraw as to give&lt;/strong&gt; — a "manage cookies" link in the footer, not a support ticket.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your site only uses strictly-necessary cookies, you don't need a consent banner at all — just disclose them in your privacy policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy policy checklist
&lt;/h2&gt;

&lt;p&gt;A privacy policy isn't a formality — it's the document that proves you thought about what you collect. Under GDPR Article 13, it needs to disclose, in plain language:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who you are and how to contact you (business name, email, physical address if you have one)&lt;/li&gt;
&lt;li&gt;What personal data you collect (form fields, cookies, server logs, payment details)&lt;/li&gt;
&lt;li&gt;Why you collect it and your legal basis (consent, contract, legitimate interest)&lt;/li&gt;
&lt;li&gt;How long you keep it — a real retention period, not "as long as necessary"&lt;/li&gt;
&lt;li&gt;Who you share it with — email provider, payment processor, host, analytics tools&lt;/li&gt;
&lt;li&gt;Whether data leaves the EU/UK and how that transfer is protected&lt;/li&gt;
&lt;li&gt;The visitor's rights: access, correction, deletion, restriction, objection, portability&lt;/li&gt;
&lt;li&gt;Where to complain if they're unhappy — their local data protection authority&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A policy copy-pasted from another site and never updated when you add a new tool (a chatbot, a new email platform) is one of the most common gaps we find during audits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contact and signup forms: collect less, store safer
&lt;/h2&gt;

&lt;p&gt;GDPR's data minimization principle (Article 5(1)(c)) says you may only collect what you actually need for the stated purpose. Source: &lt;a href="https://gdpr-info.eu/art-5-gdpr/" rel="noopener noreferrer"&gt;official GDPR text, Article 5&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Practical fixes for most small-site forms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop fields you don't use. A contact form asking for phone number, company size, and job title when you only ever email people back is over-collecting.&lt;/li&gt;
&lt;li&gt;Separate marketing consent from the form submission itself — an unticked "send me updates" checkbox, not a bundled agreement.&lt;/li&gt;
&lt;li&gt;Never email form submissions containing sensitive data (ID numbers, health info) in plain text — route them to an encrypted CRM or ticketing system instead.&lt;/li&gt;
&lt;li&gt;Set a real deletion schedule for old leads and abandoned carts — most email and CRM tools let you auto-purge inactive contacts.&lt;/li&gt;
&lt;li&gt;Serve every form over HTTPS. A form on an unencrypted &lt;code&gt;http://&lt;/code&gt; page is both a GDPR problem and a basic security hole.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The clause almost every small business misses: Article 32
&lt;/h2&gt;

&lt;p&gt;Most owners think GDPR is a paperwork exercise — write a policy, add a banner, done. But Article 32 ("Security of processing") is a legal obligation to actually secure the data you collect, and it's the part regulators focus on hardest after a breach. Source: &lt;a href="https://gdpr-info.eu/art-32-gdpr/" rel="noopener noreferrer"&gt;GDPR Article 32, official text&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The regulation doesn't hand you a fixed checklist — it says measures must be "appropriate" to the risk. For a small business website, that translates to a concrete list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encrypt data in transit.&lt;/strong&gt; Every page over HTTPS/TLS, not just checkout — an expired or missing certificate anywhere is a gap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep software patched.&lt;/strong&gt; Outdated CMS core, plugins, or themes are the most common way small sites get breached — see &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;is my website hackable&lt;/a&gt; for how attackers actually find these.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use strong authentication on admin accounts.&lt;/strong&gt; Unique passwords plus two-factor authentication (2FA) for anyone with CMS, hosting, or database access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit who has access.&lt;/strong&gt; Not every staff member needs admin — use editor/contributor roles for people who don't manage plugins or settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Back up regularly, and actually test the restore.&lt;/strong&gt; Article 32 explicitly calls out "the ability to restore availability... in a timely manner" after an incident — a backup you've never restored isn't one you can rely on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set basic security headers.&lt;/strong&gt; &lt;code&gt;Content-Security-Policy&lt;/code&gt;, &lt;code&gt;Strict-Transport-Security&lt;/code&gt;, and &lt;code&gt;X-Content-Type-Options&lt;/code&gt; cut down common attack surface — check yours free with our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers tool&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test it periodically.&lt;/strong&gt; Article 32 requires "a process for regularly testing, assessing and evaluating the effectiveness" of these measures — the part a scanner alone can't fully judge, since it can't weigh context the way a person reviewing your actual site can.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is what separates "we have a privacy policy" from actually meeting your GDPR security obligation — and it's the part a manual audit is built for, not a checkbox tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you have a breach: the 72-hour clock
&lt;/h2&gt;

&lt;p&gt;If personal data is exposed — a hacked database, a misconfigured form emailing submissions to the wrong place, a leaked backup — GDPR Article 33 gives you 72 hours from becoming aware of it to notify your supervisory authority, unless the breach is unlikely to risk people's rights and freedoms. If it's high-risk (passwords or financial data exposed), you may also need to tell the affected individuals directly.&lt;/p&gt;

&lt;p&gt;Fines scale with severity: up to €10 million or 2% of global annual turnover for lesser infringements, and up to €20 million or 4% for the most serious ones — whichever is higher. Source: &lt;a href="https://gdpr-info.eu/art-83-gdpr/" rel="noopener noreferrer"&gt;GDPR Article 83&lt;/a&gt;. For most small businesses, real enforcement is rare and usually follows a complaint or a breach, not a random audit — but "rare" isn't "never," and prevention is almost always cheaper than the incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  One-page GDPR checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Cookie banner blocks non-necessary cookies until opt-in consent&lt;/li&gt;
&lt;li&gt;[ ] "Reject" is as easy to click as "Accept"&lt;/li&gt;
&lt;li&gt;[ ] Privacy policy lists what you collect, why, how long, and who it's shared with&lt;/li&gt;
&lt;li&gt;[ ] Privacy policy names all third-party tools (analytics, email platform, payment processor)&lt;/li&gt;
&lt;li&gt;[ ] Contact/signup forms only ask for fields you actually use&lt;/li&gt;
&lt;li&gt;[ ] Marketing consent is a separate, unticked checkbox&lt;/li&gt;
&lt;li&gt;[ ] All forms and pages served over HTTPS&lt;/li&gt;
&lt;li&gt;[ ] CMS, plugins, and themes are up to date&lt;/li&gt;
&lt;li&gt;[ ] Admin accounts use unique passwords + 2FA&lt;/li&gt;
&lt;li&gt;[ ] Backups exist and have been test-restored in the last 6 months&lt;/li&gt;
&lt;li&gt;[ ] You know who to notify within 72 hours if data is exposed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GDPR applies based on your visitors' location, not your business's — check your analytics before assuming it doesn't apply to you.&lt;/li&gt;
&lt;li&gt;The cookie banner only needs to gate non-essential cookies (analytics, ads); strictly necessary ones just need disclosure.&lt;/li&gt;
&lt;li&gt;Your privacy policy should describe your actual current tools and data flows, not a copy-pasted template.&lt;/li&gt;
&lt;li&gt;Article 32's "appropriate technical measures" is a real security requirement — HTTPS, patching, 2FA, and tested backups — not just a legal sentence.&lt;/li&gt;
&lt;li&gt;A manual review catches the context-dependent gaps (over-collecting forms, unpatched plugins, missing headers) that automated scanners and legal templates both miss.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where a manual audit fits in
&lt;/h2&gt;

&lt;p&gt;None of this replaces legal advice on your specific data flows — but the security half of GDPR (Article 32) is exactly what a hands-on website review is built to check. Bug Circuit's &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit audit&lt;/a&gt; is $49: a real person manually reviews your site and hands you a written report with fixes, including the headers, patching, and access issues that feed straight into your GDPR security obligations. Start with our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free passive check&lt;/a&gt; if you just want a quick read on where you stand first.&lt;/p&gt;

</description>
      <category>gdpr</category>
      <category>privacypolicy</category>
      <category>cookieconsent</category>
      <category>dataprotection</category>
    </item>
    <item>
      <title>Webflow Security: Is Your Site Actually Safe?</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Wed, 02 Sep 2026 17:13:20 +0000</pubDate>
      <link>https://dev.to/bugcircuit/webflow-security-is-your-site-actually-safe-3nmf</link>
      <guid>https://dev.to/bugcircuit/webflow-security-is-your-site-actually-safe-3nmf</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/webflow-security-is-your-site-actually-safe" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webflow's hosting keeps your server safe — it doesn't check the code, forms, and integrations you added on top of it, and that's where most Webflow sites actually get compromised.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for agencies and freelancers running client sites on Webflow, and Webflow site owners who assume "Webflow is secure" means the whole site is covered. You'll get a plain-English breakdown of what Webflow's hosting actually protects, the four risk areas it doesn't touch, and a 10-minute checklist you can run on any Webflow site today — plus how to think about it if you resell security audits as part of your client work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Webflow's hosting actually protects
&lt;/h2&gt;

&lt;p&gt;Webflow is a managed platform, and that buys you real security out of the box. Its hosting runs behind a CDN with automatic SSL/TLS, infrastructure-level DDoS mitigation, and automated backups — you don't manage a server, so there's no unpatched Linux box or outdated PHP version for an attacker to exploit the way there often is on a self-hosted WordPress install.&lt;/p&gt;

&lt;p&gt;But "managed hosting" only covers the parts Webflow itself controls. Everything you build on top of that — custom code, forms, integrations, content — is your responsibility, same as on any platform.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Who's responsible&lt;/th&gt;
&lt;th&gt;Covered by Webflow hosting?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Servers, SSL, CDN, uptime, DDoS&lt;/td&gt;
&lt;td&gt;Webflow&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform patching (no plugins to update)&lt;/td&gt;
&lt;td&gt;Webflow&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom code you embed (head/footer/embed blocks)&lt;/td&gt;
&lt;td&gt;You / your agency&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API keys and tokens pasted into embeds or integrations&lt;/td&gt;
&lt;td&gt;You / your agency&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form spam and abuse settings&lt;/td&gt;
&lt;td&gt;You / your agency&lt;/td&gt;
&lt;td&gt;Partially — defaults exist but aren't complete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CMS collection data exposed via the API&lt;/td&gt;
&lt;td&gt;You / your agency&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response security headers (CSP, HSTS, etc.)&lt;/td&gt;
&lt;td&gt;You / your agency&lt;/td&gt;
&lt;td&gt;Mostly no&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is the gap that shows up in almost every Webflow audit we run: the platform itself is solid, but the things a builder added — a Zapier webhook, a tracking script, a "quick fix" embed — are where the actual exposure lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four risks Webflow hosting doesn't cover
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Leaked API keys in custom code embeds
&lt;/h3&gt;

&lt;p&gt;Webflow's Custom Code panel (Site Settings → Custom Code, or an Embed element on a page) is one of its most useful features — and one of the easiest ways to leak a secret. Anything typed into an embed is delivered as plain client-side HTML/JavaScript, meaning anyone can see it by right-clicking → View Page Source.&lt;/p&gt;

&lt;p&gt;We regularly find live API keys for tools like Airtable, Google Maps, Mailchimp, Zapier, and CRMs sitting in plain view inside embeds — usually copy-pasted straight from a tutorial. A key with write access in the wrong hands can mean spam data injected into a CRM, a maxed-out API bill, or a foothold into a connected tool.&lt;/p&gt;

&lt;p&gt;Hard-coding secrets into client-facing code is a well-documented anti-pattern: OWASP's &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" rel="noopener noreferrer"&gt;Secrets Management Cheat Sheet&lt;/a&gt; and the &lt;a href="https://cwe.mitre.org/data/definitions/798.html" rel="noopener noreferrer"&gt;CWE-798: Use of Hard-Coded Credentials&lt;/a&gt; weakness class both cover it directly. The fix: any key that needs to stay secret belongs in a server-side function or a proxy — never in an embed the browser can read.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Unprotected form submissions
&lt;/h3&gt;

&lt;p&gt;Webflow Forms come with basic honeypot-style spam filtering, but that's not the same as rate limiting or bot protection. Left on defaults, a public form is an open door for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated spam floods that fill your (or your client's) inbox and CMS&lt;/li&gt;
&lt;li&gt;Bots probing form fields for weak input validation&lt;/li&gt;
&lt;li&gt;Fake leads polluting sales data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OWASP catalogs this class of abuse under &lt;a href="https://owasp.org/www-project-automated-threats-to-web-applications/" rel="noopener noreferrer"&gt;Automated Threats to Web Applications&lt;/a&gt;. To close the gap: turn on reCAPTCHA in the form element's settings, restrict what fields accept (no open file uploads unless genuinely required), and don't route submissions anywhere that could be used to spoof internal emails or phish your team.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. CMS data exposed through the API
&lt;/h3&gt;

&lt;p&gt;Webflow's CMS is genuinely well-built, but "CMS item" and "private data" aren't automatically the same thing. Two patterns show up repeatedly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A collection meant for internal use (draft content, pricing tiers, internal notes) gets published because "unpublished" only hides it from the live site, not from anyone with the direct API access an integration might have.&lt;/li&gt;
&lt;li&gt;A Webflow API token — used to power custom filtering, search, or a headless front end — gets embedded in client-side JavaScript instead of a backend, exposing read/write access to every collection it can reach.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat any Webflow API token the same as a database password: server-side only, scoped to the minimum access it needs, and rotated if you're ever unsure where it's been pasted.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Security headers you have to set yourself
&lt;/h3&gt;

&lt;p&gt;Response headers like &lt;code&gt;Content-Security-Policy&lt;/code&gt;, &lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt;, and &lt;code&gt;Strict-Transport-Security&lt;/code&gt; tell the browser how to defend the page against things like clickjacking and script injection — but most Webflow plans don't give you a direct panel to set them. If your plan doesn't support custom headers, the practical fix is fronting the site with a service like Cloudflare, which can inject these headers at the edge without touching Webflow itself.&lt;/p&gt;

&lt;p&gt;OWASP's &lt;a href="https://owasp.org/www-project-secure-headers/" rel="noopener noreferrer"&gt;Secure Headers Project&lt;/a&gt; is the reference for what each header does and recommended values. Run your live site through our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers checker&lt;/a&gt; to see exactly which ones are missing — it takes about ten seconds and needs nothing installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 10-minute self-check for any Webflow site
&lt;/h2&gt;

&lt;p&gt;Run through this on your own site, or a client's, before assuming it's fine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;View source on every page with an embed.&lt;/strong&gt; Search for &lt;code&gt;key=&lt;/code&gt;, &lt;code&gt;token=&lt;/code&gt;, &lt;code&gt;apikey&lt;/code&gt;, or &lt;code&gt;secret&lt;/code&gt; — anything that looks like a credential shouldn't be there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check every form's settings&lt;/strong&gt; for reCAPTCHA or spam protection and confirm exactly where submissions get sent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List every third-party integration&lt;/strong&gt; (Zapier, Make, Airtable, Google Sheets, a CRM) connected to the site and confirm none of their keys live inside Webflow's custom code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan for security headers&lt;/strong&gt; using a header-check tool and note what's missing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review CMS collections&lt;/strong&gt; for anything published that shouldn't be public — draft content, internal pricing, staff data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check for an orphaned staging subdomain&lt;/strong&gt; (&lt;code&gt;.webflow.io&lt;/code&gt;) still live and indexable after launch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If more than one or two of these turn up something, it's worth getting a second pair of eyes on it rather than guessing at severity yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "it's on Webflow, so it's secure" is a trap for agencies
&lt;/h2&gt;

&lt;p&gt;If you build or manage sites for clients, "Webflow is secure" is a sentence clients repeat back to you — and it's true just enough to be dangerous. Webflow's hosting is genuinely solid infrastructure, but a client breached through a leaked Zapier key sitting in their homepage's embed code won't care that the servers were fine. The exposure was in what your team built, and that's exactly the layer an automated scanner tends to skim past, because scanners test infrastructure patterns, not the specific embed a designer pasted in eight months ago. Our &lt;a href="https://bugcircuit.com/guides/manual-vs-automated-penetration-testing" rel="noopener noreferrer"&gt;guide comparing manual vs. automated penetration testing&lt;/a&gt; covers why a human reading the actual page source catches this class of issue that tooling alone tends to miss — it's why agencies increasingly bundle a manual pass into every Webflow handoff instead of a one-line "we use Webflow, so you're covered."&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Webflow's hosting secures the servers, SSL, and uptime — it does not check your custom code, forms, integrations, or CMS data for you.&lt;/li&gt;
&lt;li&gt;Anything typed into a Custom Code embed is publicly visible via View Source, including any API key pasted there by mistake.&lt;/li&gt;
&lt;li&gt;Turn on reCAPTCHA on public forms and never route form data anywhere an attacker could use it for phishing.&lt;/li&gt;
&lt;li&gt;Treat Webflow API tokens like passwords: server-side only, minimum scope, never in client-facing JavaScript.&lt;/li&gt;
&lt;li&gt;Missing security headers (CSP, HSTS, X-Content-Type-Options) are on you to add — usually via a proxy like Cloudflare if your plan doesn't support them directly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your self-check turned up a stray API key, a wide-open form, or you're just not sure what's actually exposed on a Webflow build you inherited, that's exactly what a manual audit is for. &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit&lt;/a&gt; is a $49 one-time check where a real person reads the actual page source, tests the forms, and hands you a written report of what's exposed and how to fix it — not another automated scan re-flagging the same generic warnings. Or start with our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free passive security check&lt;/a&gt; if you just want a quick read on where things stand.&lt;/p&gt;

</description>
      <category>webflow</category>
      <category>websitesecurity</category>
      <category>apikeys</category>
      <category>nocodesecurity</category>
    </item>
    <item>
      <title>What Is Clickjacking? The 1-Line Fix</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Mon, 31 Aug 2026 23:13:12 +0000</pubDate>
      <link>https://dev.to/bugcircuit/what-is-clickjacking-the-1-line-fix-cdp</link>
      <guid>https://dev.to/bugcircuit/what-is-clickjacking-the-1-line-fix-cdp</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/what-is-clickjacking-the-1-line-fix" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clickjacking is an attack where a hacker hides your website inside an invisible frame on their own page, then tricks a visitor into clicking something they can't see — a "Buy Now" button, a "Follow" button, or an account-settings toggle that actually belongs to your site.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for anyone who owns or runs a website — WordPress, Shopify, or a custom app — and wants to know if clickjacking is something to worry about. In a few minutes you'll understand exactly how the invisible-overlay trick works, see the real damage it can do, and get the one HTTP response header (plus copy-paste code for the platforms people actually use) that shuts it down for good.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is clickjacking, actually?
&lt;/h2&gt;

&lt;p&gt;Clickjacking, also called a "UI redress attack," is a trick, not a break-in. The attacker doesn't steal a password or hack your server — they abuse a normal browser feature called an &lt;strong&gt;iframe&lt;/strong&gt;, which lets one webpage embed another webpage inside it, like a window within a window.&lt;/p&gt;

&lt;p&gt;Here's the setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The attacker builds their own page with something tempting on it — "Click to claim your prize," a fake video play button, a captcha.&lt;/li&gt;
&lt;li&gt;Behind that visible content, they load your real website inside an iframe and set its transparency to zero, making it completely invisible to the visitor.&lt;/li&gt;
&lt;li&gt;They line up your site's real button — say, "Confirm Purchase" or "Delete Account" — exactly under the fake button the visitor sees.&lt;/li&gt;
&lt;li&gt;The visitor clicks what looks like the prize button, but the click actually lands on your invisible page underneath, in the visitor's real logged-in session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the click happens on your real site with the visitor's real cookies, your server has no way to tell a genuine click from a hijacked one — the request looks completely normal. That's why the fix has to happen at the browser-framing level rather than inside your app's logic; see &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's Clickjacking Defense Cheat Sheet&lt;/a&gt; for the full technical breakdown. The technique was named and publicized by security researchers Jeremiah Grossman and Robert Hansen in 2008, and it's now formally tracked as &lt;a href="https://cwe.mitre.org/data/definitions/1021.html" rel="noopener noreferrer"&gt;CWE-1021: Improper Restriction of Rendered UI Layers or Frames&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can an attacker actually make your visitors do?
&lt;/h2&gt;

&lt;p&gt;Anything a logged-in user can do with a single click is fair game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Force a purchase or subscription renewal&lt;/strong&gt; on a checkout or "buy now" button&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change account settings&lt;/strong&gt; — recovery email, password reset options, two-factor auth&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grant browser permissions&lt;/strong&gt;, like "Allow" prompts for camera or microphone&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manipulate social proof&lt;/strong&gt; — trick visitors into liking, following, or sharing something ("likejacking")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trigger a donation or money transfer&lt;/strong&gt; on sites with one-click payment buttons&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete content or data&lt;/strong&gt; behind a "Confirm delete" button that was never meant to be clicked blind&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this needs stolen credentials. It just needs your pages to be frameable, and either a logged-in visitor or an action that doesn't require login at all, like a public donation form.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 1-line fix: a frame-protection header
&lt;/h2&gt;

&lt;p&gt;The fix is a single line in your server's response headers telling browsers "never let another site put my pages inside a frame." Once that header is present, the invisible-overlay trick can't render at all — the browser simply refuses to load your page inside the attacker's frame.&lt;/p&gt;

&lt;p&gt;Two headers do this job. Set both if you can; if you only add one, make it the CSP version.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Header&lt;/th&gt;
&lt;th&gt;The 1 line&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Content-Security-Policy: frame-ancestors 'self';&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only your own site can frame your pages&lt;/td&gt;
&lt;td&gt;Modern standard; can list multiple trusted origins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options&lt;/td&gt;
&lt;td&gt;&lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Same idea, older syntax&lt;/td&gt;
&lt;td&gt;Reliable fallback for older clients; use &lt;code&gt;DENY&lt;/code&gt; if nothing should ever frame the page&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both are documented on MDN: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options" rel="noopener noreferrer"&gt;X-Frame-Options&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors" rel="noopener noreferrer"&gt;CSP frame-ancestors&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy-paste it for your platform
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt; — add inside 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;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;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;"frame-ancestors&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;"&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;Apache&lt;/strong&gt; — add to &lt;code&gt;.htaccess&lt;/code&gt; or your vhost config:&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;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-Frame-Options "SAMEORIGIN"
&lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Content-Security-Policy "frame-ancestors 'self';"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;WordPress (no code needed):&lt;/strong&gt; many security plugins expose a "Clickjacking protection" or "Frame options" toggle in settings. If your host or plugin offers it, that's the fastest route.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js / Express&lt;/strong&gt; — using the popular &lt;code&gt;helmet&lt;/code&gt; middleware:&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helmet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;frameguard&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;action&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contentSecurityPolicy&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;directives&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;frameAncestors&lt;/span&gt;&lt;span class="p"&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;'self'&lt;/span&gt;&lt;span class="dl"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cloudflare (no origin access needed):&lt;/strong&gt; Rules → Transform Rules → Modify Response Header → add both headers with the values above. This works even if you can't edit your hosting config directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check if you're actually protected
&lt;/h2&gt;

&lt;p&gt;Don't take it on faith — verify the header is live on your production pages, not just sitting in a config file that never shipped:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your site, open browser DevTools → Network tab, click the main document request, and check the Headers.&lt;/li&gt;
&lt;li&gt;Look for &lt;code&gt;x-frame-options&lt;/code&gt; or &lt;code&gt;content-security-policy&lt;/code&gt; in the response.&lt;/li&gt;
&lt;li&gt;Or skip the manual digging and run your domain through Bug Circuit's &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;free security headers checker&lt;/a&gt; — it flags missing frame protection alongside the other headers that matter, like HSTS and X-Content-Type-Options, in one pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common mistakes that undo the fix
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Setting it in code but not in production.&lt;/strong&gt; A CSP meta tag in your HTML, or a header only set in your dev environment, doesn't help real visitors hitting your live, cached pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using &lt;code&gt;DENY&lt;/code&gt; when you legitimately embed your own content&lt;/strong&gt;, like a payment widget or dashboard loaded from a subdomain. &lt;code&gt;DENY&lt;/code&gt; blocks that too — use &lt;code&gt;SAMEORIGIN&lt;/code&gt;, or list the specific trusted origin in &lt;code&gt;frame-ancestors&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A CDN or proxy stripping the header.&lt;/strong&gt; Some caches serve stale responses from before the header existed. After deploying, purge the cache and re-check.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only testing the homepage.&lt;/strong&gt; Checkout, account settings, and admin login are the actual targets — confirm the header is present sitewide, not just on the one page you happened to check.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is this the only clickjacking-style trick?
&lt;/h2&gt;

&lt;p&gt;Frame-based clickjacking is the classic version and by far the most common in the wild, but related tricks exist too — cursorjacking (offsetting the visible cursor from the real one), drag-and-drop hijacking, and tapjacking on mobile. The frame-ancestors/X-Frame-Options fix closes off the frame-based attack entirely. A full manual review checks for the less common variants too, and confirms your specific high-value pages — checkout, settings, delete-account — aren't exposed in ways a header alone can't catch.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a header isn't the whole story
&lt;/h2&gt;

&lt;p&gt;Adding this header takes minutes and shuts down an entire class of attack — but it's one line among dozens of things that can go wrong on a small business site: exposed admin panels, outdated plugins, weak session handling, misconfigured payment flows. If no one has actually looked at your site's security before, our guide on &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;figuring out if your website is hackable&lt;/a&gt; is a good next stop, and if you're weighing an automated scanner against a real person checking your site, see &lt;a href="https://bugcircuit.com/guides/manual-vs-automated-penetration-testing" rel="noopener noreferrer"&gt;manual vs. automated penetration testing&lt;/a&gt; for how they actually differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clickjacking hides your site in an invisible iframe so visitor clicks land on your buttons instead of the fake ones they see.&lt;/li&gt;
&lt;li&gt;The fix is one HTTP header: &lt;code&gt;Content-Security-Policy: frame-ancestors 'self';&lt;/code&gt; — add &lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt; too for broader compatibility.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;SAMEORIGIN&lt;/code&gt; / &lt;code&gt;'self'&lt;/code&gt; instead of &lt;code&gt;DENY&lt;/code&gt; if you ever embed your own pages inside your own site.&lt;/li&gt;
&lt;li&gt;Verify the header on your &lt;em&gt;live&lt;/em&gt; production pages, not just in config — CDNs can keep serving stale, unprotected responses.&lt;/li&gt;
&lt;li&gt;Run a free check at &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;Bug Circuit's security headers tool&lt;/a&gt; to confirm it's actually in place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Frame protection is a five-minute fix once you know it's missing — the harder part is knowing what else might be. A &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit audit&lt;/a&gt; is $49, done by an actual person, and comes back with every issue like this one spelled out with the exact fix, not just a scanner score.&lt;/p&gt;

</description>
      <category>clickjacking</category>
      <category>securityheaders</category>
      <category>xframeoptions</category>
      <category>csp</category>
    </item>
    <item>
      <title>What Is a Security Header? The 5 You Need</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Sun, 30 Aug 2026 05:12:55 +0000</pubDate>
      <link>https://dev.to/bugcircuit/what-is-a-security-header-the-5-you-need-2j52</link>
      <guid>https://dev.to/bugcircuit/what-is-a-security-header-the-5-you-need-2j52</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/what-is-a-security-header-the-5-you-need" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A security header is a short instruction your web server sends to every visitor's browser telling it how to behave safely on your site — and most small sites are missing at least three of the five that matter most.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for anyone who runs a WordPress site, Shopify store, or small SaaS app and just got flagged by a security scanner, a client's vendor questionnaire, or our own &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; for "missing security headers." By the end, you'll know what each header does, what it actually stops, and have copy-pasteable code to add all five today.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a security header, exactly?
&lt;/h2&gt;

&lt;p&gt;Every time a browser loads your site, your server sends back more than just the page content — it also sends a set of HTTP response headers, small text instructions that ride alongside the page and never show up on screen. Most headers are boring plumbing (content length, cache rules). Security headers are the subset that tell the browser things like "only run scripts from my own domain" or "never load me inside someone else's frame."&lt;/p&gt;

&lt;p&gt;The browser enforces these instructions itself — you're not installing anything, and visitors never see them. Think of it as handing the browser a short list of house rules before it starts rendering your page. The &lt;a href="https://owasp.org/www-project-secure-headers/" rel="noopener noreferrer"&gt;OWASP Secure Headers Project&lt;/a&gt; maintains the standard reference for which headers exist and what each one does, and it's the source most scanners (including ours) check against.&lt;/p&gt;

&lt;p&gt;Missing headers don't automatically mean you've been hacked. They mean the browser is running your site with fewer guardrails than it could have — which matters most when something else on your site (an old plugin, a comment form, a third-party script) is already vulnerable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 security headers every small site needs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Header&lt;/th&gt;
&lt;th&gt;What it stops&lt;/th&gt;
&lt;th&gt;Example value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Content-Security-Policy (CSP)&lt;/td&gt;
&lt;td&gt;Malicious scripts running on your page (XSS)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;default-src 'self'; frame-ancestors 'self';&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strict-Transport-Security (HSTS)&lt;/td&gt;
&lt;td&gt;Browsers being tricked into connecting over unencrypted HTTP&lt;/td&gt;
&lt;td&gt;&lt;code&gt;max-age=31536000; includeSubDomains; preload&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Frame-Options (or CSP &lt;code&gt;frame-ancestors&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Your site being loaded invisibly inside another site (clickjacking)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SAMEORIGIN&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X-Content-Type-Options&lt;/td&gt;
&lt;td&gt;The browser guessing a file's type and running it as something dangerous&lt;/td&gt;
&lt;td&gt;&lt;code&gt;nosniff&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Referrer-Policy&lt;/td&gt;
&lt;td&gt;Full page URLs (sometimes containing tokens or IDs) leaking to third-party sites&lt;/td&gt;
&lt;td&gt;&lt;code&gt;strict-origin-when-cross-origin&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  1. Content-Security-Policy (CSP) — the big one
&lt;/h3&gt;

&lt;p&gt;CSP tells the browser which sources of scripts, styles, images, and fonts are allowed to load on your page. If an attacker manages to inject a malicious &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag — through a vulnerable comment form, a hacked plugin, or a compromised ad network — a strict CSP simply refuses to run it, because it didn't come from an approved source.&lt;/p&gt;

&lt;p&gt;This is the header that stops cross-site scripting (XSS) from doing real damage, which is why &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's CSP guidance&lt;/a&gt; treats it as the highest-value header on the list. It's also the trickiest to set up, because a policy that's too strict will silently break embedded YouTube videos, Google Fonts, or chat widgets. Start with a &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; header (same syntax, but it only logs violations instead of blocking them) so you can see what would break before you enforce it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Strict-Transport-Security (HSTS) — no downgrading to HTTP
&lt;/h3&gt;

&lt;p&gt;Even if your site has an SSL certificate and redirects HTTP to HTTPS, a visitor's very first request can still go out over plain HTTP for a split second — long enough for an attacker on the same network (public Wi-Fi, a compromised router) to intercept it. HSTS fixes this by telling the browser, "never try HTTP for this domain again, for the next year," so it upgrades to HTTPS before sending anything.&lt;/p&gt;

&lt;p&gt;Be careful with &lt;code&gt;includeSubDomains&lt;/code&gt;: it applies the rule to every subdomain too, so confirm all of them actually support HTTPS first. Once you're confident, you can submit your domain to the &lt;a href="https://hstspreload.org/" rel="noopener noreferrer"&gt;HSTS preload list&lt;/a&gt; so browsers enforce HTTPS even on a user's very first visit, before your server has said anything.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. X-Frame-Options / frame-ancestors — stop clickjacking
&lt;/h3&gt;

&lt;p&gt;Clickjacking is when an attacker loads your live site inside an invisible iframe on their own page, then overlays fake buttons to trick visitors into clicking something on &lt;em&gt;your&lt;/em&gt; site — like "delete account" or "transfer funds" — without realizing it. &lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt; tells browsers your page may only be framed by itself. The modern equivalent is CSP's &lt;code&gt;frame-ancestors&lt;/code&gt; directive; &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's Clickjacking Defense Cheat Sheet&lt;/a&gt; recommends sending both, since &lt;code&gt;frame-ancestors&lt;/code&gt; isn't supported in a few older browsers still in the wild.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. X-Content-Type-Options — stop MIME-sniffing tricks
&lt;/h3&gt;

&lt;p&gt;Browsers sometimes try to be "helpful" by guessing a file's actual type instead of trusting what the server declared — this is called MIME-sniffing. Attackers have abused this to get a browser to treat an uploaded file (say, a user avatar) as executable JavaScript instead of a harmless image. &lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt; turns this guessing off entirely and forces the browser to trust the declared content type.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Referrer-Policy — stop leaking your URLs
&lt;/h3&gt;

&lt;p&gt;When a visitor clicks a link from your site to another site, the browser can send the full URL of the page they came from in the &lt;code&gt;Referer&lt;/code&gt; header — including anything in the URL itself, like a password-reset token, an internal search query, or a customer ID. &lt;code&gt;Referrer-Policy: strict-origin-when-cross-origin&lt;/code&gt; limits what gets shared: your own site still gets full detail, but outside sites only see your domain name, not the full path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check which headers your site already has
&lt;/h2&gt;

&lt;p&gt;Before changing anything, see where you stand. Run our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;free security headers checker&lt;/a&gt; against your domain — it's passive (no login, no scanning your login forms) and shows exactly which of the five are present, missing, or misconfigured, in plain English.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to add these headers
&lt;/h2&gt;

&lt;p&gt;Exact syntax depends on your hosting setup. Here's the same five headers for the most common stacks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nginx&lt;/strong&gt; (inside your &lt;code&gt;server&lt;/code&gt; 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;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;frame-ancestors&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;"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&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;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;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;X-Content-Type-Options&lt;/span&gt; &lt;span class="s"&gt;"nosniff"&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&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;Apache&lt;/strong&gt; (in &lt;code&gt;.htaccess&lt;/code&gt; or your vhost config):&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;IfModule&lt;/span&gt;&lt;span class="sr"&gt; mod_headers.c&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Content-Security-Policy "default-src 'self'; frame-ancestors 'self';"
  &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
  &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-Frame-Options "SAMEORIGIN"
  &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; X-Content-Type-Options "nosniff"
  &lt;span class="nc"&gt;Header&lt;/span&gt; &lt;span class="ss"&gt;always&lt;/span&gt; &lt;span class="ss"&gt;set&lt;/span&gt; Referrer-Policy "strict-origin-when-cross-origin"
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nl"&gt;IfModule&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;Netlify&lt;/strong&gt; (a &lt;code&gt;_headers&lt;/code&gt; file in your publish directory):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
  Content-Security-Policy: default-src 'self'; frame-ancestors 'self';
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  X-Frame-Options: SAMEORIGIN
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;WordPress:&lt;/strong&gt; if you're on shared hosting without server access, a plugin like "HTTP Headers" or the security-headers module in a plugin such as Really Simple Security can add these without editing server config. Add one header at a time and reload your homepage between each to catch anything that breaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloudflare:&lt;/strong&gt; use Rules → Transform Rules → Modify Response Header to add each header at the edge, without touching your origin server at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes to avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Copy-pasting a CSP from another site.&lt;/strong&gt; Every site loads different scripts (analytics, chat widgets, payment forms) — a policy built for someone else's stack will either break yours or leave gaps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Turning on HSTS &lt;code&gt;preload&lt;/code&gt; before confirming every subdomain works over HTTPS.&lt;/strong&gt; Preload removal from browsers can take months.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Setting &lt;code&gt;X-Frame-Options: DENY&lt;/code&gt; on a site that legitimately embeds itself&lt;/strong&gt; (e.g., a widget meant to be iframed by customers) — use &lt;code&gt;SAMEORIGIN&lt;/code&gt; or a specific &lt;code&gt;frame-ancestors&lt;/code&gt; list instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adding headers and never testing the site afterward.&lt;/strong&gt; Reload every major page type — homepage, checkout, contact form — before calling it done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treating headers as the whole security picture.&lt;/strong&gt; They reduce what a successful attack can do; they don't patch the vulnerable plugin, weak password, or exposed admin panel that let the attack start. For that, see our guide on &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;how to tell if your website is hackable&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A security header is an instruction your server sends to the browser — invisible to visitors, enforced automatically.&lt;/li&gt;
&lt;li&gt;The five that matter most for a small site: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options (or &lt;code&gt;frame-ancestors&lt;/code&gt;), X-Content-Type-Options, and Referrer-Policy.&lt;/li&gt;
&lt;li&gt;CSP is the highest-value and highest-risk header to configure — test with &lt;code&gt;Content-Security-Policy-Report-Only&lt;/code&gt; before enforcing.&lt;/li&gt;
&lt;li&gt;Check your current headers for free before changing anything, then add them one at a time and reload the site to catch breakage.&lt;/li&gt;
&lt;li&gt;Headers reduce the damage an attack can do — they don't replace patching the actual vulnerability that let an attacker in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Headers are the easy, free part. The harder question — whether something on your site is actually exploitable right now — needs a person to look, not just a scanner. That's what our &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;$49 manual audit&lt;/a&gt; is for: a real security engineer checks your headers along with everything else and hands you a plain-English report of what to fix and how.&lt;/p&gt;

</description>
      <category>securityheaders</category>
      <category>csp</category>
      <category>hsts</category>
      <category>websitesecuritybasics</category>
    </item>
    <item>
      <title>Fix Chrome's "Deceptive Site Ahead" Warning</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Thu, 27 Aug 2026 17:12:24 +0000</pubDate>
      <link>https://dev.to/bugcircuit/fix-chromes-deceptive-site-ahead-warning-4f9m</link>
      <guid>https://dev.to/bugcircuit/fix-chromes-deceptive-site-ahead-warning-4f9m</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/fix-chromes-deceptive-site-ahead-warning" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The red "Deceptive site ahead" screen means Google's Safe Browsing system found phishing or social-engineering content on your site — you fix it by removing that content and then filing a review request in Google Search Console.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for site owners who've just seen the full-page red Chrome warning (not the small gray "Not Secure" label in the address bar, and not Search Console's "This site may be hacked" message — those are different problems). You'll get: exactly what triggers this specific warning, how it differs from the other two, and the step-by-step review-request process to get it lifted — including what to check first if you run WordPress.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Deceptive site ahead" actually means
&lt;/h2&gt;

&lt;p&gt;This warning comes from &lt;a href="https://safebrowsing.google.com/" rel="noopener noreferrer"&gt;Google Safe Browsing&lt;/a&gt;, a service Chrome (and Firefox, and Safari) checks against before loading a page. It isn't one generic "your site is bad" flag — Safe Browsing has separate categories, and each produces a different warning screen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Deceptive site ahead"&lt;/strong&gt; — social engineering content: phishing pages, fake login forms, deceptive download buttons, scareware popups&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"The site ahead contains malware"&lt;/strong&gt; — the site tries to install malicious software on visitors' devices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"This site is dangerous"&lt;/strong&gt; — a general catch-all Chrome uses when multiple threat types are detected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google's own definition of social engineering content is content that "tricks users into doing something dangerous... such as revealing confidential information or downloading software" — for example a page that impersonates a bank, Google, or Microsoft login, or a popup that claims the visitor's device is infected. See Google's &lt;a href="https://developers.google.com/search/docs/monitor-debug/security/social-engineering" rel="noopener noreferrer"&gt;social engineering (phishing) content policy&lt;/a&gt; for the exact criteria. This is the same category &lt;a href="https://owasp.org/www-community/attacks/Phishing" rel="noopener noreferrer"&gt;OWASP describes as phishing&lt;/a&gt;: tricking a user into handing over credentials or money by impersonating something trustworthy.&lt;/p&gt;

&lt;p&gt;Importantly, this often isn't content &lt;em&gt;you&lt;/em&gt; put there. It's usually a symptom of a hack: an attacker planted a phishing page or malicious redirect somewhere on your site, and Safe Browsing's crawlers found it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this differs from "Not Secure" and "This site may be hacked"
&lt;/h2&gt;

&lt;p&gt;These three warnings look similar but come from completely different systems, and mixing them up leads to the wrong fix.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Warning&lt;/th&gt;
&lt;th&gt;Where it appears&lt;/th&gt;
&lt;th&gt;What triggers it&lt;/th&gt;
&lt;th&gt;Who issues it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deceptive site ahead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full-page red interstitial in the browser, before the page loads&lt;/td&gt;
&lt;td&gt;Phishing / social-engineering content found on your domain&lt;/td&gt;
&lt;td&gt;Google Safe Browsing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Not Secure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Small gray/red label in the address bar&lt;/td&gt;
&lt;td&gt;Page loaded over plain HTTP, or has mixed content (HTTP resources on an HTTPS page)&lt;/td&gt;
&lt;td&gt;Chrome itself, based on the connection, not content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;"This site may be hacked"&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A gray label under your listing in Google Search results&lt;/td&gt;
&lt;td&gt;Googlebot found spam, injected links, or malicious code while indexing your pages&lt;/td&gt;
&lt;td&gt;Google Search (reported via Search Console's Security Issues report)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Fixing a "Not Secure" label means installing or fixing an SSL/TLS certificate — it says nothing about malicious content. Fixing "This site may be hacked" means cleaning spam/injected code Googlebot found in your indexed pages. "Deceptive site ahead" is the most urgent of the three because it actively blocks visitors from reaching your site at all, and it's specifically about content designed to deceive, not just insecure or spammy content. If you're unsure which category your problem falls into, our &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;guide to whether your site is hackable&lt;/a&gt; walks through the warning signs for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually triggers this warning
&lt;/h2&gt;

&lt;p&gt;The content Safe Browsing looks for typically falls into one of these patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A fake login page&lt;/strong&gt; planted somewhere on your domain (often in an unused subfolder) mimicking PayPal, Microsoft 365, a bank, or a crypto wallet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deceptive popups or overlays&lt;/strong&gt; — fake "your device is infected" alerts, fake browser update prompts, or "you've won a prize" popups, often injected via a compromised ad network or a malicious script&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloaked redirects&lt;/strong&gt; — a script that sends normal visitors to your real site but redirects search engines or specific referrers to a phishing page, making the problem harder to spot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A hacked plugin or theme&lt;/strong&gt; on WordPress, Shopify apps, or similar CMS platforms that silently drops phishing files into an uploads or cache directory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A compromised third-party embed&lt;/strong&gt; — an ad unit, widget, or iframe you didn't author, serving deceptive content you don't directly control but that still lives on your page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a WordPress site specifically, the usual entry point is an outdated plugin or theme with a known vulnerability, a weak admin password, or a leftover admin account nobody remembers creating. If you want a fuller picture of how sites get compromised in the first place, see our guide on &lt;a href="https://bugcircuit.com/website-hacked" rel="noopener noreferrer"&gt;what to do when your website is hacked&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-step: fix it and request removal
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Confirm what Google found.&lt;/strong&gt; Go to Search Console's Security Issues report, or check your domain directly with the &lt;a href="https://transparencyreport.google.com/safe-browsing/search" rel="noopener noreferrer"&gt;Safe Browsing site status tool&lt;/a&gt; — it will tell you the flagged pages and the date detected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take the site into maintenance mode&lt;/strong&gt; if you can, so no visitors hit the deceptive content while you work. This isn't required, but it limits harm and buys you time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find and remove the malicious content.&lt;/strong&gt; Check recently modified files (&lt;code&gt;find /path/to/site -mtime -14 -type f&lt;/code&gt; on a Linux host is a good start), unfamiliar folders under &lt;code&gt;wp-content/uploads&lt;/code&gt;, unexpected &lt;code&gt;.htaccess&lt;/code&gt; redirect rules, and any admin users or plugins you don't recognize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Close the entry point.&lt;/strong&gt; Update WordPress core, every plugin, and every theme. Change all passwords — WP admin, hosting control panel, SFTP/FTP, and database. Remove any admin account you didn't create. If you use WordPress security salts, regenerate them via wp-config.php.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rescan to confirm it's clean.&lt;/strong&gt; Run the site through the Safe Browsing site status tool again, plus an independent scanner like Sucuri SiteCheck, before you submit anything to Google.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request a review.&lt;/strong&gt; In Search Console, open the Security Issues report for your verified property and click "Request Review." Briefly describe what was wrong and what you did to fix it — Google's own &lt;a href="https://developers.google.com/search/docs/monitor-debug/security/request-review" rel="noopener noreferrer"&gt;request-a-review guide&lt;/a&gt; covers the exact form fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wait it out.&lt;/strong&gt; Reviews commonly clear within a day or two once the site is genuinely clean, though Google doesn't publish a fixed turnaround time — resist the urge to resubmit repeatedly, which can slow things down rather than speed them up.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Before you hit submit: a quick checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Your domain is verified in Search Console (Domain or URL-prefix property)&lt;/li&gt;
&lt;li&gt;[ ] The specific flagged pages/files are gone, not just hidden&lt;/li&gt;
&lt;li&gt;[ ] All passwords (WP admin, hosting, FTP, database) have been changed&lt;/li&gt;
&lt;li&gt;[ ] Core, plugins, and themes are fully updated&lt;/li&gt;
&lt;li&gt;[ ] A fresh scan (Safe Browsing status + a second scanner) comes back clean&lt;/li&gt;
&lt;li&gt;[ ] You've noted what caused it, so it doesn't happen again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skipping any of these is the most common reason a review request gets rejected and the warning reappears a few days later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preventing a repeat
&lt;/h2&gt;

&lt;p&gt;Once you're clean, a few habits make this much less likely to happen again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep plugins/themes updated and delete ones you're not actively using — each one is a potential entry point&lt;/li&gt;
&lt;li&gt;Turn on strong security headers (our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers checker&lt;/a&gt; shows what's missing on your site)&lt;/li&gt;
&lt;li&gt;Use a web application firewall (Wordfence, Sucuri, or Cloudflare's proxy) to block common exploit attempts before they reach your code&lt;/li&gt;
&lt;li&gt;Require two-factor authentication for every admin account&lt;/li&gt;
&lt;li&gt;Run periodic malware scans rather than waiting for Google to tell you something's wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A free automated scanner catches known signatures, but the phishing pages and cloaked redirects that trigger Safe Browsing are often hand-placed by an attacker specifically to avoid detection — which is exactly the kind of thing a manual review is built to catch that an automated pass misses. If you want a second set of eyes, our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; gives you a fast yes/no read on whether anything critical is currently exposed, no card or login required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"Deceptive site ahead" is a Google Safe Browsing flag for phishing/social-engineering content — different from the address-bar "Not Secure" label (HTTPS issue) and Search Console's "This site may be hacked" (indexed spam)&lt;/li&gt;
&lt;li&gt;The usual cause is a hacked plugin, theme, or third-party embed that planted a fake login page, deceptive popup, or cloaked redirect&lt;/li&gt;
&lt;li&gt;Fix the content, patch the entry point, and rotate every credential before you request review — partial fixes are the top reason review requests fail&lt;/li&gt;
&lt;li&gt;Submit the review through Search Console's Security Issues report; don't resubmit repeatedly while waiting&lt;/li&gt;
&lt;li&gt;Add ongoing scanning and a WAF afterward so the same hole doesn't get exploited again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you'd rather have a human confirm the site is actually clean before you file the review — or trace exactly how the attacker got in — a Bug Circuit &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;manual audit&lt;/a&gt; starts at $49: a real engineer checks the whole site and hands you a written report with evidence and exact fixes, not just a scanner printout.&lt;/p&gt;

</description>
      <category>googlesafebrowsing</category>
      <category>phishing</category>
      <category>wordpresssecurity</category>
      <category>malwareremoval</category>
    </item>
    <item>
      <title>Is Wix or Squarespace Secure? What They Do &amp; Don't Cover</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Mon, 24 Aug 2026 23:12:15 +0000</pubDate>
      <link>https://dev.to/bugcircuit/is-wix-or-squarespace-secure-what-they-do-dont-cover-35a6</link>
      <guid>https://dev.to/bugcircuit/is-wix-or-squarespace-secure-what-they-do-dont-cover-35a6</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/is-wix-or-squarespace-secure-what-they-do-dont-cover" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yes, Wix and Squarespace are secure at the infrastructure level — but that only covers part of the risk, and the rest is on you.&lt;/strong&gt; Both platforms patch servers, run your site over HTTPS, and guard against the classic hosting-level attacks. Neither one protects a weak login password, a sketchy embedded script, a missing email record, or a page you forgot was still public.&lt;/p&gt;

&lt;p&gt;This is for owners running a small business, portfolio, or online store on Wix or Squarespace who want a straight answer: what's actually covered, what isn't, and what to check this week. You'll walk away with a concrete hardening checklist, not just reassurance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Wix and Squarespace Actually Secure For You
&lt;/h2&gt;

&lt;p&gt;Both companies run closed, managed platforms — you don't touch a server, install patches, or configure a firewall, because they do it centrally for every site on the platform. That buys you real protection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automatic HTTPS/SSL&lt;/strong&gt; on every domain, including custom domains, with certificates renewed for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server and software patching&lt;/strong&gt; handled centrally — you're never running an outdated CMS core like you would with self-hosted WordPress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DDoS mitigation and network-level filtering&lt;/strong&gt; at the hosting layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PCI DSS-compliant payment processing&lt;/strong&gt; if you use their built-in checkout, so you're not storing card numbers yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wix publishes its practices at &lt;a href="https://www.wix.com/about/security" rel="noopener noreferrer"&gt;wix.com/about/security&lt;/a&gt; and Squarespace at &lt;a href="https://www.squarespace.com/security" rel="noopener noreferrer"&gt;squarespace.com/security&lt;/a&gt; — both are worth a skim if a client ever sends you a security questionnaire.&lt;/p&gt;

&lt;p&gt;What this buys you is protection against the kind of attack that hits self-hosted CMS platforms hardest: an unpatched plugin or core file getting exploited directly. That specific risk mostly disappears on Wix or Squarespace. It does &lt;strong&gt;not&lt;/strong&gt; mean the site can't be compromised — it means the compromise happens somewhere else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Real Risk Actually Sits
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Risk area&lt;/th&gt;
&lt;th&gt;Covered by Wix/Squarespace?&lt;/th&gt;
&lt;th&gt;Who's responsible&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Server patching, SSL certificates&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DDoS protection at the network layer&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment card data (built-in checkout)&lt;/td&gt;
&lt;td&gt;Yes (PCI DSS)&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your account password &amp;amp; login security&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two-factor authentication (2FA) being turned on&lt;/td&gt;
&lt;td&gt;No — it's optional&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third-party embeds, widgets, and tracking scripts&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS records (SPF/DKIM/DMARC) for your domain&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unlisted, password-protected, or old draft pages&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Team member / collaborator access levels&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The pattern: the platform secures its own infrastructure. Everything you configure on top of it — accounts, embeds, DNS, page visibility — is yours to lock down. That's true of every hosted builder, not a knock against Wix or Squarespace specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Account Is the Weakest Point, Not Their Servers
&lt;/h2&gt;

&lt;p&gt;Most real-world Wix and Squarespace compromises don't involve hacking the platform at all — they involve someone getting into your account. Attackers don't need to break encryption if they can just log in.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Turn on two-factor authentication (2FA).&lt;/strong&gt; In Wix, go to Account Settings → Sign In &amp;amp; Security → Two-Factor Authentication. In Squarespace, it's under Account → Security → Two-Step Verification. This single step blocks the most common account-takeover method: a reused or leaked password.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a unique, long password&lt;/strong&gt; for your builder account — not one shared with any other site. &lt;a href="https://pages.nist.gov/800-63-3/sp800-63b.html" rel="noopener noreferrer"&gt;NIST's password guidelines&lt;/a&gt; recommend length over complexity: a random 16+ character passphrase beats "P@ssw0rd1!".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit collaborator access.&lt;/strong&gt; Both platforms let you add team members with different permission levels. Remove ex-contractors and freelancers as soon as a project ends — check Wix's Roles &amp;amp; Permissions or Squarespace's Contributors list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch for phishing emails&lt;/strong&gt; that mimic Wix or Squarespace login pages. These platforms are common phishing targets precisely because so many small businesses run on them.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Risky Embeds and Third-Party Apps
&lt;/h2&gt;

&lt;p&gt;Wix's App Market and Squarespace's extensions let you bolt on chat widgets, booking tools, review plugins, and marketing pixels in a couple of clicks. Convenient — and also the most common way a hosted site gets something malicious injected into it.&lt;/p&gt;

&lt;p&gt;An embedded third-party script runs in your visitors' browsers with the same trust as your own content. If that script is compromised, outdated, or was never legitimate to begin with, it can skim form data, redirect visitors, or inject unwanted content — a pattern OWASP documents broadly under &lt;a href="https://owasp.org/www-community/attacks/xss/" rel="noopener noreferrer"&gt;cross-site scripting (XSS)&lt;/a&gt;, where injected script runs in the context of a trusted page.&lt;/p&gt;

&lt;p&gt;Before adding any embed or custom code block:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only install apps from the official Wix App Market or Squarespace Extensions — never a script copy-pasted from a random tutorial or forum post.&lt;/li&gt;
&lt;li&gt;Check the app's last update date and review count. Abandoned apps are a common weak point.&lt;/li&gt;
&lt;li&gt;Remove embeds you no longer use — a dead chat widget or old A/B testing script is still a live piece of code running on every page.&lt;/li&gt;
&lt;li&gt;If you use a custom Code Injection block (Squarespace) or embed HTML widget (Wix), know exactly what every line does, or have someone who does review it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers checker&lt;/a&gt; will show you what protections your live site is actually sending, including whether a Content-Security-Policy is limiting what third-party scripts can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS and Email Spoofing: The Silent Risk
&lt;/h2&gt;

&lt;p&gt;This is the part almost every small business owner misses, because it has nothing to do with the website itself — it's about your domain's email records.&lt;/p&gt;

&lt;p&gt;When you point a custom domain at Wix or Squarespace, you also control DNS records that determine who's allowed to send email &lt;em&gt;as&lt;/em&gt; your domain. If those records are missing or misconfigured, anyone can forge an email that appears to come from you — invoicing your customers, phishing your team, or damaging your domain's reputation.&lt;/p&gt;

&lt;p&gt;The three records that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SPF&lt;/strong&gt; — lists which mail servers are allowed to send for your domain (e.g. &lt;code&gt;v=spf1 include:_spf.google.com ~all&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DKIM&lt;/strong&gt; — a cryptographic signature proving an email wasn't altered in transit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC&lt;/strong&gt; — tells receiving mail servers what to do with messages that fail SPF/DKIM checks, e.g. &lt;code&gt;v=DMARC1; p=quarantine; rua=mailto:reports@yourdomain.com&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CISA has directed U.S. federal agencies to enforce DMARC specifically because unauthenticated domains are so easy to spoof — see &lt;a href="https://www.cisa.gov/news-events/directives/binding-operational-directive-18-01" rel="noopener noreferrer"&gt;CISA Binding Operational Directive 18-01&lt;/a&gt;. The same logic applies to any business domain. Run our &lt;a href="https://bugcircuit.com/tools/email-spoofing" rel="noopener noreferrer"&gt;email spoofing checker&lt;/a&gt; to see in under a minute whether your domain can currently be impersonated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pages You Forgot Were Public
&lt;/h2&gt;

&lt;p&gt;Wix and Squarespace make it easy to spin up draft pages, staging content, old landing pages, or "unlisted" pages that aren't in your navigation menu. Unlisted is not the same as private — an unlisted page is still reachable by anyone who has or guesses the URL, and can still get indexed by search engines or found by an automated scanner.&lt;/p&gt;

&lt;p&gt;Quick check:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search &lt;code&gt;site:yourdomain.com&lt;/code&gt; in Google and skim every result — anything you don't recognize needs a look.&lt;/li&gt;
&lt;li&gt;In your site editor, review the full page list (not just the nav menu) for anything old, unfinished, or duplicated.&lt;/li&gt;
&lt;li&gt;Password-protect or delete pages containing pricing drafts, internal notes, or test content instead of just unlisting them.&lt;/li&gt;
&lt;li&gt;Check for old subdomains or preview URLs (like a &lt;code&gt;*.wixsite.com&lt;/code&gt; staging link) that are still live after you launched the real domain.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're not sure what's currently exposed, our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; scans the live, public-facing surface of your site — no login or card required — and gives you a plain-English yes/no on anything critical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Wix and Squarespace secure the servers, SSL, and payment processing — they do not secure your account, embeds, DNS, or forgotten pages.&lt;/li&gt;
&lt;li&gt;Turn on two-factor authentication today; weak or reused passwords are the most common way hosted sites actually get compromised.&lt;/li&gt;
&lt;li&gt;Audit every third-party app and embed for legitimacy and remove ones you no longer use.&lt;/li&gt;
&lt;li&gt;Add or verify SPF, DKIM, and DMARC records so nobody can spoof email from your domain.&lt;/li&gt;
&lt;li&gt;Search &lt;code&gt;site:yourdomain.com&lt;/code&gt; periodically to catch unlisted or forgotten pages before someone else finds them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've worked through this list and want a second, human set of eyes — someone who actually clicks through your site the way an attacker would rather than running an automated scan — that's exactly what &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit&lt;/a&gt; is: a $49 one-time manual audit with a full written report of what's wrong and exactly how to fix it. If you're still not sure whether your setup needs a closer look, start with our guide on &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;whether your website is hackable&lt;/a&gt; or, if something already looks off, see &lt;a href="https://bugcircuit.com/website-hacked" rel="noopener noreferrer"&gt;what to do if your website's been hacked&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>wixsecurity</category>
      <category>squarespacesecurity</category>
      <category>websitebuilders</category>
      <category>dns</category>
    </item>
    <item>
      <title>What Is CSRF? The Attack Using Your Login</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Sat, 22 Aug 2026 23:13:15 +0000</pubDate>
      <link>https://dev.to/bugcircuit/what-is-csrf-the-attack-using-your-login-5deg</link>
      <guid>https://dev.to/bugcircuit/what-is-csrf-the-attack-using-your-login-5deg</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/what-is-csrf-the-attack-using-your-login" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-site request forgery (CSRF) is an attack that tricks your browser into sending a real, authenticated request to a site you're logged into—like your admin panel—without you meaning to, so the attacker can change settings, add a user, or redirect a payout using your own login session.&lt;/strong&gt; No password is stolen. No malware is installed. Your browser just does what it's told, because it still thinks it's you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;This is for the owner or admin of a small business site—WordPress, Shopify, a custom-built dashboard, an indie SaaS—who wants a plain-English answer to "what is cross-site request forgery (CSRF)" and, more importantly, wants to know if their own admin panel is exposed. By the end you'll know exactly how the attack works, what a real one looks like, and the specific fix (a CSRF token) that makes it stop working.&lt;/p&gt;

&lt;h2&gt;
  
  
  How CSRF actually works, step by step
&lt;/h2&gt;

&lt;p&gt;CSRF abuses one basic fact about browsers: when you're logged into a site, your browser holds a &lt;strong&gt;session cookie&lt;/strong&gt;—a small file that proves "this browser belongs to a logged-in user"—and it attaches that cookie automatically to &lt;em&gt;every&lt;/em&gt; request sent to that site, no matter which page told the browser to send it.&lt;/p&gt;

&lt;p&gt;Here's the attack in practice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You log into your site's admin panel—say, &lt;code&gt;yourstore.com/admin&lt;/code&gt;—and leave the tab open, or close it but your session cookie stays valid.&lt;/li&gt;
&lt;li&gt;An attacker sends you a link, or you land on a page they control, containing a hidden form or image tag that points at an action on your own site, like adding a new admin user or changing a payout bank account.&lt;/li&gt;
&lt;li&gt;Your browser loads that hidden request. Because it's a request to &lt;code&gt;yourstore.com&lt;/code&gt;, your browser automatically attaches your valid session cookie—it has no way of knowing the request wasn't something you meant to click.&lt;/li&gt;
&lt;li&gt;If your site's admin panel doesn't check &lt;em&gt;where the request actually came from&lt;/em&gt;, it processes the request as if you clicked "save" yourself.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A minimal hidden form might look like this, sitting invisibly on an attacker's page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://yourstore.com/admin/add-user"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"f"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"attacker2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"role"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"admin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;f&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You never see a form. You never click "submit." The page just loads, the script fires, and if you were logged in as an admin at that moment, &lt;code&gt;attacker2&lt;/code&gt; is now an admin on your site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three things CSRF can actually do to your site
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Change a setting silently&lt;/strong&gt; — flip your store's shipping rules, disable two-factor authentication, or change the email address that receives password resets (redirecting future account recovery to the attacker).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a new user or admin&lt;/strong&gt; — the example above; once the attacker has their own admin account, they don't need your credentials at all going forward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect a payout or refund destination&lt;/strong&gt; — on payment or invoicing dashboards, a forged request to "update bank details" or "update payout email" can quietly reroute money on the next payment cycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice what's missing from all three: your password never left your head, and no malware touched your device. This is why CSRF is easy to underestimate—it doesn't look like a "hack" from the outside. It looks like an admin action, because technically, it was one—your browser just didn't ask you first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is possible: the same-origin gap
&lt;/h2&gt;

&lt;p&gt;Browsers enforce a rule called the &lt;strong&gt;same-origin policy&lt;/strong&gt;, which normally stops one website from &lt;em&gt;reading&lt;/em&gt; data from another. The problem is that same-origin policy doesn't stop a page from &lt;em&gt;sending&lt;/em&gt; a request to another site—it only stops it from reading the response. A hidden form submission or an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag pointed at a URL is a one-way request, and cookies get attached regardless of which page triggered it. OWASP's community page on CSRF has a good technical breakdown of this gap: &lt;a href="https://owasp.org/www-community/attacks/csrf" rel="noopener noreferrer"&gt;OWASP: Cross-Site Request Forgery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is also why CSRF has its own entry in the industry's standard weakness catalog, tracked as &lt;strong&gt;CWE-352&lt;/strong&gt;, maintained by MITRE: &lt;a href="https://cwe.mitre.org/data/definitions/352.html" rel="noopener noreferrer"&gt;CWE-352: Cross-Site Request Forgery&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual fix: CSRF tokens (and why they work)
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;CSRF token&lt;/strong&gt; is a random, unpredictable value the server generates and embeds in every form on your own site, tied to your current session. When the form is submitted, the server checks that the token in the request matches the one it issued.&lt;/p&gt;

&lt;p&gt;Here's why this stops the attack cold: the attacker's hidden form on their own page has no way to read the token, because reading it would require loading your admin page and inspecting its contents—which same-origin policy &lt;em&gt;does&lt;/em&gt; block. They can forge the request, but they can't forge a valid token to go with it.&lt;/p&gt;

&lt;p&gt;A typical implementation looks like this in the HTML your server renders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"/admin/add-user"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"hidden"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"csrf_token"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"f3a9c1e7b2d84a..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Add user&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the server side, that token is checked against the value stored in the user's session before the action runs. No match, no action—regardless of whether the cookie was valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other real defenses worth knowing about
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Defense&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Where to check it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CSRF tokens&lt;/td&gt;
&lt;td&gt;Per-session random value required on every state-changing form&lt;/td&gt;
&lt;td&gt;Custom code, most modern frameworks by default&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SameSite&lt;/code&gt; cookie attribute&lt;/td&gt;
&lt;td&gt;Tells the browser not to send the cookie on cross-site requests&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Set-Cookie: session=...; SameSite=Lax; Secure; HttpOnly&lt;/code&gt; in response headers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Re-authentication for sensitive actions&lt;/td&gt;
&lt;td&gt;Requires re-entering a password before changing payout/bank details or admin roles&lt;/td&gt;
&lt;td&gt;Payment dashboards, account settings pages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checking the &lt;code&gt;Origin&lt;/code&gt;/&lt;code&gt;Referer&lt;/code&gt; header&lt;/td&gt;
&lt;td&gt;Server rejects requests that didn't originate from your own domain&lt;/td&gt;
&lt;td&gt;Server-side middleware or WAF rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No state-changing GET requests&lt;/td&gt;
&lt;td&gt;Actions like "delete user" or "add admin" require POST, never a plain link&lt;/td&gt;
&lt;td&gt;Code review of admin routes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of these alone is bulletproof—&lt;code&gt;SameSite=Lax&lt;/code&gt; still allows some top-level navigation requests through, for instance—which is why a real audit checks for CSRF tokens &lt;em&gt;and&lt;/em&gt; cookie attributes &lt;em&gt;and&lt;/em&gt; how sensitive actions are gated, rather than assuming one setting covers everything. You can check your current cookie and header configuration for free with our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers scanner&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is your site actually exposed? A quick self-check
&lt;/h2&gt;

&lt;p&gt;You can spot obvious red flags yourself in a few minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Open your admin panel's "add user" or "change settings" form and view the page source (right-click → View Page Source). Look for a hidden input with a name like &lt;code&gt;csrf_token&lt;/code&gt;, &lt;code&gt;_token&lt;/code&gt;, or &lt;code&gt;authenticity_token&lt;/code&gt;. If you don't see one, that form may be forgeable.&lt;/li&gt;
&lt;li&gt;[ ] Check whether any admin action can be triggered by just visiting a URL (a plain GET link) rather than submitting a form—those are especially easy to forge.&lt;/li&gt;
&lt;li&gt;[ ] If you're on WordPress, confirm you're not running custom form handlers or plugins that skip WordPress's built-in &lt;code&gt;wp_nonce_field()&lt;/code&gt; protection—this is a common source of CSRF gaps in older or poorly maintained plugins.&lt;/li&gt;
&lt;li&gt;[ ] If you use a custom-built admin dashboard, ask your developer directly whether CSRF tokens are implemented on every state-changing route, not just login.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of this is unclear, that's exactly the kind of thing a manual review is built to catch—automated scanners often miss CSRF because they can't tell a legitimate form submission from a forged one without understanding your app's logic. Our &lt;a href="https://bugcircuit.com/guides/manual-vs-automated-penetration-testing" rel="noopener noreferrer"&gt;guide to manual vs. automated penetration testing&lt;/a&gt; walks through why that distinction matters here specifically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSRF doesn't steal your password—it hijacks your already-logged-in browser session to submit a real, authenticated request on your behalf.&lt;/li&gt;
&lt;li&gt;The tell-tale sign of exposure is a state-changing form (add user, change payout, disable 2FA) with no hidden CSRF token and no re-authentication step.&lt;/li&gt;
&lt;li&gt;CSRF tokens work because the attacker's page can never read a value they'd need same-origin access to see.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SameSite=Strict&lt;/code&gt; or &lt;code&gt;SameSite=Lax&lt;/code&gt; cookies add a strong second layer, but shouldn't be your only defense—check your current settings with our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers tool&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you're not sure your admin panel or payment dashboard is protected, that uncertainty is worth resolving before an attacker finds it first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want a straight answer on whether your specific site is exposed to this—not a generic checklist, but someone actually testing your login flows and forms—that's what a manual audit is for. &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit&lt;/a&gt; is a one-time $49 human review of your whole site with exact fixes, or you can start with our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; if you just want a fast yes/no first.&lt;/p&gt;

</description>
      <category>csrf</category>
      <category>websecurity</category>
      <category>sessionsecurity</category>
      <category>csrftokens</category>
    </item>
    <item>
      <title>Is Shopify Secure? What You Still Own</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Fri, 21 Aug 2026 17:12:38 +0000</pubDate>
      <link>https://dev.to/bugcircuit/is-shopify-secure-what-you-still-own-11l</link>
      <guid>https://dev.to/bugcircuit/is-shopify-secure-what-you-still-own-11l</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/is-shopify-secure-what-you-still-own" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yes, Shopify's core platform is secure — but that only covers Shopify's servers, checkout, and payment processing. Everything you install, write, or click on top of it (apps, themes, staff logins, custom code) is your responsibility, and that's where most Shopify stores actually get breached.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for Shopify store owners, admins, and freelancers who assume "Shopify handles security" and want to know exactly where that stops. You'll get a plain map of the shared-responsibility line, a table you can point to when a client or investor asks, and a self-check you can run in the next 10 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short answer: yes, and no
&lt;/h2&gt;

&lt;p&gt;Shopify's own infrastructure is genuinely well-built. It runs as a PCI DSS Level 1 service provider, which means the servers, checkout, and card processing meet the strictest tier of the payment card industry's security standard — the same tier as major banks and processors. You don't need to manage firewalls, patch servers, or encrypt card data yourself; Shopify does that layer for you, and merchants inherit much of that compliance automatically when they use Shopify Payments and hosted checkout (&lt;a href="https://help.shopify.com/en/manual/payments/pci-compliance" rel="noopener noreferrer"&gt;Shopify's PCI compliance guide&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;But "the platform is secure" and "my store is secure" are two different claims. Shopify draws a clear line, common to every cloud platform: they secure the platform, you secure what you build on it. That's the same shared-responsibility model AWS, Google Cloud, and every SaaS vendor uses — it's just rarely explained to small merchants in plain terms.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Shopify actually secures
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Servers and network infrastructure&lt;/strong&gt; — DDoS protection, uptime, patching the underlying systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checkout and payment processing&lt;/strong&gt; — encrypted card data, PCI DSS Level 1 compliance, fraud-detection signals on Shopify Payments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform-level vulnerabilities&lt;/strong&gt; — bugs in Shopify's own core code (the admin, storefront engine, checkout) are Shopify's to find and patch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTPS on your storefront&lt;/strong&gt; — Shopify auto-provisions and renews SSL certificates for your &lt;code&gt;myshopify.com&lt;/code&gt; and connected domains.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's real, meaningful security — and it's why Shopify stores don't need to worry about the things a self-hosted store (say, raw WordPress with WooCommerce) has to manage manually, like server patching or SSL renewal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you still own
&lt;/h2&gt;

&lt;p&gt;Here's where the myth breaks. Everything below sits outside Shopify's platform boundary, and a vulnerability in any of them can expose customer data, redirect checkout, or hand an attacker your admin panel — even though "Shopify" never had a bug.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apps
&lt;/h3&gt;

&lt;p&gt;Every app you install gets a scope of permissions — often read/write access to customers, orders, or even your theme code. A poorly coded or abandoned app is a door Shopify can't close for you; it's not part of Shopify's own codebase. This mirrors the exact risk category OWASP calls out as &lt;a href="https://owasp.org/Top10/A06_2021-Vulnerable_and_Outdated_Components/" rel="noopener noreferrer"&gt;"Vulnerable and Outdated Components"&lt;/a&gt; — third-party code you didn't write but now depend on.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Audit installed apps quarterly under &lt;strong&gt;Settings → Apps and sales channels&lt;/strong&gt;. Remove anything not actively used.&lt;/li&gt;
&lt;li&gt;Check what data scope an app requests before installing (visible on the install screen) — a countdown-timer app doesn't need customer PII access.&lt;/li&gt;
&lt;li&gt;Favor apps still receiving updates; an app last updated three years ago is a red flag, not a bargain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Themes and custom Liquid
&lt;/h3&gt;

&lt;p&gt;Liquid is Shopify's templating language for building themes. Custom &lt;code&gt;.liquid&lt;/code&gt; code, injected third-party scripts (chat widgets, pixels, upsell snippets), and hardcoded API keys in theme files are all your responsibility. A common real mistake: a developer pastes a private API key into &lt;code&gt;theme.liquid&lt;/code&gt; for a "quick fix," and it ships to every visitor's browser, publicly readable in page source.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Never hardcode API tokens or secrets in theme files — use app proxy or backend calls instead.&lt;/li&gt;
&lt;li&gt;Remove old third-party scripts you no longer use; each one is an extra piece of code with checkout-adjacent access.&lt;/li&gt;
&lt;li&gt;If you use Checkout Extensibility or Shopify Functions for custom logic, keep that code in a private repo with a review step before deploy, not edited live in the admin.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Staff access
&lt;/h3&gt;

&lt;p&gt;Every staff account is a potential entry point. Shopify supports granular admin permissions — most stores don't use them, defaulting everyone to broad access instead.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings → Users and permissions&lt;/strong&gt; and give each staff member only the permissions their job needs (e.g., a support rep doesn't need "Manage settings" or theme access).&lt;/li&gt;
&lt;li&gt;Turn on &lt;a href="https://help.shopify.com/en/manual/your-account/security/two-step-verification" rel="noopener noreferrer"&gt;two-step verification&lt;/a&gt; for every staff login — Shopify has required it for account owners since 2022, and you should require it for staff too.&lt;/li&gt;
&lt;li&gt;Remove access immediately when someone leaves — an ex-contractor with a live login is one of the most common, least glamorous breach paths.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Phishing and social engineering
&lt;/h3&gt;

&lt;p&gt;Attackers don't need a Shopify vulnerability if they can just ask nicely. Fake "Shopify Support" emails asking you to "verify your account" or install a "required" app are a known pattern targeting merchants — CISA's general guidance on recognizing these tactics applies directly here: never click login links from email, always type &lt;code&gt;admin.shopify.com&lt;/code&gt; directly, and verify unexpected requests through a second channel (&lt;a href="https://www.cisa.gov/news-events/news/avoiding-social-engineering-and-phishing-attacks" rel="noopener noreferrer"&gt;CISA: Avoiding Social Engineering and Phishing Attacks&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bookmark your admin URL instead of clicking email links to log in.&lt;/li&gt;
&lt;li&gt;Set up SPF, DKIM, and DMARC on your sending domain so attackers can't easily spoof "you" in phishing emails to your customers — check yours with our &lt;a href="https://bugcircuit.com/tools/email-spoofing" rel="noopener noreferrer"&gt;email spoofing checker&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Train staff that Shopify will never ask for your password by email or DM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The shared-responsibility line, at a glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Who secures it&lt;/th&gt;
&lt;th&gt;Real examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Servers, network, uptime&lt;/td&gt;
&lt;td&gt;Shopify&lt;/td&gt;
&lt;td&gt;DDoS protection, patching, infrastructure hardening&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checkout &amp;amp; payment processing&lt;/td&gt;
&lt;td&gt;Shopify&lt;/td&gt;
&lt;td&gt;PCI DSS Level 1 compliance, card data encryption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storefront SSL/HTTPS&lt;/td&gt;
&lt;td&gt;Shopify&lt;/td&gt;
&lt;td&gt;Auto-issued and renewed certificates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Installed apps&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Permission scopes, app vulnerabilities, abandoned apps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Theme &amp;amp; custom Liquid code&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Hardcoded keys, injected scripts, insecure customizations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Staff accounts &amp;amp; permissions&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Weak passwords, over-broad access, ex-employee logins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain, DNS, email&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;SPF/DKIM/DMARC, registrar account, domain lock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phishing awareness&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;td&gt;Fake support emails, credential theft, malicious app links&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  10-minute Shopify security self-check
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Two-step verification is on for every staff account, not just the owner.&lt;/li&gt;
&lt;li&gt;[ ] Staff permissions in &lt;strong&gt;Settings → Users and permissions&lt;/strong&gt; match actual job needs.&lt;/li&gt;
&lt;li&gt;[ ] You've reviewed installed apps in the last 3 months and removed unused ones.&lt;/li&gt;
&lt;li&gt;[ ] No API keys or secrets are hardcoded in your theme's &lt;code&gt;.liquid&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;[ ] SPF/DKIM/DMARC are set up on your store's sending domain.&lt;/li&gt;
&lt;li&gt;[ ] You always type your admin URL directly instead of clicking email links to log in.&lt;/li&gt;
&lt;li&gt;[ ] Response headers on your storefront (CSP, X-Frame-Options, etc.) are reviewed — run a free check with our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers scanner&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you checked all seven, you're ahead of most stores. If you're not sure about several, that uncertainty is itself the finding — it usually means no one has actually looked at the store-level risks since launch. Our guide on &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;whether your website is hackable&lt;/a&gt; walks through the warning signs in more depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a manual look actually helps
&lt;/h2&gt;

&lt;p&gt;An automated scanner can flag a missing security header in seconds, but it can't tell you that a marketing app has write access to your customer list it doesn't need, or that a staff account from a former employee is still active, or that a snippet a freelancer added two years ago is quietly loading a script from a domain that no longer exists. Those are judgment calls a human reviewer makes by actually looking at your store's configuration — the difference we cover in &lt;a href="https://bugcircuit.com/guides/manual-vs-automated-penetration-testing" rel="noopener noreferrer"&gt;manual vs. automated penetration testing&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Shopify secures the platform (servers, checkout, PCI compliance) — you secure everything layered on top of it: apps, themes, staff access, and your team's judgment.&lt;/li&gt;
&lt;li&gt;Audit installed apps and their permission scopes quarterly; remove anything unused or unmaintained.&lt;/li&gt;
&lt;li&gt;Turn on two-step verification for every staff login and scope permissions to the job, not the person.&lt;/li&gt;
&lt;li&gt;Never click email links to log into your admin — type the URL directly, and set up SPF/DKIM/DMARC so attackers can't spoof your domain.&lt;/li&gt;
&lt;li&gt;A missing header or an unused app with broad access won't show up by guessing — a manual review of your actual store configuration will.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've read this far and you're not fully sure where your store stands on the checklist above, that's exactly what a manual audit is for. &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit&lt;/a&gt;, our $49 one-time review, has a real person go through your store's apps, theme code, and configuration and hand you a plain-English report of what's actually exposed — not a certification, not a guess, just what's true about your specific store right now.&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>ecommercesecurity</category>
      <category>sharedresponsibility</category>
      <category>phishing</category>
    </item>
    <item>
      <title>WooCommerce Security Checklist for Stores</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Thu, 20 Aug 2026 11:12:21 +0000</pubDate>
      <link>https://dev.to/bugcircuit/woocommerce-security-checklist-for-stores-3jk5</link>
      <guid>https://dev.to/bugcircuit/woocommerce-security-checklist-for-stores-3jk5</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/woocommerce-security-checklist-for-stores" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fastest way to leak customer data on WooCommerce isn't a genius hacker — it's a forgotten plugin update or a stale WordPress core, and you can close both gaps today.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for store owners running WooCommerce on WordPress who are worried about a breach hitting customer names, addresses, or order history — not developers looking for a code audit. You'll get a concrete checklist you can work through in one sitting, in the order that actually reduces risk fastest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real risk isn't your server holding credit cards
&lt;/h2&gt;

&lt;p&gt;Most WooCommerce owners picture a breach as someone stealing credit card numbers off their server. In a properly configured store, that's not actually where the risk lives — if you use Stripe, PayPal, or another hosted payment gateway, card numbers never touch your database at all; they go straight from the customer's browser to the payment processor.&lt;/p&gt;

&lt;p&gt;The real exposure is everything else: names, emails, shipping addresses, order history, and admin credentials, sitting in a WordPress database that's reachable through whichever of your 15 plugins hasn't been updated since last year. WordPress core, WooCommerce, and every plugin you install are all separate pieces of software with separate vulnerabilities — and CISA's Known Exploited Vulnerabilities catalog is full of exactly this pattern: attackers scanning the web for sites still running a patched-months-ago plugin version. &lt;a href="https://www.cisa.gov/known-exploited-vulnerabilities-catalog" rel="noopener noreferrer"&gt;CISA KEV Catalog&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The checklist: do these in order
&lt;/h2&gt;

&lt;p&gt;Work down this list top to bottom — it's ordered by how much risk each item removes per minute spent.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;th&gt;How often&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Update WordPress core, WooCommerce, theme, and every plugin&lt;/td&gt;
&lt;td&gt;Unpatched software is the #1 entry point attackers scan for&lt;/td&gt;
&lt;td&gt;Weekly, or auto-update minor versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Delete plugins/themes you're not actively using&lt;/td&gt;
&lt;td&gt;Inactive code still runs and still has vulnerabilities&lt;/td&gt;
&lt;td&gt;Today, then quarterly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Turn on two-factor authentication (2FA) for every admin/shop manager account&lt;/td&gt;
&lt;td&gt;Stops stolen passwords from being enough to log in&lt;/td&gt;
&lt;td&gt;Today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Confirm your payment gateway is hosted checkout / tokenized (Stripe, PayPal, Square)&lt;/td&gt;
&lt;td&gt;Your server never stores or sees full card numbers&lt;/td&gt;
&lt;td&gt;Verify today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Set &lt;code&gt;DISALLOW_FILE_EDIT&lt;/code&gt; to true in wp-config.php&lt;/td&gt;
&lt;td&gt;Blocks attackers who get admin access from editing theme/plugin code&lt;/td&gt;
&lt;td&gt;Today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Add strong security headers (HSTS, CSP, X-Frame-Options)&lt;/td&gt;
&lt;td&gt;Reduces damage from XSS and clickjacking&lt;/td&gt;
&lt;td&gt;Today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Confirm off-site, automated backups are running&lt;/td&gt;
&lt;td&gt;Lets you recover instead of paying a ransom or rebuilding&lt;/td&gt;
&lt;td&gt;Verify today, then weekly checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Rename or remove the default "admin" username; enforce unique logins per staff member&lt;/td&gt;
&lt;td&gt;Stops credential-stuffing and makes breach forensics possible&lt;/td&gt;
&lt;td&gt;Today&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Install a WordPress firewall/malware scanner (Wordfence, Sucuri, or your host's WAF)&lt;/td&gt;
&lt;td&gt;Blocks known attack patterns before they hit your code&lt;/td&gt;
&lt;td&gt;Today, monitor weekly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Review user roles — no one has Administrator who only needs Shop Manager&lt;/td&gt;
&lt;td&gt;Limits what a compromised account can do&lt;/td&gt;
&lt;td&gt;Monthly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Update discipline: the single biggest lever
&lt;/h2&gt;

&lt;p&gt;Open &lt;strong&gt;WordPress admin → Dashboard → Updates&lt;/strong&gt; right now and clear everything queued. Then set a recurring habit:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable automatic updates for minor WordPress core releases (Settings → this is on by default since WP 3.7 for security releases).&lt;/li&gt;
&lt;li&gt;Update WooCommerce itself as soon as a new version drops — check the changelog for "security" or "vulnerability" language first.&lt;/li&gt;
&lt;li&gt;Go through every installed plugin individually. If a plugin hasn't been updated by its developer in over a year, treat that as a red flag even if no known vulnerability is public yet.&lt;/li&gt;
&lt;li&gt;Delete anything deactivated. A disabled plugin sitting in &lt;code&gt;/wp-content/plugins/&lt;/code&gt; is still a live target if its files are reachable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This single habit closes more real-world breach paths than almost anything else on this list — most WordPress compromises trace back to a known, already-patched vulnerability in outdated software, which is exactly the pattern OWASP flags under "Vulnerable and Outdated Components" in its Top 10 risks. &lt;a href="https://owasp.org/www-project-top-ten/" rel="noopener noreferrer"&gt;OWASP Top 10&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lock down who can log in
&lt;/h2&gt;

&lt;p&gt;Your wp-admin login is the front door. Harden it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enforce 2FA&lt;/strong&gt; for every account with admin or shop manager access — WP 2FA and Wordfence both offer free options.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kill the shared "admin" account.&lt;/strong&gt; Give every staff member and contractor their own login tied to their name, and remove access the day they leave.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit login attempts.&lt;/strong&gt; Most security plugins add this by default — it stops brute-force password guessing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set roles correctly.&lt;/strong&gt; A customer service rep processing refunds needs Shop Manager, not Administrator. Fewer people with full access means less damage if one account is compromised.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable XML-RPC&lt;/strong&gt; if you don't use the WordPress mobile app or Jetpack — it's a common brute-force and DDoS amplification target.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WordPress.org's own hardening guide covers the server-level version of these steps if you manage your own hosting. &lt;a href="https://wordpress.org/support/article/hardening-wordpress/" rel="noopener noreferrer"&gt;WordPress.org: Hardening WordPress&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep card data off your server entirely
&lt;/h2&gt;

&lt;p&gt;This is the one that keeps owners up at night, and it's also the one with the cleanest fix: &lt;strong&gt;never let WooCommerce or your server touch a raw card number.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a gateway that tokenizes on the customer's browser — Stripe, Square, and PayPal's hosted fields all do this. WooCommerce's own checkout blocks integrate directly with these.&lt;/li&gt;
&lt;li&gt;If you're on an older, custom-built checkout that stores card fields locally, migrate off it. That configuration puts you in a much heavier PCI DSS assessment category.&lt;/li&gt;
&lt;li&gt;Confirm your gateway plugin settings show "hosted fields" or "tokenized" rather than a raw credit card number field rendered on your own domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Done this way, you typically qualify for the simplest PCI compliance self-assessment (SAQ A), because card data never enters your environment. The Payment Card Industry Security Standards Council publishes the official criteria for which SAQ applies to your setup. &lt;a href="https://www.pcisecuritystandards.org/" rel="noopener noreferrer"&gt;PCI Security Standards Council&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add security headers your browser already understands
&lt;/h2&gt;

&lt;p&gt;Headers are instructions your server sends telling browsers how to treat your site defensively. Add these via your host, a plugin like Wordfence, or your &lt;code&gt;.htaccess&lt;/code&gt;/nginx config:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Strict-Transport-Security: max-age=31536000; includeSubDomains&lt;/code&gt; — forces HTTPS, blocking downgrade attacks.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt; — stops your checkout page from being embedded in a malicious iframe (clickjacking).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt; — stops browsers from misinterpreting uploaded files as executable scripts.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Content-Security-Policy&lt;/code&gt; — restricts which domains can load scripts on your site, a strong defense against injected skimmer scripts (a real WooCommerce attack pattern known as Magecart-style card skimming).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check what's currently set on your live store, free, with our &lt;a href="https://bugcircuit.com/tools/security-headers" rel="noopener noreferrer"&gt;security headers scanner&lt;/a&gt; — most WooCommerce sites are missing at least two of these out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back it up before anything else breaks
&lt;/h2&gt;

&lt;p&gt;A backup won't stop a breach, but it's the difference between a bad afternoon and losing your store. Confirm you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated, scheduled backups (daily for active stores) stored &lt;strong&gt;off&lt;/strong&gt; the same server — UpdraftPlus, host-native backups, or your hosting provider's snapshot system.&lt;/li&gt;
&lt;li&gt;At least one backup you've actually tested restoring, not just one you assume works.&lt;/li&gt;
&lt;li&gt;Database backups included, not just files — WooCommerce order and customer data lives in the database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Outdated WordPress core, WooCommerce, or plugins are the most common way small stores get breached — update weekly and delete what you don't use.&lt;/li&gt;
&lt;li&gt;Use a tokenized checkout (Stripe, PayPal, Square) so raw card numbers never touch your server — this also keeps your PCI compliance burden minimal.&lt;/li&gt;
&lt;li&gt;Turn on 2FA, kill shared admin logins, and match user roles to what each person actually needs.&lt;/li&gt;
&lt;li&gt;Add HSTS, CSP, and X-Frame-Options headers, and confirm off-site backups are actually running and restorable.&lt;/li&gt;
&lt;li&gt;A checklist catches configuration gaps; it won't catch a logic flaw or an exposed endpoint specific to your setup — that takes a person actually testing your live site.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Working through this list yourself fixes the common, well-known gaps. What it can't do is find the issue unique to &lt;em&gt;your&lt;/em&gt; store — a misconfigured REST API endpoint, a coupon logic flaw, an exposed staging URL. That's the gap a real &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;manual security audit&lt;/a&gt; closes: a person actually testing your checkout and admin, not a scanner running the same generic ruleset every other site gets. If you want a free first read before spending anything, our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free website security check&lt;/a&gt; will tell you, no card required, whether anything critical is already exposed.&lt;/p&gt;

</description>
      <category>woocommerce</category>
      <category>wordpresssecurity</category>
      <category>ecommerce</category>
      <category>pcicompliance</category>
    </item>
    <item>
      <title>How to Stop Brute-Force Attacks on WordPress Login</title>
      <dc:creator>Bug Circuit</dc:creator>
      <pubDate>Sun, 16 Aug 2026 23:12:43 +0000</pubDate>
      <link>https://dev.to/bugcircuit/how-to-stop-brute-force-attacks-on-wordpress-login-kbc</link>
      <guid>https://dev.to/bugcircuit/how-to-stop-brute-force-attacks-on-wordpress-login-kbc</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://bugcircuit.com/blog/how-to-stop-brute-force-attacks-on-wordpress-login" rel="noopener noreferrer"&gt;Bug Circuit blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You stop WordPress brute-force login attacks by rate-limiting failed login attempts, requiring two-factor authentication, and closing off the two doors attackers actually use — &lt;code&gt;wp-login.php&lt;/code&gt; and &lt;code&gt;xmlrpc.php&lt;/code&gt; — while skipping the tweaks that feel like security but don't add real protection.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is for anyone running WordPress — a small business owner, an agency managing client sites, or a solo blogger — who's noticed a wall of failed login attempts in their logs, or just wants to get ahead of it. You'll get a step-by-step hardening stack with exact plugin names and config snippets, plus an honest breakdown of what's real defense versus what's just theater.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a brute-force attack on WordPress actually looks like
&lt;/h2&gt;

&lt;p&gt;Most WordPress attacks aren't a person typing passwords by hand. They're bots working through a list — either guessing many passwords against one username (classic brute force), or trying username/password pairs leaked from &lt;em&gt;other&lt;/em&gt; breaches against your site (credential stuffing, per &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Credential_Stuffing_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP's Credential Stuffing Prevention Cheat Sheet&lt;/a&gt;). Both hit &lt;code&gt;/wp-login.php&lt;/code&gt; (and &lt;code&gt;/wp-admin/&lt;/code&gt;, which just redirects there) at high volume, hoping your admin account uses a weak or reused password.&lt;/p&gt;

&lt;p&gt;There's a second, less obvious front: &lt;code&gt;xmlrpc.php&lt;/code&gt;. This is WordPress's legacy remote-publishing API, and its &lt;code&gt;system.multicall&lt;/code&gt; method lets an attacker bundle hundreds of username/password guesses into a &lt;em&gt;single&lt;/em&gt; HTTP request. That means basic rate limiting — which usually counts requests, not the login attempts hidden inside them — can miss it entirely. This is one of the most useful facts in this guide, because most login-hardening advice ignores it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hardening stack: what matters vs. what's theater
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Defense&lt;/th&gt;
&lt;th&gt;Actually stops brute force?&lt;/th&gt;
&lt;th&gt;Effort&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Rate-limit / lock out after failed attempts&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Low (plugin)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two-factor authentication (2FA)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Low–medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disable or restrict XML-RPC&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong, unique passwords + no shared logins&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WAF / edge rate limiting (e.g. Cloudflare)&lt;/td&gt;
&lt;td&gt;Yes, blocks before WordPress even loads&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hide/rename &lt;code&gt;wp-login.php&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Partial — cuts noise, not a real barrier&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename the "admin" username&lt;/td&gt;
&lt;td&gt;Partial — stops the laziest bots only&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Login CAPTCHA&lt;/td&gt;
&lt;td&gt;Partial — slows automation, not a full stop&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you only have time for two things, do the first two rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Limit login attempts and lock accounts out
&lt;/h2&gt;

&lt;p&gt;Install &lt;strong&gt;Limit Login Attempts Reloaded&lt;/strong&gt; (free, wordpress.org) and configure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lockout after &lt;strong&gt;4 failed attempts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Lockout duration: &lt;strong&gt;20 minutes&lt;/strong&gt;, doubling on repeat offenses.&lt;/li&gt;
&lt;li&gt;"Cookie-based brute-force protection" and IP logging turned on so you can see who's knocking.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're behind Cloudflare (even the free tier), add a rate-limiting rule: block or CAPTCHA-challenge any IP sending more than 5 POST requests to &lt;code&gt;/wp-login.php&lt;/code&gt; within 1 minute. Edge-level rate limiting stops traffic before it ever reaches your server, which matters if you're on shared hosting where WordPress itself can get overwhelmed just processing the attempts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Turn on two-factor authentication (2FA)
&lt;/h2&gt;

&lt;p&gt;This is the single highest-leverage step. Even if a bot guesses your password, it still can't log in without the second factor. Use the official &lt;strong&gt;Two Factor&lt;/strong&gt; plugin (wordpress.org, maintained by WordPress core contributors) or the 2FA module in Wordfence or Solid Security (formerly iThemes Security). Enforce it on every account with Administrator or Editor access — not just yours. CISA lists multi-factor authentication as one of the highest-impact steps anyone can take to prevent account takeover; see their &lt;a href="https://www.cisa.gov/secure-our-world/turn-mfa" rel="noopener noreferrer"&gt;guidance on turning on MFA&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Disable or restrict XML-RPC
&lt;/h2&gt;

&lt;p&gt;Most sites don't need XML-RPC anymore — WordPress 5.6+ added Application Passwords (under &lt;strong&gt;Users → Profile → Application Passwords&lt;/strong&gt;) and a REST API that cover what the old Jetpack/mobile-app integrations used it for. If you don't use the WordPress mobile app or Jetpack's older connection method, block it outright.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache (.htaccess):&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;Files xmlrpc.php&amp;gt;
Require all denied
&amp;lt;/Files&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 plaintext"&gt;&lt;code&gt;location = /xmlrpc.php {
    deny all;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you &lt;em&gt;do&lt;/em&gt; need XML-RPC (some Jetpack features still use it), don't disable the whole file — just remove the dangerous multicall method with a small must-use plugin:&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="nf"&gt;add_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s1"&gt;'xmlrpc_methods'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$methods&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$methods&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'system.multicall'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$methods&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;h2&gt;
  
  
  Step 4: IP-level lockout with fail2ban (self-managed servers/VPS)
&lt;/h2&gt;

&lt;p&gt;If you manage your own server, install the &lt;strong&gt;WP fail2ban&lt;/strong&gt; plugin, which logs failed WordPress login attempts to syslog in a format fail2ban can parse, then add a jail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[wordpress]
enabled  = true
filter   = wordpress
logpath  = /var/log/auth.log
maxretry = 5
findtime = 600
bantime  = 3600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This bans the &lt;em&gt;IP address&lt;/em&gt; at the firewall level after repeated failures — the attacker can't even reach &lt;code&gt;wp-login.php&lt;/code&gt; again, not just get denied by it. On managed hosting (WP Engine, Kinsey, most shared hosts) you won't have shell access for this; lean on your host's built-in brute-force protection instead, which most reputable WordPress hosts now include.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Hiding wp-login.php — useful, but don't count on it
&lt;/h2&gt;

&lt;p&gt;Plugins like &lt;strong&gt;WPS Hide Login&lt;/strong&gt; let you change your login URL from &lt;code&gt;/wp-login.php&lt;/code&gt; to something custom, like &lt;code&gt;/portal-access&lt;/code&gt;. This is "security through obscurity" — it doesn't fix a vulnerability, it just makes your site a less visible target to the dumbest, most generic bots scanning the entire internet for &lt;code&gt;/wp-login.php&lt;/code&gt;. It genuinely does cut down log noise and server load. It should never be your &lt;em&gt;only&lt;/em&gt; defense, because a single leaked link, a misconfigured cache, or a targeted attacker (rather than a mass scanner) bypasses it instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's mostly theater
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Renaming the "admin" username alone&lt;/strong&gt; — helps against the laziest scripts, does nothing against credential stuffing using real emails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A CAPTCHA with no rate limiting behind it&lt;/strong&gt; — slows bots down, doesn't stop a patient attacker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"We're secure" trust badges&lt;/strong&gt; — cosmetic, provide zero technical protection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are harmful to have, but don't let them substitute for 2FA and rate limiting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick setup checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Login lockout after 4–5 failed attempts (plugin or edge rule)&lt;/li&gt;
&lt;li&gt;[ ] 2FA enforced on every admin/editor account&lt;/li&gt;
&lt;li&gt;[ ] XML-RPC blocked, or &lt;code&gt;system.multicall&lt;/code&gt; removed if you need it&lt;/li&gt;
&lt;li&gt;[ ] Unique, strong passwords — no shared logins across staff&lt;/li&gt;
&lt;li&gt;[ ] fail2ban or host-level IP lockout if you're on a VPS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.toOptional"&gt; &lt;/a&gt; login URL hidden to cut down bot noise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not sure any of this is actually configured correctly on your site, &lt;a href="https://wordpress.org/documentation/article/hardening-wordpress/" rel="noopener noreferrer"&gt;WordPress.org's own hardening guide&lt;/a&gt; is a solid technical reference to check settings against — or run our &lt;a href="https://bugcircuit.com/free-website-security-check" rel="noopener noreferrer"&gt;free passive security check&lt;/a&gt; to see what's exposed without touching your site.&lt;/p&gt;

&lt;p&gt;If you're already seeing signs something's wrong — unfamiliar admin users, spam pages appearing, a host warning you — that's a different problem than prevention; our &lt;a href="https://bugcircuit.com/website-hacked" rel="noopener noreferrer"&gt;guide on what to do if your website's been hacked&lt;/a&gt; walks through the recovery steps. And if you're just trying to figure out your overall exposure before it gets to that point, our guide on &lt;a href="https://bugcircuit.com/guides/is-my-website-hackable" rel="noopener noreferrer"&gt;how to tell if your website is hackable&lt;/a&gt; is a good next read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rate limiting plus two-factor authentication stops the overwhelming majority of WordPress brute-force attempts — everything else is secondary.&lt;/li&gt;
&lt;li&gt;XML-RPC's &lt;code&gt;system.multicall&lt;/code&gt; lets attackers test hundreds of passwords in one request, so basic rate limiting alone can miss it — block or restrict it directly.&lt;/li&gt;
&lt;li&gt;Hiding &lt;code&gt;wp-login.php&lt;/code&gt; reduces bot noise but is not a real security control on its own.&lt;/li&gt;
&lt;li&gt;Renaming the "admin" username and adding a CAPTCHA are minor helpers, not defenses — don't rely on them alone.&lt;/li&gt;
&lt;li&gt;If you manage your own server, fail2ban with the WP fail2ban plugin adds real IP-level lockout; on managed hosting, confirm your host already does this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hardening login is one piece of the picture — it won't catch a vulnerable plugin, an outdated theme, or a misconfigured form elsewhere on the site. A &lt;a href="https://bugcircuit.com/pricing" rel="noopener noreferrer"&gt;Circuit audit&lt;/a&gt; is $49 and gets a real person manually checking your whole site, not just the login page, with a written report of exactly what's wrong and how to fix it. No pressure — it's just the honest next step once the login is locked down.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>bruteforce</category>
      <category>loginsecurity</category>
      <category>xmlrpc</category>
    </item>
  </channel>
</rss>
