<?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: Radosław Fedorczuk</title>
    <description>The latest articles on DEV Community by Radosław Fedorczuk (@_abbdc2).</description>
    <link>https://dev.to/_abbdc2</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%2F1638908%2Ff78640fb-9cfc-4468-9a46-270841633531.jpg</url>
      <title>DEV Community: Radosław Fedorczuk</title>
      <link>https://dev.to/_abbdc2</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_abbdc2"/>
    <language>en</language>
    <item>
      <title>How bots probe a small website, and the six answers they hope to get</title>
      <dc:creator>Radosław Fedorczuk</dc:creator>
      <pubDate>Wed, 21 Oct 2026 11:39:37 +0000</pubDate>
      <link>https://dev.to/_abbdc2/how-bots-probe-a-small-website-and-the-six-answers-they-hope-to-get-153g</link>
      <guid>https://dev.to/_abbdc2/how-bots-probe-a-small-website-and-the-six-answers-they-hope-to-get-153g</guid>
      <description>&lt;p&gt;Small business sites rarely get a targeted attack. They get the same few requests that bots send to every address on a list. This post shows six of those requests, the response a bot hopes for, and the command to test your own site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the volume keeps going up
&lt;/h2&gt;

&lt;p&gt;Three public data points.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automated traffic was 51% of all web traffic in 2024, and bad bots were 37%, up from 32% in 2023, according to the 2025 Imperva Bad Bot Report. The report says generative AI lowered the barrier to building and running bots (&lt;a href="https://www.businesswire.com/news/home/20250415432215/en/Artificial-Intelligence-Fuels-Rise-of-Hard-to-Detect-Bots-That-Now-Make-up-More-Than-Half-of-Global-Internet-Traffic-According-to-the-2025-Imperva-Bad-Bot-Report" rel="noopener noreferrer"&gt;Thales press release&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;The CVE Program published 28,961 records in 2023, 40,077 in 2024 and 48,244 in 2025 (&lt;a href="https://www.cve.org/About/Metrics" rel="noopener noreferrer"&gt;CVE.org metrics&lt;/a&gt;). Patchstack counted 7,966 new WordPress ecosystem vulnerabilities in 2024, 96% of them in plugins (&lt;a href="https://patchstack.com/whitepaper/state-of-wordpress-security-in-2025/" rel="noopener noreferrer"&gt;Patchstack&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Mandiant measured an average time-to-exploit of five days for vulnerabilities exploited in 2023 (&lt;a href="https://cloud.google.com/blog/topics/threat-intelligence/time-to-exploit-trends-2023" rel="noopener noreferrer"&gt;Google Cloud / Mandiant&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI is now part of both finding and exploiting bugs. Google's Big Sleep agent found an exploitable stack buffer underflow in SQLite before it reached a release (&lt;a href="https://projectzero.google/2024/10/from-naptime-to-big-sleep.html" rel="noopener noreferrer"&gt;Project Zero&lt;/a&gt;), and later found CVE-2025-6965, which Google says was known only to threat actors (&lt;a href="https://blog.google/innovation-and-ai/technology/safety-security/cybersecurity-updates-summer-2025/" rel="noopener noreferrer"&gt;Google&lt;/a&gt;). In DARPA's AI Cyber Challenge final, automated systems analysed more than 54 million lines of code, found 54 of 63 planted vulnerabilities, patched 43, and found 18 real ones nobody planted, at about $152 per task (&lt;a href="https://www.darpa.mil/news/2025/aixcc-results" rel="noopener noreferrer"&gt;DARPA&lt;/a&gt;). On the attack side, Anthropic reported a campaign where AI did 80 to 90% of the tactical work against roughly 30 targets, including vulnerability discovery and exploit code (&lt;a href="https://www-cdn.anthropic.com/d7dd50dd1185f59be051b307150d877f2b82bd2c.pdf" rel="noopener noreferrer"&gt;Anthropic report&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Nobody has to point these tools at a small brochure site for this to matter. The list of known holes grows faster, and checking every site on the internet for them gets cheaper every year.&lt;/p&gt;

&lt;h2&gt;
  
  
  The six probes
&lt;/h2&gt;

&lt;p&gt;The request and response pairs below are the examples shown on &lt;a href="https://shieldwave.io" rel="noopener noreferrer"&gt;shieldwave.io&lt;/a&gt;. Each one is how a site with that hole answers.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. A backup left in the web root
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; GET /backup-full.zip
&amp;lt; 200 OK, application/zip, 48 MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Backup plugins, migration tools and tired developers leave archives and SQL dumps in public folders. Bots request common names: &lt;code&gt;backup.zip&lt;/code&gt;, &lt;code&gt;backup-full.zip&lt;/code&gt;, &lt;code&gt;site.tar.gz&lt;/code&gt;, &lt;code&gt;db.sql&lt;/code&gt;, &lt;code&gt;wp-config.php.bak&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.git/config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in &lt;/span&gt;backup.zip backup-full.zip db.sql wp-config.php.bak .env .git/config&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s '&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code} %{size_download}\n'&lt;/span&gt; &lt;span class="s2"&gt;"https://example.com/&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;code&gt;200&lt;/code&gt; is not proof on its own. Many sites return &lt;code&gt;200&lt;/code&gt; with an HTML error page for every path. Check the first bytes: a zip starts with &lt;code&gt;PK&lt;/code&gt;, a &lt;code&gt;.git/config&lt;/code&gt; starts with &lt;code&gt;[core]&lt;/code&gt;. Fix it by moving the file out of the web root and denying &lt;code&gt;*.zip&lt;/code&gt;, &lt;code&gt;*.sql&lt;/code&gt; and &lt;code&gt;*.tar.gz&lt;/code&gt; in the server config.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Plugin version fingerprinting through readme.txt
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; GET /wp-content/plugins/slider-pro/readme.txt
&amp;lt; 200 OK, Stable tag: 2.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most WordPress.org plugins ship a &lt;code&gt;readme.txt&lt;/code&gt; with a &lt;code&gt;Stable tag&lt;/code&gt; line. A bot does not need to log in or guess. It requests the readme for a list of plugin slugs, reads the version and matches it against public vulnerability data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://example.com/wp-content/plugins/contact-form-7/readme.txt | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'stable tag'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Blocking the readme hides the easy signal, but versioned asset URLs like &lt;code&gt;?ver=5.9.3&lt;/code&gt; often leak the same number. The real fix is updating or removing the plugin. Unused plugins count, since their files are still reachable.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Missing DMARC
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; dig TXT _dmarc.yourwebsite.com
&amp;lt; NXDOMAIN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No DMARC record means receiving servers get no policy for mail that fails SPF and DKIM. Someone can send invoices "from" the domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dig +short TXT example.com | &lt;span class="nb"&gt;grep &lt;/span&gt;spf
dig +short TXT _dmarc.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with &lt;code&gt;v=DMARC1; p=none; rua=mailto:...&lt;/code&gt; to collect reports, confirm SPF and DKIM pass for every legitimate sender, then move to &lt;code&gt;p=quarantine&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. SQL errors from a form
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; POST /contact   email=' OR '1'='1
&amp;lt; 500, error in your SQL syntax
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A database error string in a response is a strong sign that input reaches a query unescaped. Do not run this against a site you do not own or have permission to test. On your own site, the fix is prepared statements (&lt;code&gt;$wpdb-&amp;gt;prepare()&lt;/code&gt; in WordPress) and turning off error display in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Old TLS still accepted
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; ClientHello, TLS 1.0
&amp;lt; ServerHello, TLS 1.0 accepted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; example.com:443 &lt;span class="nt"&gt;-tls1&lt;/span&gt; &amp;lt;/dev/null 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'Protocol|alert'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recent OpenSSL builds may refuse TLS 1.0 on the client side, so a failure can mean your client refused, not the server. &lt;code&gt;nmap --script ssl-enum-ciphers -p 443 example.com&lt;/code&gt; gives a clearer answer. Fix it by allowing only TLS 1.2 and 1.3.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Comment and form script injection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; POST /wp-comments-post.php
&amp;lt; 302 Found, comment saved
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bot submits a payload and checks whether it lands in the page unescaped. The fix is escaping output. A &lt;code&gt;Content-Security-Policy&lt;/code&gt; header limits what an injected script can load and run, and &lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt; stops browsers from guessing file types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://example.com | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'content-security-policy|x-content-type-options|strict-transport-security'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running all of it at once
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://shieldwave.io" rel="noopener noreferrer"&gt;ShieldWave&lt;/a&gt; to run these checks and more than 20 others from the outside and write the result in plain language for the site owner. The free check takes about 90 seconds. A full scan of a verified site takes a few minutes, because it never goes above 15 requests per second and slows down further when the server struggles. I run ENSOMEDIA, a one-person studio, and I wrote the scanner.&lt;/p&gt;

&lt;p&gt;The report sorts findings into fix this week, this month, and can wait, and connects findings that make each other worse. It also produces a brief for the developer. This is the sample brief from the home page, for a fictional shop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Subject: Security fixes for example-shop.com

- /backup-full.zip is publicly accessible (HTTP 200, 48 MB). Remove it from the web root and deny *.zip, *.sql, *.tar.gz in the server config.
- Outdated plugins: slider-pro 2.1.0 (known vulnerability, fixed in 2.4.3), plus two more listed in the attached report. Update and retest.
- No DMARC record. Add _dmarc TXT "v=DMARC1; p=quarantine; rua=mailto:..." once SPF and DKIM pass.
- Missing Content-Security-Policy and X-Content-Type-Options: nosniff. Add at the web server level.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sample is made up. Here is a real report, for my own studio's site, scanned on 21 October 2026 with the domain blurred. It came back at 98 with two low findings and nothing urgent, which is what a maintained site should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5isvs5qo8i1aos21fzg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi5isvs5qo8i1aos21fzg.png" alt="ShieldWave report summary for a real site: score 98 out of 100, risk level low, 0 critical, 0 high, 0 medium, 2 low findings." width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every finding says why it got its severity, how sure the scanner is, and gives you a command to confirm it yourself, so you do not have to take the score on trust:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9bwja7ofp910agnim4s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa9bwja7ofp910agnim4s.png" alt="A ShieldWave finding: CSP allows inline scripts. Low severity, confirmed at 95%, with CWE and OWASP references and a curl command to check it." width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this is the developer brief that scan produced:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91lt4y1r781gg4rrobyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F91lt4y1r781gg4rrobyn.png" alt="The developer brief from the same real scan: a short message listing the two fixes, ready to send." width="799" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some details developers ask about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Active tests need ownership.&lt;/strong&gt; Without verification, ShieldWave only reads what the site shows everyone. The SQL injection and XSS tests send inputs to forms, so they run only after you verify the site with a DNS record, a file, a meta tag or the WordPress plugin. A test message may arrive in the contact form inbox.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic is capped.&lt;/strong&gt; The &lt;a href="https://shieldwave.io/docs/scanning-production" rel="noopener noreferrer"&gt;scanning docs&lt;/a&gt; state a budget of at most 5 requests per second for the free check and 15 for a full scan, with a robots.txt opt-out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is not a pentest.&lt;/strong&gt; A pentester spends days on one target. ShieldWave catches the common holes that bots look for.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tools.&lt;/strong&gt; Single checks are free at &lt;a href="https://shieldwave.io/tools/ssl-certificate-checker/" rel="noopener noreferrer"&gt;/tools/ssl-certificate-checker/&lt;/a&gt;, &lt;a href="https://shieldwave.io/tools/spf-dkim-dmarc-check/" rel="noopener noreferrer"&gt;/tools/spf-dkim-dmarc-check/&lt;/a&gt; and &lt;a href="https://shieldwave.io/tools/security-headers-check/" rel="noopener noreferrer"&gt;/tools/security-headers-check/&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pricing, so you know what you are clicking into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free:&lt;/strong&gt; 5 checks a month for one site, with the score and the three most serious problems. No account, no card.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Full report for one site:&lt;/strong&gt; $9, paid once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro:&lt;/strong&gt; $12 a month for up to 25 sites, unlimited scans, scheduled scans with email alerts, the developer brief and PDF reports. The first 7 days are a free trial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you look after client sites, Pro is the plan for that: one dashboard for all of them, and a brief per site you can forward as it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The inside view: a free WordPress plugin
&lt;/h2&gt;

&lt;p&gt;An outside scan cannot see files. The Ensomedia Security plugin, newly listed in the &lt;a href="https://wordpress.org/plugins/ensomedia-security/" rel="noopener noreferrer"&gt;WordPress.org directory&lt;/a&gt; after the plugin review, runs 24 checks inside WordPress:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core and plugin files against WordPress.org checksums, and themes against their release packages, plus PHP files those releases do not contain.&lt;/li&gt;
&lt;li&gt;Malware and backdoors: web shells, decode-and-execute chains, PHP hidden in images, hidden administrators, injected JavaScript.&lt;/li&gt;
&lt;li&gt;PHP files in uploads, and &lt;code&gt;.htaccess&lt;/code&gt; or &lt;code&gt;.user.ini&lt;/code&gt; rules that run uploads as PHP.&lt;/li&gt;
&lt;li&gt;Known vulnerabilities (opt-in), with the version that fixes each one.&lt;/li&gt;
&lt;li&gt;Login limits, two-factor login with an authenticator app or passkeys, and &lt;code&gt;wp shieldwave two-factor disable&lt;/code&gt; as a CLI rescue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fupmbxwhyf19hompyg19v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fupmbxwhyf19hompyg19v.png" alt="Ensomedia Security showing a finding with signs of a break-in: what to do now, and the file, rule and code that matched." width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Screenshot 3 from the WordPress.org listing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Scheduled scans and email alerts are free and need no account. It changes files, users and settings only when you press a button. The &lt;a href="https://shieldwave.io/transparency/" rel="noopener noreferrer"&gt;transparency page&lt;/a&gt; lists every outside request, and the signed threat feed can be checked with a short Node script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-O&lt;/span&gt; https://shieldwave.io/verify/shieldwave-verify-feed.mjs
node shieldwave-verify-feed.mjs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install it from Plugins, Add New, search "Ensomedia Security". The plugin is new, so false positives are treated as bugs: open a topic in its &lt;a href="https://wordpress.org/support/plugin/ensomedia-security/" rel="noopener noreferrer"&gt;support forum&lt;/a&gt; or write to &lt;a href="mailto:support@shieldwave.io"&gt;support@shieldwave.io&lt;/a&gt;, and it reaches me directly.&lt;/p&gt;

&lt;p&gt;The two work together. Connecting the plugin to a ShieldWave account is optional, and when you do, its results land in the same dashboard as the outside scan, so each site has one list of problems seen from both sides. The free account shows up to three connected WordPress sites.&lt;/p&gt;

&lt;p&gt;Run the outside check on a site you own at &lt;a href="https://shieldwave.io" rel="noopener noreferrer"&gt;shieldwave.io&lt;/a&gt;, then install the plugin on the WordPress sites you look after.&lt;/p&gt;

</description>
      <category>security</category>
      <category>wordpress</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>What I learned scanning thousands of Shopify themes for WCAG violations</title>
      <dc:creator>Radosław Fedorczuk</dc:creator>
      <pubDate>Tue, 19 May 2026 21:10:41 +0000</pubDate>
      <link>https://dev.to/_abbdc2/what-i-learned-scanning-thousands-of-shopify-themes-for-wcag-violations-5d29</link>
      <guid>https://dev.to/_abbdc2/what-i-learned-scanning-thousands-of-shopify-themes-for-wcag-violations-5d29</guid>
      <description>&lt;p&gt;A friend showed me their Shopify store last November and asked, "is this accessible?"&lt;/p&gt;

&lt;p&gt;I had no idea how to answer. I knew accessibility was a thing. I knew there were lawsuits. I had a vague sense that alt text mattered. But sitting there with their store on screen, I could not tell them if a blind customer could buy a product from it. So I started auditing. Six months later I have an app on the Shopify App Store, a list of thousands of stores I have scanned through development, and a much sharper sense of what is actually broken in the wild.&lt;/p&gt;

&lt;p&gt;Here are six things that surprised me.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Every popular Shopify theme ships with 5 to 10 WCAG 2.2 AA violations
&lt;/h2&gt;

&lt;p&gt;Dawn, Refresh, Sense, Crave, Studio, Stiletto. I tested eight themes. They all have the same handful of issues out of the box:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Image carousels on the homepage have no alt text. The merchant gets a blank "image 1, image 2, image 3" experience on a screen reader.&lt;/li&gt;
&lt;li&gt;Search inputs in the header have a magnifying glass icon as the only label. No visible "Search" text, no aria-label.&lt;/li&gt;
&lt;li&gt;Secondary buttons use grey text on white at 3.5:1 contrast. Fails WCAG AA minimum of 4.5:1.&lt;/li&gt;
&lt;li&gt;Focus outlines are removed via CSS reset. Tab through the page and you cannot see where focus lands.&lt;/li&gt;
&lt;li&gt;Form fields use placeholder as the only label. Placeholder disappears on input, so by the time the user types, they cannot remember what field they are in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not the theme builder fault, the design language is just optimized for visual polish. But every merchant inherits these problems on day one and most do not know.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Most "accessibility apps" on the App Store are overlays that do not fix anything
&lt;/h2&gt;

&lt;p&gt;Twenty-five of the 28 apps in the Shopify Accessibility category are overlay widgets. You install them, a floating button shows up on your storefront, the button opens a panel with font size and contrast controls. The actual page code does not change.&lt;/p&gt;

&lt;p&gt;This is the part that bothers me. US courts have ruled in Robles v. Domino and several follow-up cases that overlays do not protect against ADA lawsuits, because they do not fix the underlying code. National Federation of the Blind has an active class action against accessiBe right now. The overlay vendor business model relies on merchants confusing "we installed a widget" with "we are now compliant".&lt;/p&gt;

&lt;p&gt;I made AccessifyAI explicitly not an overlay. The widget we ship adds skip links, ARIA landmarks, and visible focus outlines as semantic improvements. The AI fixes are real code changes the merchant applies to their theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The actual fixes are mostly 30 second changes once you know which file to open
&lt;/h2&gt;

&lt;p&gt;Adding an alt attribute to an image. Wrapping a div in a button element. Bumping #cccccc to #6b7280. Adding aria-label to a search input. These take 30 seconds each. The hard part is not the change, it is figuring out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which theme file contains the broken element&lt;/li&gt;
&lt;li&gt;Which Liquid section renders it&lt;/li&gt;
&lt;li&gt;Whether the same fix needs to be applied in 5 files or 1&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I built two tools for this. The first is a heuristic that maps WCAG violations to Liquid files. If the violation is on the cart icon, the fix is in snippets/cart-icon.liquid. If it is on the footer newsletter form, it is in sections/footer.liquid. The mapping is not perfect but the manual fix wizard now points merchants at the right file 80 percent of the time.&lt;/p&gt;

&lt;p&gt;The second is AI-generated diffs. I use Groq with Llama 3.1 8B to generate the fix as a unified diff. The merchant previews it in a Monaco editor side-by-side view before any change touches their theme. No surprise edits.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. EAA enforcement is real and merchants are not ready
&lt;/h2&gt;

&lt;p&gt;The European Accessibility Act went into force June 28, 2025. Germany rolled out BFSG in September 2025 with fines up to 100,000 EUR per non-compliant store. Poland is next in 2026. France, Netherlands, Belgium are queued up.&lt;/p&gt;

&lt;p&gt;The criteria are clear: if you sell to EU customers and your store has more than 10 employees or more than 2 million EUR in annual revenue, you need to meet WCAG 2.2 AA. Most Shopify Plus stores qualify.&lt;/p&gt;

&lt;p&gt;In conversations with merchants over the last few months, almost none had done an audit. The ones that had used a Lighthouse score and called it done, which is not the same as WCAG conformance. Lighthouse catches maybe 30 percent of WCAG criteria, the rest needs manual review of forms, dynamic content, and keyboard flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Building a Shopify Theme App Extension that actually works is harder than I expected
&lt;/h2&gt;

&lt;p&gt;The technical bits that took the most time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bundle size for Built for Shopify&lt;/strong&gt;. Theme extensions have a 10 KB threshold per asset for the BFS performance criteria. My initial widget was 34 KB. I had to split into a 6.8 KB loader and a 16 KB panel that lazy-loads only when the visitor clicks the floating button.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-language for the storefront widget&lt;/strong&gt;. I shipped translations for English, Polish, German, and French. The challenge was keeping the loader small. The trick: a single 4-key dictionary in the loader for the always-on parts (skip link, ARIA labels, badge), and a larger dictionary inside the lazy-loaded panel for the toggle UI. I detect the page language from the html lang attribute with a fallback chain to English.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Polaris web components in the merchant Admin&lt;/strong&gt;. Shopify is migrating from the React Polaris library to web components with closed shadow DOM. Many components filter synthetic events for security, so programmatic clicks via JS often fail silently. I had to rewrite some test flows to use real OS-level clicks via CDP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-language form state in React&lt;/strong&gt;. The Issues page in our admin has a Monaco diff editor that loads only on demand. Lazy loading saves about 800 KB on first paint but the loader pattern around React.lazy and Suspense took a few iterations to get right with React Router 7.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. The hardest thing was not the code, it was deciding what to charge
&lt;/h2&gt;

&lt;p&gt;I have a free tier (10 pages scanned, 1 store). Basic at $9.99 covers 50 pages and 5 stores. Pro at $24.99 is unlimited with regression alerts and bulk AI fixes.&lt;/p&gt;

&lt;p&gt;Pricing is hard because every other accessibility app charges $35 to $49 per month, and they have hundreds of reviews. I went lower because the only honest pitch I can make is "I am new, give me a chance and I will earn your review". Whether that works long term I will know in three months.&lt;/p&gt;




&lt;p&gt;If you run a Shopify store and any of this resonates, AccessifyAI is on the App Store. Free tier covers 10 pages so you can scan and see if any of the violations above apply to your store. If you scan and the findings are not useful, please reply to this post and tell me what you actually need. I am building this in public and feedback shapes the next version more than anything.&lt;/p&gt;

&lt;p&gt;apps.shopify.com/accessifyai&lt;/p&gt;

&lt;p&gt;If you are a developer working on a Shopify accessibility tool of your own or in another commerce platform, happy to compare notes. Drop a comment.&lt;/p&gt;

</description>
      <category>shopify</category>
    </item>
  </channel>
</rss>
