<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Josepollman on Medium]]></title>
        <description><![CDATA[Stories by Josepollman on Medium]]></description>
        <link>https://medium.com/@josepollman?source=rss-49c92569c42a------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*4Rbhf-WVK07E4-8N</url>
            <title>Stories by Josepollman on Medium</title>
            <link>https://medium.com/@josepollman?source=rss-49c92569c42a------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 04 Nov 2026 23:36:24 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@josepollman/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Chrome Now Asks Before It Loads HTTP. I Checked the Redirects on My Own Sites.]]></title>
            <link>https://medium.com/@josepollman/chrome-now-asks-before-it-loads-http-i-checked-the-redirects-on-my-own-sites-8aaed9fd87ba?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/8aaed9fd87ba</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[https]]></category>
            <category><![CDATA[google-chrome]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[web-performance]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Wed, 04 Nov 2026 07:39:41 GMT</pubDate>
            <atom:updated>2026-11-04T07:39:41.866Z</atom:updated>
            <content:encoded><![CDATA[<h4>None of my seven sites will trigger the new prompt. Four of them still send a www visitor through two redirects, the chain my own speed guide tells people to remove.</h4><p>On 21 October, Chrome’s Secure Web and Networking Team posted that Chrome now “explicitly asks users for permission before making an insecure HTTP connection”, and that this is on for all users by default. In October 2025 the Chrome Security team had said it would arrive with Chrome 154 in October 2026. It’s here.</p><p>I run seven small sites, so my first question was whether any of them would put that prompt in front of a visitor. The second question turned out to be more useful: what do my http:// addresses actually do on the way to the real page?</p><h3>What changed in Chrome</h3><p>Until now, an HTTP page got a “Not Secure” label in the address bar after it loaded. Google’s post lists three problems with that. People don’t notice passive warnings. The label only appears after the data has already crossed the network. And the one that matters for anyone running a site: “Browsers never have a chance to show a ‘Not Secure’ badge on short-lived HTTP traffic, like redirects.”</p><p>The new default is the “Always Use Secure Connections” setting, which Google launched as an opt-in in 2022. The October 2025 announcement describes it like this: “Chrome attempts every connection over HTTPS, and shows a bypassable warning to the user if HTTPS is unavailable.” Once a user approves HTTP for a site, Chrome won’t ask again “until the user has not visited the site for at least two weeks.” Single-label names like intranet/ and local addresses like 192.168.0.1 get no warning by default.</p><p>Google’s early rollout data says “nearly 95% of Chrome users on Desktop don’t see any HTTP warnings in a given week, with less than 1% seeing 3 or more.” Most visitors will never see the question, so the useful work is finding the few links that could produce it.</p><h3>The upgrade comes before the question</h3><p>The prompt is Chrome’s second move. In 2023 the Chromium blog described the first one: Chrome “will automatically upgrade all http:// navigations to https://, even when you click on a link that explicitly declares http://”, and falls back to http:// when the upgrade fails, for example “due to a site providing an invalid certificate or returning a HTTP 404.” With the new default, that fallback is where the question appears.</p><p>I checked the first half this morning. example.com answers a plain HTTP request with a 200 and no redirect, so curl got the page over HTTP. When I opened http://example.com/ in Chrome 156, the tab landed on https://example.com/. The server never redirects, so the switch to HTTPS was Chrome’s own.</p><p>So a site that serves HTTPS properly won’t trigger the prompt just because someone linked to its http:// address. The prompt is for hosts where HTTPS doesn’t work.</p><h3>What my seven sites do</h3><p>At about 07:30 UTC on 4 November I ran curl against the http:// address of all seven sites, with and without www.</p><p>All seven redirect http:// to https://. All seven answer over HTTPS on both names, and all seven send a Strict-Transport-Security header with a one-year max-age that covers subdomains. None of them should ever put Chrome’s new question in front of anyone.</p><p>The redirects were less tidy. On the bare domain, every site gets there in one hop. On www, three sites also go straight to the final address in one hop. The other four, whattofixfirst.com among them, do this:</p><p>http://www.whattofixfirst.com/ → https://www.whattofixfirst.com/ → https://whattofixfirst.com/</p><p>The first hop changes http to https and keeps the www. The second drops the www. Two rules each do their own job, and neither knows about the other.</p><p>I took the median of nine runs from my machine with curl following redirects. On whattofixfirst.com the two hops took 0.28 seconds before the final request started, and the whole chain took 0.38 seconds. A direct request to https://whattofixfirst.com/ took 0.10 seconds. The other three two-hop sites spent between 0.16 and 0.26 seconds in redirects. The three one-hop sites spent between 0.04 and 0.13. That’s one machine on one morning, and a visitor somewhere else will see different numbers.</p><figure><img alt="Table of seven sites and what an http://www link does on each. All seven reach HTTPS in one hop from the bare domain. With www, whattofixfirst.com, subcovered.com, vetthisvendor.com and knowyourmouth.com take two hops (0.16 to 0.28 seconds in redirects); canipluginsolar.com, notspoofed.com and isitunderdosed.com take one (0.04 to 0.13 seconds)." src="https://cdn-images-1.medium.com/max/1024/1*442zm_hP1f6f_nb74mKcqA.png" /><figcaption>My own curl results, 4 November 2026. Card made by me, not AI-generated.</figcaption></figure><p>whattofixfirst.com has <a href="https://whattofixfirst.com/guide/time-to-first-byte">a guide on slow Time to First Byte</a>, and redirects are the first thing on its list. It says: “Each one is a complete extra round trip. http://example.com to https://example.com to https://www.example.com is two of them before your server has even started working.” My www addresses do the mirror image of that example.</p><h3>Who actually pays for the second hop</h3><p>Fewer people than the curl numbers suggest. A Chrome user who follows an http://www link gets upgraded to https://www before the first request, so the first hop never happens and one redirect is left. A returning visitor whose browser has already seen the Strict-Transport-Security header on the bare domain gets the same treatment from any browser that follows the standard: RFC 6797 says that for a known host, including subdomains when includeSubDomains is set, the browser “MUST replace the URI scheme with ‘https’” before loading.</p><p>The full two hops land on anything that requests the address exactly as written, the way curl did. That’s real, but it’s not the emergency a “two redirects” headline implies. The fix is one rule that sends http://www straight to the https address on the bare domain.</p><h3>Where the prompt will show up</h3><p>If your own site serves HTTPS, look at the hosts in front of it. Google’s 2025 post says many of the sites responsible for the most HTTP navigations “use HTTP only for navigations that immediately redirect to HTTPS sites.” A host that only redirects is easy to forget, because nobody ever sees a page on it. If it has no working certificate, Chrome can’t upgrade the request, and your visitor gets the question before they ever reach your real site.</p><p>The places I’d check: http:// links in old emails and printed material, QR codes, short-link domains, click-tracking domains an email tool set up years ago, and spare domains that exist only to redirect.</p><h3>A check that takes a few minutes</h3><ol><li>Collect the http:// links you no longer control: old newsletters, flyers, QR codes, other people’s links to you.</li><li>Run curl -sIL on each one and read the Location headers. Each Location is a hop.</li><li>Request every hostname in the chain over https://. A certificate error or a refused connection on any of them marks a host Chrome can’t upgrade.</li><li>On the chains that work, count the hops before the final page. More than one is usually a chain you can collapse into one.</li></ol><p>The prompt is Google’s to tune. The hops are yours.</p><p>Sources, all opened 4 November 2026: Google, “Chrome Now Warns Before Insecure HTTP Connections” (21 October 2026); Google Security Blog, “HTTPS by default” (28 October 2025); Chromium Blog, “Towards HTTPS by default” (August 2023); RFC 6797, section 8.3; whattofixfirst.com, Time to First Byte guide. Redirect timings: my own curl runs, 4 November 2026, about 07:30 UTC.</p><p>I run whattofixfirst.com, a free Core Web Vitals checker.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8aaed9fd87ba" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[DigiCert Moved an Internal Archive to a Reachable Network and Treated It as an Infrastructure Change]]></title>
            <link>https://medium.com/@josepollman/digicert-moved-an-internal-archive-to-a-reachable-network-and-treated-it-as-an-infrastructure-change-bdd6c909a5a2?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/bdd6c909a5a2</guid>
            <category><![CDATA[incident-response]]></category>
            <category><![CDATA[vendor-management]]></category>
            <category><![CDATA[data-breach]]></category>
            <category><![CDATA[privacy]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Mon, 02 Nov 2026 07:36:38 GMT</pubDate>
            <atom:updated>2026-11-02T07:36:38.061Z</atom:updated>
            <content:encoded><![CDATA[<h3>DigiCert Moved an Internal Archive Onto a Reachable Network and Treated It as an Infrastructure Change</h3><h4>Its full incident report landed on Sunday night. Archived customer data was read between 27 June and 2 July, a few accounts’ ID documents among it. No certificates were touched. The cause dates to February 2025.</h4><p>DigiCert, the certificate authority, posted its full incident report to Mozilla’s bug tracker at one minute to midnight UTC on Sunday, two days inside the deadline it had set itself. I read it this morning through Bugzilla’s API, all three comments on bug 2084460. It is unusually plain about its own mistakes, which is why I think it is worth reading if you buy anything from a supplier that keeps your documents.</p><p>First, what this incident is not. No certificates were issued, modified or revoked. DigiCert says its CA systems “operate on their own secure network segments”, and its log review found no validation, issuance or revocation activity tied to the account involved. If you hold a DigiCert certificate, the report says you don’t need to do anything about it.</p><p>What was read was something else: an internal archive of the information customers’ representatives hand over when DigiCert validates who they are. Most of the data accessed was business contact details, meaning names, business email addresses, phone numbers and addresses. For “a small minority” of accounts it included a document such as a driver’s license, passport or utility bill. The report gives no count of customers or documents, so I won’t guess one.</p><h3>The timeline, in DigiCert’s own dates</h3><ul><li>4 February 2025: During an infrastructure migration, the system moved “from a VPN-restricted network segment to a different availability zone”. That “inadvertently allowed this internal business system to be accessible externally.”</li><li>18 June 2026: DigiCert staff noticed accounts on the system that did not belong to DigiCert. Because those accounts were not assigned to any application, the reviewer concluded they had no access to data. The system went behind a web application firewall that blocked new account creation from outside.</li><li>21 June: A report arrived through DigiCert’s managed security research program saying outsiders could create accounts. DigiCert confirmed it on 24 June.</li><li>27 June to 2 July: The window in which archived data was read, as reconstructed months later.</li><li>2 July: A patch made the system return HTTP 401 to any account without an assigned application.</li><li>12 October: DigiCert first suspected data had been read. On 19 October it confirmed it.</li></ul><figure><img alt="Timeline card of DigiCert’s archive incident from its Bugzilla report: February 2025 migration makes the archive reachable from outside; 18 June 2026 staff see outside accounts and conclude no data access; data read 27 June to 2 July; patch on 2 July; access confirmed 19 October." src="https://cdn-images-1.medium.com/max/1024/1*mtxnrglasHebYv3KHgsaDg.png" /><figcaption>Dates from the timeline table in DigiCert’s incident report. Card made by me from the report, not AI-generated.</figcaption></figure><p>By my count that is 109 days between the fix and the confirmation. That number is my arithmetic from their dates; DigiCert doesn’t use it.</p><p>One more detail sits in that table. The data access window opened nine days after staff first saw the outside accounts. DigiCert’s action items say no account was created through the firewall path after 18 June, which suggests the reading was done with an account that already existed. Blocking new sign-ups is a different fix from checking what existing accounts can open.</p><p>The report does not say whose account it was. The outside report on 21 June came through DigiCert’s own research program, and nothing in the report connects that researcher to the data access, so I would not read it that way.</p><h3>Three assumptions, each reasonable on its own</h3><p>DigiCert lists three contributing factors.</p><p>The first is the move itself. It was handled “as an infrastructure change rather than a security change”, so nobody reviewed what the new network position exposed, and monitoring requirements were not reassessed afterwards.</p><p>The second is a feature nobody meant to ship. The archive ran on an account manager that DigiCert also uses for customer-facing products, and a self-registration flow built for those products came along with it. In DigiCert’s words, MFA “is only enabled if the account is assigned to an application that requires MFA.” A self-registered account had no application, so it skipped MFA. It was read-only by default, and read-only still meant it could read the archive.</p><p>The third is the review in June. The initial reviews “concluded incorrectly, from the absence of an assigned application, that the account had no data access.”</p><p>In that third factor, a label was taken as a permission. The fix DigiCert lists for it is to check permissions at every endpoint: as of 30 October, each subsystem endpoint is “confirmed to enforce authorization by checking application assignment and role.”</p><p>The report sums the whole thing up in one line under lessons learned: “Authorization for a business system must not be delegated to its network position.” A second line is just as blunt: “The incident was initially handled as an account-creation issue rather than a data-access event.”</p><h3>What this means when you are the customer</h3><p>I run vetthisvendor.com, a free tool that checks a supplier before you pay them: VAT registration, IBAN checksum, sanctions lists, the company register, and whether their email domain can be forged. Nothing in that list would have told a DigiCert customer anything about this. Those checks ask whether a supplier is who it says it is. This incident is about what a legitimate supplier did with what it was given.</p><p>Certificate validation is one of the places where a business may hand a supplier an identity document. Here are the questions I would put to any supplier that holds documents like that. Each comes from something DigiCert says it has now changed:</p><ul><li>Does a change to who can reach an internal system need a security sign-off? DigiCert’s policy has required that since 28 August 2026.</li><li>Does each part of the system check permissions itself, or does it trust that only staff can reach it?</li><li>Is there an alert when an account is created outside the normal provisioning route? At DigiCert that review is still listed as ongoing, due 6 November.</li><li>Are the logs detailed enough to say afterwards who read what, and when?</li></ul><p>A supplier that can answer those plainly has told you more than a security badge in its footer does.</p><h3>The same question, pointed at my own site</h3><p>The report sent me back to <a href="https://vetthisvendor.com/privacy">my own privacy page</a>, which says “If something here is wrong, it is a bug.” The tool has no signup, and it doesn’t upload the invoice or email you check; those are read in your browser. There is one place where access works by possession rather than identity, and the page says so: result links are “unlisted, not secret. Anyone with the link can read it.” That is deliberate, so a result can be forwarded to whoever approves the payment. What a link holds is limited. The IBAN is masked down to the country code, check digits and last four characters, and the result is deleted after 90 days. This morning robots.txt still disallowed /result/, and a made-up result address returned a 404.</p><p>All of that was decided for one setup. DigiCert’s archive was also built for one setup, behind a VPN, and it stayed safe until the setup changed and nobody asked again who could reach it. That question has to be asked after every move, not once at design time.</p><h3>What the report does well</h3><p>DigiCert kept “detailed logs and audit tables”, which let it rebuild the access window, tie the activity to the account and confirm the CA was never reached. Without them, DigiCert could not have put dates on the access window. Two of its 13 action items are still open, both due 6 November: an internal audit confirming no origin server is reachable from outside, and a final review of alerting on unexpected account creation.</p><p>Plenty of supplier incident notices give a date and a reassurance. This one gives the mistake, the wrong conclusion that delayed finding it, and the date each fix shipped. If a supplier that holds your documents ever has a bad week, that is the standard to hold its write-up to.</p><p>Sources: DigiCert, “Unauthorized access to business system”, Mozilla Bugzilla bug 2084460, preliminary report and full incident report (posted 1 November 2026), read through the Bugzilla REST API on 2 November 2026. vetthisvendor.com privacy page, last updated 12 August 2026, and robots.txt, both read on 2 November 2026.</p><p>I build small free verification tools; vetthisvendor.com is the one for checking suppliers.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bdd6c909a5a2" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Chrome Refused a Certificate From the Compromised eMudhra CA. Curl on the Same Machine Returned 200.]]></title>
            <link>https://medium.com/@josepollman/chrome-refused-a-certificate-from-the-compromised-emudhra-ca-curl-on-the-same-machine-returned-200-ce860d5ffc2d?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/ce860d5ffc2d</guid>
            <category><![CDATA[ssl-certificate]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[certificate-authority]]></category>
            <category><![CDATA[devops]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Fri, 30 Oct 2026 07:39:22 GMT</pubDate>
            <atom:updated>2026-10-30T07:39:22.760Z</atom:updated>
            <content:encoded><![CDATA[<h4>Apple’s new support page explains why a Mac can block a certificate in Safari and accept it in Terminal. I ran the same test on my Linux machine. It had three trust lists, and only Chrome’s refused the certificate.</h4><p>Apple published a support article yesterday, 29 October, called “About the compromised eMudhra intermediate CAs.” Most of it is what you’d expect. The private keys of eight intermediate certificate authorities run by eMudhra were compromised, six of them issue TLS certificates, and Apple has been blocking the twelve certificates for those six since 19 October. On 23 October it also began blocking the root they chain to, emSign ECC Root CA - G3.</p><p>Further down the page, Apple gets specific. On a Mac, it says, curl, git, python3, ruby, perl and openssl “check certificates against /etc/ssl/cert.pem.” For certificates that chain to a root in that file, “these tools don’t check Apple’s block or whether the certificate has been revoked.” Safari and Mail are covered automatically. The command-line tools on the same machine wait for “a future macOS update.”</p><p>So one Mac carries two lists of what to trust, and only one of them got the fix. The machine I work on runs Linux, so this morning I tested whether it had the same split.</p><h3>The test</h3><p>There is a public test page at dv-g3b-emudhra.we-have-a-problem.com that serves a certificate issued by one of the compromised intermediates. I didn’t take that on trust. I pulled the chain with openssl and compared fingerprints. The intermediate is EM DV TLS CA - G3B, issued by emSign Root TLS CA - G3, and its SHA-256 fingerprint starts 42C4ACCD. That is the third entry in Apple’s blocked list, character for character. The site’s own certificate is dated 20 October 2026, the day after Apple started blocking.</p><p>Then I asked five clients on the same Linux machine to open the page, at 07:24 UTC on 30 October:</p><ul><li>Chrome 154: refused. “Your connection is not private,” error NET::ERR_CERT_AUTHORITY_INVALID.</li><li>curl 8.5.0: HTTP 200.</li><li>openssl 3.0.13 s_client: “Verify return code: 0 (ok).”</li><li>python3 3.12, plain urllib: HTTP 200.</li><li>Node.js 20.20.2: HTTP 200.</li></ul><p>The page that curl downloaded says, in full: “Your client successfully connected to the site. That’s bad!”</p><figure><img alt="Table of five clients on one Linux machine opening a test page whose certificate comes from a compromised eMudhra intermediate. Chrome 154 refused it with ERR_CERT_AUTHORITY_INVALID. curl, openssl, python3 and Node.js 20 all accepted it." src="https://cdn-images-1.medium.com/max/1024/1*9qZ9wNz_gCs-QIzYEs8ICQ.png" /><figcaption>My own test results, 30 October 2026. Not AI-generated.</figcaption></figure><h3>Why the answers differ</h3><p>Chrome made its own decision, and the other four never asked Chrome. Curl, openssl and Python’s standard library on Ubuntu all read the operating system’s bundle, /etc/ssl/certs/ca-certificates.crt, which comes from the ca-certificates package. I checked: curl reports that file as its CAfile, and Python’s default cert.pem is a symlink to it. Node.js uses neither by default. Its documentation describes the bundled store as “a snapshot of Mozilla CA store that is fixed at release time.”</p><p>That left two lists to look at, and one more thing.</p><p>First, the operating system’s list. The tools ran in an Ubuntu 24.04 environment with ca-certificates version 20260601~24.04.1 installed. Running trust list showed emSign ECC Root CA - G3 still marked as a trust anchor. Ubuntu had already shipped a fix. The changelog for version 20260816ubuntu0.24.04.1, dated 20 October, opens with “Blacklist the following CA cert due to intermediate cert compromise” and names emSign ECC Root CA - G3. Launchpad shows it published to noble-updates on 21 October. The fix had been out for nine days, and this environment hadn’t installed it.</p><p>That’s the most ordinary failure there is, and the reason I’m writing it down. Nothing was wrong with Ubuntu’s response. A distribution can only ship the update. Containers, build images and long-lived dev environments only get it when someone rebuilds or upgrades them, and a browser that updates itself in the background gives you no hint that the rest of the machine is behind.</p><p>Second, Node’s built-in list. I counted the roots compiled into Node 20.20.2: 144, four of them emSign, including emSign ECC Root CA - G3. Node’s October security release lists “ca-cert (eMudhra Intermediate CA Compromise)” as a fix “on 26.x, 24.x, 22.x.” Version 20 isn’t on that line. Node’s own release schedule puts its end of life at 30 April 2026, and the security post says plainly that “End-of-Life versions are always affected when a security release occurs.” This copy of Node 20 was installed through nvm. Upgrading the operating system’s certificates would not have changed its answer, because by default it never reads them.</p><p>Then revocation. Apple’s page says eMudhra and Sectigo have revoked the affected certificates. None of the four tools refused the page because of it. A revoked intermediate with a trusted root above it still verified as fine.</p><h3>The Mac version of the same check</h3><p>If you’re on a Mac, Apple gives a one-line check in step 4 of its article:</p><pre>openssl crl2pkcs7 -nocrl -certfile /etc/ssl/cert.pem | openssl pkcs7 -print_certs -noout | grep -E &#39;emSign ECC Root CA - G3|AAA Certificate Services&#39;</pre><p>If that prints emSign ECC Root CA - G3, the command-line tools still trust the chain. Apple’s article walks through removing it by hand and adds two warnings that are easy to miss.</p><p>The first is that removing the emSign root “doesn’t block the six certificates that Sectigo cross-signed,” because those still verify through AAA Certificate Services. Apple gives a second command for that root too, and warns that removing roots can stop these tools from verifying sites that chain to them through intermediates that weren’t affected.</p><p>The second is that “a macOS software update can replace /etc/ssl/cert.pem with Apple’s version.” Until the update with Apple’s own fix arrives, any update can quietly put the root back, so Apple says to re-run the check after each one.</p><p>On Ubuntu or Debian, trust list | grep -A3 &quot;emSign ECC Root CA - G3&quot; does the same job. If it prints a trust anchor, upgrade ca-certificates. For Node, node -v is enough. Node 20, and anything older than the October security releases on the 22, 24 and 26 lines, doesn’t have that update.</p><h3>Where this touches my own work</h3><p>I run notspoofed.com, a free checker for a domain’s email authentication records. One of the things it looks at is MTA-STS, which tells other mail servers to use TLS when delivering to your domain and to refuse a certificate that doesn’t check out. When I run gmail.com through <a href="https://notspoofed.com/check?domain=gmail.com">my checker</a>, it shows “MTA-STS enforce” along with the policy’s mode, MX names and max_age. Those last values aren’t in DNS. They come from a policy file my checker fetches over HTTPS from mta-sts.gmail.com.</p><p>The MTA-STS standard, RFC 8461, says both the policy host and the receiving mail server must present a certificate that will “chain to a root CA that is trusted by the Sending MTA.” It says sending servers are “expected” to use “a set of trusted CAs similar to those in widely deployed web browsers and operating systems.” Revocation checking is a MAY.</p><p>In other words, the protection is exactly as current as the root list on whichever server does the sending, or the fetching. My browser has no say in it. Every mail server and every HTTPS-fetching backend has its own answer to “do I trust emSign ECC Root CA - G3 today?”, and the only way to know that answer is to ask that machine.</p><h3>What I’m taking from it</h3><p>Chrome on this machine refused the bad certificate. Chrome’s list was one of three on it.</p><p>The checks take less than a minute each. Open a page that shouldn’t work, from each tool you actually use, and see which ones refuse. The public test page above is enough for this one incident. The habit is the part that carries over: a fix that reached your browser has told you nothing about curl, your language runtime, your containers or your mail server.</p><p><em>Sources: Apple Support, “About the compromised eMudhra intermediate CAs” (published 29 October 2026); Ubuntu ca-certificates changelog, version 20260816ubuntu0.24.04.1; Node.js October 2026 security releases and release schedule; RFC 8461 sections 3.3 and 4.2. All tests run on 30 October 2026.</em></p><p><em>I build free tools for checking email authentication and vendor details. notspoofed.com is the email one.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ce860d5ffc2d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[DreamHost Asked Customers to Check Their Mail Forwards. A New Password Doesn’t Remove One.]]></title>
            <link>https://medium.com/@josepollman/dreamhost-asked-customers-to-check-their-mail-forwards-a-new-password-doesnt-remove-one-55829e613fdd?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/55829e613fdd</guid>
            <category><![CDATA[phishing]]></category>
            <category><![CDATA[web-hosting]]></category>
            <category><![CDATA[fraud-prevention]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[email]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Wed, 28 Oct 2026 07:35:01 GMT</pubDate>
            <atom:updated>2026-10-28T07:35:01.705Z</atom:updated>
            <content:encoded><![CDATA[<h4>The host hasn’t said why it expired some mail and SFTP passwords. Two lines in its notice still tell you what to check after any reset.</h4><p>On 23 October, DreamHost started resetting the passwords of some email accounts. By that night the resets covered FTP and SFTP users too. The status post was marked resolved on 27 October at 4:45 PM Pacific, and the notice in DreamHost’s help center is still up, last updated on 26 October.</p><p>I read both pages in full this morning because of one line in the notice. Right after telling owners to “set a new password for each email address”, it asks them to “take a moment to review the forwarding settings on each address and remove any forward that you don’t recognize or may no longer use.”</p><p>Neither page says what happened. The notice says the passwords “were recently expired” “to ensure the continued integrity of DreamHost customer accounts”. The status feed says “as a precaution” and gives no count of affected accounts. A separate status post from 21 October, about a PHP vulnerability, says DreamHost had “not observed any attack traffic related to this issue to date”. I’m not going to guess at a cause. This story is about the two requests in the notice. They apply whatever the reason was.</p><figure><img alt="Timeline of DreamHost status updates, 23 to 27 October 2026, Pacific time: 23 Oct 2:20 PM File Manager issues; 5:20 PM some email passwords reset as a precaution; 10:13 PM resets extended to FTP and SFTP users; 24 Oct 10:37 AM reset complete; 24 to 25 Oct owners emailed in batches; 26 Oct 3:35 PM File Manager back; 27 Oct 4:45 PM resolved, with no cause or account count given." src="https://cdn-images-1.medium.com/max/1024/1*TK7n32D0mHZN3mkg0FmKVA.png" /><figcaption>DreamHost’s own status updates, 23 to 27 October 2026, laid out by me from its public status feed. Not AI-generated.</figcaption></figure><h3>What a forward does after the password changes</h3><p>A forward is a setting on the address. It doesn’t sign in and it doesn’t hold a session, so a new password has nothing to cut off. If a mailbox forwards to an outside address, new mail keeps going there after the reset, and someone reading that mailbox normally sees nothing different.</p><p>Microsoft’s guide to recovering a compromised Microsoft 365 mailbox treats this as a separate step. It says its steps cover “known methods that might allow the attacker to maintain persistence and regain control of the account later.” Disabling the account or resetting the password is step 1. Reviewing mail forwarders is step 6, with its own command for inbox rules, “including hidden ones”, that forward or redirect messages. The guide’s list of symptoms includes “Recently added external email forwarding” and rules that move messages into the Notes, Junk Email or RSS Subscriptions folders.</p><p>DreamHost’s panel is not Microsoft 365, and its notice doesn’t say anyone added a forward to anything. It asks owners to look. The place to look is Mail &gt; Manage Email in the DreamHost panel, the same page where the new passwords get set.</p><h3>The second request: don’t use the mailbox to announce the change</h3><p>The notice then asks owners to contact their users, “such as employees, clients, or family members”, and recommends “a phone call, secure text, or any private channel other than their DreamHost-hosted email address.”</p><p>DreamHost gives a practical reason: those users can’t open their inbox until they have the new password. Microsoft’s guide gives a second reason for the same advice: “Don’t send the new password to the user through email, because the attacker could have access to the mailbox at this point.”</p><p>Six of the eleven updates in the status feed carry some version of the same warning: “We will never email you asking for your password”, and the notification “will not ask you to log in through a link”. Go to panel.dreamhost.com directly. That warning matters more than usual here. Affected owners were emailed in batches between 24 and 25 October, and two days of real notices arriving is also two days in which a fake one would look normal.</p><h3>Why I care about this from the payment side</h3><p>I build vetthisvendor.com, a free tool that checks a supplier before you pay them: VAT registration, IBAN checksum, sanctions lists, the company register, and whether their email domain can be forged. The site’s own FAQ says what it can’t catch. Asked whether a clean result means it is safe to pay, the answer is no: “These checks cannot detect the most common invoice fraud, where a real supplier’s mailbox is compromised and only the bank details are changed.”</p><p>Microsoft’s step 6 reads “Remove any suspicious mailbox forwarding that the attacker added.” A forward is a quiet way to keep reading a mailbox after losing the password. Whoever holds the copy still sees the threads: purchase order numbers, payment terms, the name of the person who normally sends the invoices and how they sign off. <a href="https://vetthisvendor.com/guide/supplier-changed-bank-details">My guide on supplier bank detail changes</a> describes the same trick from the other end, a mailbox rule that hides your replies from the real supplier, “which is why ‘I emailed to check and they confirmed’ is not confirmation.”</p><p>So “they’ve reset their passwords” is not the reassurance it sounds like. If a supplier tells you they had a password reset, on any host, two checks matter: a forwarding check on their side and a confirmation call on yours. The call goes to a number you already had, from an old invoice, your accounting system, or their website that you went to yourself. Not the number in the email signature, because whoever controls the mailbox controls the signature too.</p><h3>What I’d do this week with a DreamHost account</h3><ul><li>Set the new passwords at panel.dreamhost.com, typed into the address bar, not reached through a link in an email.</li><li>While on Mail &gt; Manage Email, read the forwarding settings on every address. Remove anything you don’t recognize, as the notice asks, and anything nobody uses any more.</li><li>The notice only mentions the forwarding settings on that panel page. If your users can set up their own filters or rules somewhere else, check those separately.</li><li>Give each user their new password by phone or text, never by email to the address you just reset.</li><li>Update the saved password in every mail, FTP and SFTP client that stores it, as the notice reminds you.</li></ul><h3>The part a notice can’t do</h3><p>A host can expire passwords from its side. It can’t tell which forwards were meant to be there. Only the owner knows that, which is why the notice asks instead of deleting them.</p><p>Payments work the same way. A tool can tell you an IBAN is well formed and a VAT number is registered. It can’t tell you whether the supplier really asked for the money to go somewhere new. In both cases the last check is a person, reached through a channel the attacker doesn’t control.</p><p>Sources, opened 28 October 2026: DreamHost Knowledge Base, “Current Status Notifications”, notice of October 25, 2026 (last updated October 26). DreamHost status history feed, “Investigating an incident affecting File Manager and Webmail”, updates of 23 to 27 October. Microsoft Learn, “Respond to a compromised email account in Microsoft 365”.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=55829e613fdd" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Google’s Public DNS Says the Blocklist Test Address Doesn’t Exist]]></title>
            <link>https://medium.com/@josepollman/googles-public-dns-says-the-blocklist-test-address-doesn-t-exist-49b1f67f474b?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/49b1f67f474b</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[sysadmin]]></category>
            <category><![CDATA[dns]]></category>
            <category><![CDATA[spam]]></category>
            <category><![CDATA[email]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Mon, 26 Oct 2026 07:42:13 GMT</pubDate>
            <atom:updated>2026-10-26T07:42:13.726Z</atom:updated>
            <content:encoded><![CDATA[<h4>Every IPv4 blocklist has to list 127.0.0.2. This morning Google answered “no such name” for it on Spamhaus, Cloudflare answered with an error code, and the fallback path in my own IP checker would read Google’s answer as “not listed”.</h4><p>DNS blocklists have a built-in self-test. RFC 5782, the 2010 document that describes how they work, says it plainly: “IPv4-based DNSxLs MUST contain an entry for 127.0.0.2 for testing purposes.” It also says they “MUST NOT contain an entry for 127.0.0.1.”</p><p>So the test is the same for every list. Ask the list about 127.0.0.2 and you should get an answer back, normally 127.0.0.2 itself. Ask about 127.0.0.1 and you should get nothing. If 127.0.0.2 comes back empty, your lookups aren’t working, whatever the list says about any real address.</p><p>This morning, at 07:23 UTC, I asked Spamhaus’s ZEN list about 127.0.0.2 through Google’s and Cloudflare’s public resolvers. They gave me two different wrong answers.</p><h3>What Google and Cloudflare sent back</h3><p>A blocklist query is an ordinary DNS lookup. You reverse the address and put the list’s zone after it, so the test query for ZEN is 2.0.0.127.zen.spamhaus.org. I sent it to Google Public DNS and to Cloudflare&#39;s 1.1.1.1 through their JSON lookup pages, which return the raw answer.</p><p>Google returned status 3, which is NXDOMAIN: the name does not exist. The authority section came from Spamhaus’s own zone, with hostmaster.spamhaus.org in it, so this wasn&#39;t Google failing to reach Spamhaus. The query got there and came back with &quot;no such name&quot;. I got the same result for 2.0.0.127.sbl.spamhaus.org, Spamhaus&#39;s SBL zone.</p><p>Cloudflare returned an answer: 127.255.255.254. Then I asked Cloudflare about 127.0.0.1, the address no list is allowed to contain. Same answer, 127.255.255.254.</p><figure><img alt="Two panels of raw DNS JSON. Left, Google Public DNS for 2.0.0.127.zen.spamhaus.org: Status 3, NXDOMAIN, with a Spamhaus SOA record. Right, Cloudflare for the same name and for 1.0.0.127.zen.spamhaus.org: both answer 127.255.255.254, Spamhaus’s error code for queries through a public resolver." src="https://cdn-images-1.medium.com/max/1024/1*Jio0NLpG9Vcq9zY23xO_7w.png" /><figcaption>The raw answers from both resolvers, 26 October 2026, 07:23 UTC. Formatted from the JSON responses; not AI-generated.</figcaption></figure><h3>Why the two answers fail differently</h3><p>Cloudflare’s answer is documented. In a February 2021 post, Spamhaus listed the codes its public mirrors return when they won’t answer a query. 127.255.255.254 means &quot;Query via public/open resolver/generic rDNS&quot;. The same post is clear about what those codes are: &quot;none of these return codes relate to the reputation of the query – they are error codes.&quot;</p><p>A January 2022 Spamhaus post explains the reason for Cloudflare in particular. Spamhaus’s free mirrors are for small, non-commercial use, and Spamhaus monitors usage against its terms. In Spamhaus’s words, “Cloudflare masks organizations’ queries to the Project’s Public Mirrors”, so Spamhaus can’t tell who is asking or how much. It began returning the error code across Cloudflare’s address space from 15 February 2022.</p><p>The danger with the Cloudflare answer is that it looks like a listing. A blocklist that lists an address answers with a 127.x.x.x address, and so does this error. Mail software that doesn’t recognise the code can count it as a hit, and since Cloudflare gave it for 127.0.0.1 too, every sender would be listed. Spamhaus warned about exactly this: “serious issues can occur, including bouncing all emails back to their senders and your emails not being queried against the blocklists.”</p><p>At least that failure is loud. Rejected mail produces bounces, and people see bounces.</p><p>Google’s answer is the quiet one. NXDOMAIN is exactly what a blocklist returns for an address it doesn’t list. A mail server that gets NXDOMAIN for a real sender’s address has no way to tell “not listed” from “not answered”. Nothing in the answer looks like an error. The blocklist check is effectively switched off, and nothing reports it.</p><p>I read two Spamhaus pages this morning, and neither describes what Google’s resolver gets back. Google may be getting a different treatment from Cloudflare for its own reasons, and that could change. What I can say is what came back today, for the test address, through both resolvers.</p><h3>The test is one line</h3><p>If you run a mail server, or a monitoring script, or anything else that checks Spamhaus, run this from the machine that does the checking, using whatever resolver that machine actually uses:</p><p>dig +short 2.0.0.127.zen.spamhaus.org</p><p>The answer should include 127.0.0.2. If you get nothing at all, or anything starting with 127.255.255, your blocklist lookups are not working and every “clean” result from that machine means nothing.</p><p>Why it matters which machine: the resolver your laptop uses tells you nothing about the one your server uses, and a server can end up on a public resolver without anyone choosing it. Spamhaus’s own advice is either to query from a dedicated address with proper forward and reverse DNS, or to switch to its free Data Query Service, which uses a registered key.</p><h3>Then I read my own code</h3><p>I build notspoofed.com, a set of free email authentication tools. One of them is a sending-IP checker that looks an address up on eight blocklists, Spamhaus ZEN first. The source is public, so after the Google result I opened it to see which of these two failures it could fall into.</p><p>The file that lists the blocklists says every zone in it “was verified to answer correctly for 127.0.0.2&quot; and &quot;to stay silent for 127.0.0.1&quot;. There&#39;s a function that treats anything starting with 127.255.255 as a refusal, not a listing, and the result page shows that list as &quot;unknown&quot;. The page says so in plain words: &quot;It is not the same as &#39;not listed&#39;, and we do not report it as such.&quot; So the Cloudflare failure is handled. When I ran the checker on Google&#39;s own address, 8.8.8.8, this morning, one list, Barracuda, failed to answer, and the page reported it as unknown, not clean.</p><p>The code also expects its own recursive resolver, so Spamhaus sees a real, attributable server instead of a public one. A comment in the file explains why: public resolvers get the refusal code, and that “silently removes the two most important blocklists from the results.”</p><p>But the same file keeps two public resolvers as backups behind it, 1.1.1.1 and then 8.8.8.8, so that “a dead Unbound” (the resolver software) “degrades the blocklist checks rather than taking the whole site down.” And the blocklist code reads an empty answer as clean. NXDOMAIN is an empty answer.</p><p>Put those together and there’s a path to the quiet failure. If the checker’s own resolver and 1.1.1.1 were both out of reach, the query would go to Google, Google would say the name doesn’t exist, and my tool would show Spamhaus ZEN as “not listed”. That’s the false all-clear the tool’s own comments say it is built to avoid. It needs two things to fail first, so it isn’t likely. But it’s possible, and nothing on the page would show it.</p><p>There’s a second, smaller problem. You can’t run the RFC test through the tool yourself. Enter 127.0.0.2 and it refuses: “127.0.0.2 is a private or reserved address, so it cannot be a public sending IP.” That’s true of sending IPs, and it means the one input that proves the lookups work is the one the form won’t take.</p><h3>What the check should do instead</h3><p>The verification the file describes was done when the list was written, and as far as I can see in the code, it isn’t repeated when a check runs. The fix is to do it on every check: before trusting a “not listed” from a blocklist, ask the same list about 127.0.0.2 through the same resolver. If that doesn’t come back listed, report the list as unknown for this check, whatever the reason. It costs one extra query per list, and the result can be cached for a few minutes.</p><p>It’s the same test as the dig line above, run by the software instead of by a person who remembers to. A blocklist that can’t find its own test entry isn’t telling you anything about your sender, and the check should say so instead of showing a green row.</p><p>If you want to see how your own sending address looks on the major lists, with refusals shown as unknown, the checker is at <a href="https://notspoofed.com/ip">notspoofed.com/ip</a>. Run the dig line from your own server too. They test different machines.</p><p>Sources: RFC 5782, section 5 (rfc-editor.org). Spamhaus, “Using our public mirrors? Check your return codes now”, 11 February 2021. Spamhaus, “If you query the legacy DNSBLs via Cloudflare’s DNS move to Spamhaus Technology’s free Data Query Service”, 17 January 2022. Resolver answers from dns.google and cloudflare-dns.com, 26 October 2026, 07:23 UTC.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=49b1f67f474b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The EU Accessibility Law for Businesses Never Uses the Phrase “Accessibility Statement”]]></title>
            <link>https://medium.com/@josepollman/the-eu-accessibility-law-for-businesses-never-uses-the-phrase-accessibility-statement-5348fe6f184f?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/5348fe6f184f</guid>
            <category><![CDATA[ecommerce]]></category>
            <category><![CDATA[accessibility]]></category>
            <category><![CDATA[european-union]]></category>
            <category><![CDATA[web-accessibility]]></category>
            <category><![CDATA[google-search-console]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Fri, 23 Oct 2026 06:46:54 GMT</pubDate>
            <atom:updated>2026-10-23T06:46:54.322Z</atom:updated>
            <content:encoded><![CDATA[<h4>My new accessibility pages got their first two search clicks from a query for the public-sector directive. Reading both laws side by side showed me where the mix-up starts, and what my own pages leave out.</h4><p>On 19 October I put two new pages live on whattofixfirst.com, a site built mostly around page-speed checks. One is a scope checker: up to six questions that tell you whether the European Accessibility Act or the US Americans with Disabilities Act is likely to apply to your website. The other is an accessibility statement generator that writes the information the European Accessibility Act asks a shop to publish.</p><p>Search Console shows what happened next. In the month to 23 October the two pages had 11 impressions and 2 clicks between them. Both clicks came from the same query: “web accessibility directive”. One landed on the scope checker, which Google showed in seventh place. The other landed on the statement generator, at position 21. Both were on 19 October, the day the pages went up, and both came from Japan. It may well have been one person opening two results.</p><p>Two clicks are not a trend, and I won’t pretend they are. But the query doesn’t match either page. Neither one mentions the Web Accessibility Directive at all. I checked both again this morning. The scope checker’s page title starts “EAA &amp; ADA Scope Checker”. The generator’s reads “Accessibility Statement Generator: EAA Annex V &amp; US, Free”. The words “public sector” appear on neither.</p><p>So I read the two directives side by side to see why Google had matched them.</p><figure><img alt="Top of the accessibility statement generator page on whattofixfirst.com: the heading Accessibility statement generator, a paragraph saying EU mode follows the structure of Annex V of the European Accessibility Act, and a line saying it was updated 19 October 2026." src="https://cdn-images-1.medium.com/max/1024/1*PNRqw7YqjE0XwVBNZCNzGQ.png" /><figcaption>Screenshot of my own statement generator page on whattofixfirst.com, taken 23 October 2026. Not AI-generated.</figcaption></figure><h3>Two laws, two audiences</h3><p>The Web Accessibility Directive is Directive (EU) 2016/2102. Its full title says what it covers: “the accessibility of the websites and mobile applications of public sector bodies”. Article 1 repeats that and then carves out exceptions, such as public service broadcasters and NGOs that do not provide services essential to the public. The European Commission’s page on the directive, last updated in June 2026, says it has been in force since 22 December 2016 and that Member States report their monitoring results to the Commission every three years.</p><p>A business that sells online is covered by a different law, the European Accessibility Act, Directive (EU) 2019/882. Article 2(2)(f) lists “e-commerce services” among the services it covers when they are provided to consumers after 28 June 2025. Article 3(30) defines e-commerce as services provided at a distance, through websites and mobile apps, “at the individual request of a consumer with a view to concluding a consumer contract”.</p><p>The Commission’s own page draws the line in one sentence: the Web Accessibility Directive “complements the European Accessibility Act which covers a wide range of products and services also in the private sector.”</p><p>The two can overlap. Recital 46 of the Act says activities on public sector websites and apps that fall within its scope, such as e-commerce or passenger transport, should comply with the Act as well. So a public body that runs an online shop can have both. A private shop can only fall under one of them, and it is not the one with “web” in its name.</p><h3>Where the phrase comes from</h3><p>To find the link, I searched the EUR-Lex text of each directive for the phrase “accessibility statement”.</p><p>The Web Accessibility Directive uses it 11 times. Article 7 requires public sector bodies to publish “a detailed, comprehensive and clear accessibility statement” for each website, using a model statement that the Commission later adopted as Implementing Decision (EU) 2018/1523. The statement has to explain which content is not accessible and why, describe and link to a feedback mechanism, and link to the enforcement procedure.</p><p>The European Accessibility Act uses the phrase zero times. What it asks of a service provider is “information”. Article 13(2) says service providers “shall prepare the necessary information in accordance with Annex V”. Annex V says that information goes “in the general terms and conditions, or equivalent document”, and lists what it should contain where applicable: a general description of the service in accessible formats, the explanations needed to understand how the service works, and a description of how the service meets the accessibility requirements.</p><p>So the name on my tool, “accessibility statement”, is the public-sector directive’s term. The duty the tool writes for is the private-sector one, and that law never uses the name. Someone who types the formal name of the public-sector law and lands on a page with “accessibility statement” in its title has found a near miss.</p><h3>What the two pages say, and what they don’t</h3><p>The pages are not wrong about the Act. The scope checker cites Article 2(2)(f) and Article 3(30) for consumer e-commerce and says the requirements have applied since 28 June 2025. It handles the microenterprise exemption the way the text does: Article 4(5) exempts microenterprises that provide services, and Article 3(23) defines a microenterprise as one with fewer than 10 persons and an annual turnover or balance sheet total of no more than 2 million euros. The generator’s own FAQ says there is no official template for private companies, which matches Annex V.</p><p>What neither page does is tell a visitor who arrived from “web accessibility directive” whether they are in the right place. A public body using the generator would get a statement built on Annex V of the Act, when its duty under the other law is the Article 7 statement and the model in Decision 2018/1523. Nothing on the page would warn it.</p><p>The fix is a sentence or two near the top of both pages: the Web Accessibility Directive covers public sector websites and apps, its statement follows a fixed model, and this generator does not produce that one. It is not on the pages yet.</p><h3>The shortcut the Commission rules out</h3><p>One more line from the Commission’s page is worth quoting, because it applies under both laws. The legal requirements rest on the harmonised standard EN 301 549 v3.2.1, and on accessibility overlays the Commission is blunt: “Overlays, or any other tools which do not ensure the website itself meets the detailed criteria of the standard, are not an appropriate solution. It is best to fix accessibility issues at their source.”</p><p>That matters for anyone who has just found out which law applies to them and is looking for the fastest way out. A statement doesn’t fix anything either. It records what works, what doesn’t, and how a customer can still get served. My generator defaults to “partially conformant” and asks you to confirm each known limitation before it prints it. Its FAQ calls partial conformance “the honest state of almost every site”.</p><h3>What two clicks are worth</h3><p>Small sites get small data, and the easy choice is to ignore it until there is enough to mean something. A query still shows the words a visitor used before they reached you, at any volume. Those words can come from a different law, a different audience or a different problem than the one you built for.</p><p>Here the visitor’s words came from the public sector’s law, and my pages answered the private sector’s. The two directives share a goal, a technical standard and most of a vocabulary, and the difference between them fits in one sentence. It just has to be on the page.</p><p>If you run a shop that sells to consumers in the EU and want to know whether the Act reaches you, the <a href="https://whattofixfirst.com/accessibility/scope-checker">scope checker on whattofixfirst.com</a> walks through it in up to six questions, including the microenterprise test.</p><p><em>Sources: Directive (EU) 2016/2102, Articles 1 and 7; Directive (EU) 2019/882, Articles 2, 3, 4(5) and 13(2), recital 46 and Annex V (EUR-Lex, read 23 October 2026); European Commission, “Web accessibility”, last updated 23 June 2026; Google Search Console for whattofixfirst.com, 23 September to 23 October 2026. General information, not legal advice.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5348fe6f184f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The ConnectWise Backup Breach Needed No Customer Password]]></title>
            <link>https://medium.com/@josepollman/the-connectwise-backup-breach-needed-no-customer-password-c1668bd00259?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/c1668bd00259</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[information-security]]></category>
            <category><![CDATA[fraud-prevention]]></category>
            <category><![CDATA[microsoft-365]]></category>
            <category><![CDATA[third-party-risk]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Wed, 21 Oct 2026 06:34:37 GMT</pubDate>
            <atom:updated>2026-10-21T06:34:37.407Z</atom:updated>
            <content:encoded><![CDATA[<h4>A backup app’s own credential, held in the vendor’s tenant, was used to get tokens in customer Microsoft 365 tenants. I ran the vendor through my own supplier check this morning. It passed, which shows what a supplier check can’t see.</h4><p>The FAQ on my vendor checker answers a question most people would rather hear yes to: “Does a clean result mean it is safe to pay?” The answer is no. The checks cannot see the most common invoice fraud, where a real supplier’s mailbox is taken over and only the bank details on the invoice change.</p><p>In the guide that goes with it, I wrote that the attacker usually gets into that mailbox “with a password from an unrelated breach, or a phishing page that collected it weeks earlier.” That was true when I wrote it and it is still the common case. Last week showed a route that needed neither, and it came through a supplier.</p><h3>What happened</h3><p>ConnectWise Cloud Backup, which used to be called SkyKick, backs up Microsoft 365 and Google Workspace data for managed service providers and their clients. To do that, Huntress explains, the app is granted broad access to mailboxes, OneDrive, SharePoint, Teams and directory data in every tenant it is installed in.</p><p>On 15 October, according to Huntress’s write-up, the app’s identity signed in to customer tenants from a hosting-provider address between 06:13 and 08:34 UTC and received Microsoft Graph access tokens. Normal traffic from the app comes from Microsoft’s own cloud network. The sign-ins moved through tenants in sorted order a few seconds apart, which Huntress reads as a script working from a target list. By 19:00 UTC on 16 October Huntress had confirmed unauthorized sign-ins in 162 tenants. In a later update it reported sign-in activity from the same address in almost 1,000 Entra tenants, more than 300 of them successful.</p><p>Huntress is specific about the credential itself:</p><blockquote><em>“The credential type was a client assertion, which means the credential lives in the vendor’s own tenant. Nothing a customer did in their environment could have produced it.”</em></blockquote><p>No customer password was phished. There was no MFA prompt to get past either: in Huntress’s words, app-only sign-ins involve “no user, no device, and no MFA prompt.” The customer’s part in this was a decision made earlier: they, or their IT provider, consented to a backup app, and the app needed wide access to do its job.</p><p>It got worse in one tenant. Huntress saw a second ConnectWise app, the Cloud Management app for Microsoft Teams, add itself to the Global Administrator role at 03:44 UTC on 15 October and then put new client secrets on two other applications, one of them Huntress’s own. Those secrets were set to expire in 2028. Huntress’s 19 October update found a second tenant with the same pattern. It also says plainly that it has not tied that earlier activity to the same operator as the 06:13 sign-ins.</p><h3>What the vendor says it cannot see</h3><p>ConnectWise’s advisory on its Trust Center is unusually direct about the limits of its own response. It disabled seven application identities at 07:00 UTC on 17 October. Then come three sentences that matter to anyone who has approved a vendor app:</p><ul><li>Disabling the connections “does not reverse changes previously made inside a tenant.”</li><li>“Previously issued access tokens may remain usable until they expire or are otherwise invalidated.”</li><li>“Cloud Backup does not provide the downstream security visibility needed for us to determine independently whether a particular partner or customer tenant experienced unauthorized activity.”</li></ul><p>Put those together and the vendor that held the key is telling each customer to go and look for themselves. Huntress adds the reason why looking may not settle it: directory reads through Microsoft Graph leave no audit trail, so for the tenant it examined most closely, “tokens issued, nothing visible taken” is the current state. That is not the same as nothing taken.</p><p>As of the advisory’s 21 October 00:30 UTC update, Cloud Backup, SaaS Security and Cloud Management are still suspended, and ConnectWise says it is still working out how the unauthorized access first occurred.</p><h3>I ran the vendor through my own tool</h3><p>VetThisVendor runs five checks on a supplier: VAT registration, IBAN checksum, sanctions screening, the company register and the sending email domain. I only entered the domain, so the other four checks show as not run.</p><p>connectwise.com passed. SPF present, DMARC at quarantine, mail servers present, domain registered more than ten years ago. The green box says forged mail claiming to come from it is likely to be rejected or quarantined, which is a fair reading of its records.</p><figure><img alt="VetThisVendor result for connectwise.com: VAT, IBAN, sanctions and company register not checked because only a domain was entered; sending domain passes with SPF present, DMARC quarantine, MX present, registered over 10 years." src="https://cdn-images-1.medium.com/max/1024/1*ru_j6zwPEhZgMTG5bVYYXA.png" /><figcaption>VetThisVendor’s result for connectwise.com, run on 21 October 2026. Only the sending domain was entered. Screenshot of my own tool, not an AI-generated image.</figcaption></figure><p>None of that is wrong, and none of it is relevant to what happened. Every check I built answers a question about identity: is this business real, is this registration real, can someone pretend to be them by email. Not one of them asks what a supplier can already do inside your systems. A supplier with a perfect domain, a clean register entry and a long history can still hold standing access to every mailbox you have, through an app you approved once and forgot about.</p><p>I knew that in the abstract. The FAQ answer is there because I knew it. What this case added was a concrete version where the supplier itself was never the fraudster, the supplier’s own email was never forged, and nothing the customer did produced the credential that was used.</p><h3>Why someone who pays invoices should care</h3><p>This is where it touches my own subject. ConnectWise’s remediation guide tells every affected tenant to search the audit log for inbox rule changes, mailbox permission changes and transport rules, and to investigate “unexpected external forwarding, rules that hide or delete messages, new Full Access or Send As rights.”</p><p>That list is the toolkit of bank-detail fraud. My guide describes the same moves from the other side: an attacker inside a mailbox reads the thread, waits for a real invoice, and sometimes sets a rule so the customer’s replies never reach the real person.</p><p>Huntress says that in the two tenants it reviewed it found no sign of mailbox or file manipulation. Neither source reports any invoice fraud from this incident. The point is what the access allows, not what anyone has shown was done with it. A backup app has to read and write mail to back it up and restore it. Whoever holds its credential holds that too.</p><h3>What I would actually do with this</h3><p>If you approve vendor apps in Microsoft 365, or your IT provider does it for you:</p><ol><li>Open Enterprise applications in the Entra admin center and look at what has been consented. Huntress asks for management and security tools to be reviewed first, and a backup app has broad access by design.</li><li>For each of those, find the service principal sign-ins. Huntress points out that they are on a separate tab from user sign-ins, so the default view will not show them.</li><li>Ask the vendor three questions: what credential the app uses and where it lives, how fast they can revoke it, and whether they can see activity in your tenant if it is misused. ConnectWise’s own answer to the last one was no.</li><li>Know which controls help and which don’t. ConnectWise’s guide notes that Conditional Access for workload identities covers single-tenant service principals registered in your tenant, not third-party multitenant apps like this one. Huntress lists other Entra controls that limit the damage: application management policies that restrict client secrets and cap their lifetime, and fewer people holding the roles that can add credentials to apps.</li></ol><p>And if you pay suppliers, the old rule survives this intact. A bank-detail change gets a phone call to a number you already had, whatever the email looks like and however it got there. No check of the vendor from the outside will tell you who is sitting in the mailbox.</p><p>I build tools that check suppliers before you pay them, at <a href="https://vetthisvendor.com/guide/supplier-changed-bank-details">vetthisvendor.com</a>. The check describes the supplier on the day you run it. It says nothing about the keys you have already handed them.</p><p><em>Sources: Huntress, “ConnectWise (SkyKick) Vendor Credentials Abused in M365 Attacks” (published 16 October 2026, updated to 19 October), and ConnectWise Trust Center advisory “Cloud Backup (formerly known as SkyKick) Service Interruption” (first published 16 October 2026, read at its 21 October 00:30 UTC update).</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c1668bd00259" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Apple’s Servers Signed a Forged iCloud Address. My Header Analyzer Called It Good.]]></title>
            <link>https://medium.com/@josepollman/apples-servers-signed-a-forged-icloud-address-my-header-analyzer-called-it-good-cfb830b009b4?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/cfb830b009b4</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[email]]></category>
            <category><![CDATA[phishing]]></category>
            <category><![CDATA[email-security]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Mon, 19 Oct 2026 06:38:22 GMT</pubDate>
            <atom:updated>2026-10-19T06:38:22.078Z</atom:updated>
            <content:encoded><![CDATA[<h4>A now-fixed iCloud bug let a logged-in user send as any @icloud.com address with SPF, DKIM and DMARC all passing. I pasted the researchers’ headers into my own tool to see what a pass can and can’t tell you.</h4><p>On 1 October, SEC Consult published a write-up by Timo Longin with a title that says most of it: “From: anyone@icloud.com”. He found two ways to send mail through Apple’s own iCloud servers with somebody else’s iCloud address in the From line. The messages arrived at Gmail with SPF, DKIM and DMARC all passing. One of his test messages came from tim.cook@icloud.com.</p><p>Before anything else: this is fixed. The researchers confirmed Apple’s fix on 9 December 2025, after reporting the first bug in May 2024, and they only published once it was done. It also needed a logged-in iCloud account, the sender’s own, so it was never a way for a stranger with no account to send as Apple users.</p><p>I build notspoofed.com, a set of free email authentication tools, and a lot of what I’ve written about email authentication comes down to one sentence: a DMARC pass tells you the domain’s own servers sent the message. This is the cleanest real case I’ve seen of what that sentence leaves out.</p><h3>What the researchers did</h3><p>When you send through iCloud, you log in to Apple’s submission server and hand it a message. Apple checks that the From address in that message is one of yours. Try to put someone else’s address there and iCloud refuses with “From address is not one of your addresses”. That check is Apple’s own. SMTP doesn’t require it; each provider decides whether to enforce it.</p><p>Longin’s finding was that the message passed through two parsers inside iCloud, and they didn’t read it the same way. He calls them parser 1 and parser 2. Parser 1 did the From check. Parser 2, which the researchers think is based on Postfix, prepared the message for sending.</p><p>The first trick used bare carriage-return characters, a CR without the line feed that should follow it. He wrote two From headers. One had CR characters around the colon, so parser 1 didn’t treat it as a From header at all, and it checked the second one, his real address. Parser 2 then turned each bare CR into a proper line break. That cleaned up the fake header and pushed his real From line down into the body of the message, where nothing reads it as a header. The message left Apple with one From header, the forged one.</p><p>After Apple’s first round of changes, the researchers’ timeline says, the fix “merely blacklists the POC substring “admin”” in the From header, the word from his first proof of concept. A day after reporting that, they sent Apple a new working message from security@icloud.com. The second method, which Longin calls dot-peeling, abused the rule for lines that start with a full stop. Parser 2 followed that rule from the SMTP standard and parser 1 didn’t, which opened the same gap a different way.</p><p>Apple paid a $15,000 bounty in November 2024. The whole disclosure took about a year and a half.</p><h3>Why DKIM passed</h3><p>DKIM is a cryptographic signature over the message. You might expect a heavily rewritten message to break it. It didn’t, and the post explains why in one line: “DKIM signatures are created after parser 2 processed the message.”</p><p>Apple’s servers signed the message after the forgery had already happened. The signature was perfectly valid. It covered the forged From header because that was the From header by the time Apple signed. SPF passed because the message really did leave from Apple’s servers. DMARC passed because both of those results were for icloud.com, and the From address was at icloud.com too.</p><p>Every check did its job. None of them were built to answer the question that mattered here, which was whether this iCloud user was allowed to use that iCloud address.</p><h3>I pasted their headers into my own analyzer</h3><p>notspoofed.com has a header analyzer. You paste the raw headers from a message you received, and it shows the delivery path and explains why DMARC passed or failed. It runs entirely in the browser.</p><p>SEC Consult’s post prints the trace headers from one of their test messages as text: the Authentication-Results lines Gmail added, the Return-Path and the Received line. The From line only appears in their screenshots, so I added one myself, with the address from their proof of concept, plus a To and Subject line. Then I pressed Analyze.</p><p>The verdict was “GOOD, DMARC passed”. The explanation underneath: “The receiving server accepted this message as genuinely from icloud.com, authenticated by both SPF and DKIM.” The alignment table showed SPF and DKIM both passing for icloud.com, both “aligned (strict)” with the From domain.</p><figure><img alt="notspoofed.com header analyzer with pasted iCloud headers showing Return-Path attacker@icloud.com and From tim.cook@icloud.com. Verdict: GOOD, DMARC passed; SPF and DKIM pass for icloud.com, aligned (strict)." src="https://cdn-images-1.medium.com/max/1024/1*kYVdFiwlodLE3BMU3qJbJA.png" /><figcaption>My header analyzer’s verdict on the headers SEC Consult published, with a From, To and Subject line I added. Screenshot of my own tool, not AI-generated.</figcaption></figure><p>That verdict is accurate as far as it goes. The message really was authenticated as icloud.com. But higher up in what I pasted, above the Received line, is this:</p><pre>Return-Path: &lt;attacker@icloud.com&gt;</pre><p>The envelope sender, which in this test was the researchers’ own account, was attacker@icloud.com. The From line said tim.cook@icloud.com. My tool showed both addresses on the page and said nothing about the difference. It compares domains, because DMARC compares domains, and it didn’t compare the parts before the @.</p><h3>What a pass actually certifies</h3><p>DMARC was designed to stop people forging your domain from somewhere else. It does that well. At a domain like icloud.com, where every user shares the same domain, a pass can only mean “Apple’s servers sent this”. Which Apple user wrote that From line is a question for Apple’s own submission check, and nothing downstream can re-check it.</p><p>That isn’t a flaw in DMARC. It was never meant to answer that question. But the word “pass” is easy to read as more than it is: the email passed authentication, so it must be from who it says. For a shared domain, the honest reading is narrower. The provider vouched for the domain. You are trusting the provider’s own rules for everything after that.</p><h3>The one trace that was left</h3><p>The researchers point to the mismatch themselves. Mail from iCloud normally has the same address in the envelope and the From line, so a filter that knew that “could” flag it. They also add: “as it is, this is a legitimate and authenticated email.”</p><p>Could my analyzer flag it? It could compare the Return-Path with the From address. The hard part is not raising false alarms. Mismatches are normal for mailing lists, for newsletters sent through a delivery service, and for forwarded mail, where the envelope sender is often a bounce-handling address nobody reads. A warning on every mismatch would fire on a lot of ordinary marketing mail. A narrow check, only for big consumer mailbox domains where one person normally sends as themselves, would be quieter. I haven’t built it, and I’d want to test it on real mail before showing it to anyone.</p><h3>What I’d take from it</h3><p>If you approve payments or account changes partly because a message “passed authentication”, keep this case in mind. Every check passed on a forged address, at a major mail provider. Apple fixed this bug, but the gap between checking a domain and checking a person is built into how DMARC works. Sender identity at a shared mail domain rests on that provider’s own rules.</p><p>So a pass is where checking starts, not where it ends. For anything that moves money or changes access, confirm through a channel you already had, such as a phone number from your own records, not one from the message.</p><p>And if you read raw headers, look at the Return-Path next to the From line. In this case it was the only line that showed which account sent the message.</p><p>The header analyzer I used is free on <a href="https://notspoofed.com/headers">notspoofed.com</a>, needs no account, and runs in your browser.</p><p><em>Source: Timo Longin, “From: anyone@icloud.com”, SEC Consult blog, 1 October 2026, including its disclosure timeline. Read on 19 October 2026. Jose Pollman builds notspoofed.com.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cfb830b009b4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Meta’s New Business Terms Authorize Crawling for AI Training. They Never Mention Robots.txt.]]></title>
            <link>https://medium.com/@josepollman/metas-new-business-terms-authorize-crawling-for-ai-training-they-never-mention-robots-txt-2820b8b05e01?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/2820b8b05e01</guid>
            <category><![CDATA[web-scraping]]></category>
            <category><![CDATA[meta]]></category>
            <category><![CDATA[seo]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[web-crawler]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Fri, 16 Oct 2026 06:44:53 GMT</pubDate>
            <atom:updated>2026-10-16T06:44:53.904Z</atom:updated>
            <content:encoded><![CDATA[<h4>From 30 October, managing a Facebook Page means agreeing to a crawl clause. Checking my own robots.txt against it showed the file wasn’t blocking Meta’s training crawler in the first place.</h4><p>A small but steady set of searches turns up one of my sites, whattofixfirst.com: “are ai crawlers like gptbot blocked by default”, “do ai crawlers respect robots txt”, “ai crawler robots.txt”. The numbers are tiny, a handful of impressions each over the last four weeks, and the site ranks around position 90 for them. But the question behind them is clear. People want to know how to say no to AI training, and they assume the answer lives in robots.txt.</p><p>That is the answer my own guide gives. It lists the training-only crawlers, Meta’s meta-externalagent among them, and offers a one-group block: name them, add Disallow: /, done. It also says, plainly, that robots.txt &quot;is a request, not a wall&quot;.</p><p>This week I read a document that adds a different kind of answer, and it made me go back and check my own files.</p><h3>What Meta changed</h3><p>Meta publishes Commercial Terms that apply when you use its products “for a business or commercial purpose”. The updated version takes effect on 30 October 2026. Its list of business purposes includes “using ads or marketing messages”, “selling or listing products” and, the one that caught me, “managing a Page”.</p><p>The new version adds this paragraph under “Licenses &amp; Rights You Provide Meta”:</p><blockquote><em>You authorize us (or any entity acting on our behalf) to use automated software (such as web scrapers, bots, robots, spiders, crawlers, and user agents) and create test credentials to access, index, cache, analyze, collect, retrieve, or crawl the domains, web pages, or URLs (and any content available through them) that are associated with your products or services, or that are made available through your or users’ use of Meta Company Products and services, and to periodically pull updates from such domains, web pages, or URLs.</em></blockquote><p>The next sentence says Meta “may use any content from such domains, web pages, or URLs to provide, develop, improve, research, train, and maintain the integrity of” its products.</p><p>I counted words in both versions as rendered on facebook.com. The current terms, dated 6 March 2024, use “crawl” zero times, “scrape” zero times and “train” zero times. The new version uses “crawl” twice and “train” once. Neither version contains the string “robots.txt”. The new one doesn’t mention an opt-out.</p><p>How you accept is in the terms themselves. Both versions say that by continuing to use Meta’s products for business purposes after notice of an update, you agree to be bound. The new version ends that section with: “If you do not agree to the updated terms, you may stop all access or use of our Products for business or commercial purposes.”</p><h3>What Meta’s own crawler page says</h3><p>Meta also publishes a page for webmasters listing its crawlers, last updated 21 May 2026. It says Meta wants site owners to state preferences “by using industry-standard practices like robots.txt rather than non-standard formats like NoAI tags”. It describes Meta-ExternalAgent as crawling “for use cases such as training foundation AI models or improving products by indexing content directly”. To block a Meta crawler, it says, add a disallow for that crawler in robots.txt.</p><p>The same page names two exceptions. Meta-ExternalFetcher “may bypass robots.txt rules” because it fetches links at a user’s request, and FacebookExternalHit “might bypass robots.txt when performing security or integrity checks”.</p><p>So there are now two Meta documents that touch the same question. One says robots.txt is how you tell Meta’s training crawler to stay out. The other, for businesses, grants permission to crawl and train on sites “associated with your products or services” and does not mention robots.txt at all. The terms don’t say they override a robots.txt rule, and they don’t say they respect one. I’m not going to guess which wins. I’m not a lawyer, and nothing in either document answers it.</p><h3>Then I checked my own sites</h3><p>I manage Facebook Pages for three of my sites. The newest is for isitunderdosed.com, a pre-workout label checker, and most of its posts carry a link back to the site in the first comment. If any of my domains counts as “associated with your products or services”, that one does.</p><p>Its robots.txt, fetched live this morning, starts like this:</p><pre>User-agent: *<br>Content-Signal: search=yes, ai-input=yes, ai-train=no<br>Allow: /<br>Disallow: /report/thanks/</pre><p>Below that are groups for OpenAI’s, Anthropic’s and Perplexity’s search and answer crawlers, all allowed. There is no group for meta-externalagent, or for any training crawler.</p><p>I ran the file through the robots.txt checker on whattofixfirst.com, which I built. In site mode it fetches the live file and reads it the way each of 22 crawlers would. The verdict was “ALL CLEAR”. Every training crawler, meta-externalagent included, came back “Allowed”, each with the same reasoning: obeys the * group, line 3, Allow: /.</p><figure><img alt="Robots.txt checker result for isitunderdosed.com, model training section: GPTBot, ClaudeBot, anthropic-ai, cohere-ai, Google-Extended, Applebot-Extended, CCBot, meta-externalagent and Bytespider all Allowed, each obeying the * group, line 3, Allow: /." src="https://cdn-images-1.medium.com/max/736/1*x3raDdi3FBZ_TXnWreYuBg.png" /><figcaption>The training-crawler rows from my robots.txt checker on whattofixfirst.com, reading isitunderdosed.com’s live file on 16 October 2026. Screenshot of my own tool, not an AI-generated image.</figcaption></figure><p>That ai-train=no line reads like a refusal, but my own checker&#39;s FAQ explains why it isn&#39;t one. Content-Signal &quot;is a policy statement, not a rule: it stops no crawler, and none of the crawler documentation linked on this page mentions reading it.&quot; Meta&#39;s crawler page, read this morning, doesn&#39;t mention it either.</p><p>So the site with a Facebook business Page, and the only one of my sites whose robots.txt says ai-train=no, was never blocking Meta&#39;s training crawler. That was true before Meta changed a word of its terms.</p><p>The checker also has a blind spot here. It called the file “ALL CLEAR” because it judges whether the crawlers that cite you can reach you. It doesn’t compare the Content-Signal line with the rules underneath and point out that they disagree. It does offer the fix: a preset called “Opt out of training, stay visible” that adds one group blocking nine training crawlers, meta-externalagent among them.</p><h3>Three layers, and which ones you control</h3><p>After reading both Meta documents and my own files, this is how I’d sort it.</p><ol><li>The robots.txt rule: a User-agent: meta-externalagent group with Disallow: / is the mechanism Meta&#39;s own crawler page describes for blocking that crawler. It&#39;s in your file and you can change it in a minute.</li><li>The content signal: a Content-Signal line puts your preference on record. On its own it blocks nothing, and Meta’s crawler page doesn’t say it reads it.</li><li>The contract: if you run ads, sell through Meta, or manage a Page, the Commercial Terms apply to you. From 30 October they include the crawl and training clause, accepted by continuing to use those products. The only exit the terms name is to stop using them for business.</li></ol><p>The first two live in a text file on your server. The third lives in a document you accepted by clicking through, or will accept by carrying on as usual.</p><h3>What my guide leaves out</h3><p>My guide on which AI crawlers to allow treats this purely as a crawler question: which user agents to name, which groups to write, which fetchers to leave alone. For most sites that’s still the right frame. For anyone who also manages a Facebook Page or runs Meta ads, it now leaves out half the picture. The guide can tell you how to write the request. It can’t tell you what you’ve already agreed to elsewhere.</p><p>What I’d suggest to anyone in the same position is small. Fetch your live robots.txt in a browser, since your CDN may have changed it. Check whether meta-externalagent is actually disallowed or only covered by a signal line. Then read the “Licenses &amp; Rights You Provide Meta” paragraph in the updated terms before 30 October, with the scope wording in front of you: domains “associated with your products or services”. Meta doesn’t define that phrase any further.</p><p>The robots.txt checker I used is free on <a href="https://whattofixfirst.com/robots-txt-checker">whattofixfirst.com</a> and needs no signup. Paste a file or give it a URL.</p><p><em>Sources: Meta Commercial Terms, current (effective 6 March 2024) and updated (effective 30 October 2026), facebook.com/legal; Meta Web Crawlers developer page, updated 21 May 2026. All read on 16 October 2026. Jose Pollman builds whattofixfirst.com and isitunderdosed.com.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2820b8b05e01" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Brevo’s Attacker Didn’t Need to Forge a DNS Record. A Cloudflare Key Let Them Write One.]]></title>
            <link>https://medium.com/@josepollman/brevos-attacker-didn-t-need-to-forge-a-dns-record-a-cloudflare-key-let-them-write-one-757176ef9aac?source=rss-49c92569c42a------2</link>
            <guid isPermaLink="false">https://medium.com/p/757176ef9aac</guid>
            <category><![CDATA[dns]]></category>
            <category><![CDATA[information-security]]></category>
            <category><![CDATA[dnssec]]></category>
            <category><![CDATA[cloudflare]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Josepollman]]></dc:creator>
            <pubDate>Wed, 14 Oct 2026 06:37:42 GMT</pubDate>
            <atom:updated>2026-10-14T06:37:42.372Z</atom:updated>
            <content:encoded><![CDATA[<h4>For five and a half hours a fake verification page ran on Brevo’s own domains while its servers stayed untouched. Reading the post-mortem sent me back to one line in my own DNS checker.</h4><p>Brevo, the email marketing company, published a post-mortem about an attack on its own websites on 14 September. One sentence in the root-cause section is why I read it twice:</p><blockquote><em>Because the Worker rewrote responses at the edge and removed security headers such as Content-Security-Policy, our origin servers and files remained unmodified and standard integrity checks did not detect the change.</em></blockquote><p>Nothing on Brevo’s servers was altered. The pages visitors received were. Everything in between happened inside a CDN account, and what opened that account was one API key.</p><h3>What happened on 14 September</h3><p>The timeline in the post-mortem is short. All times are UTC.</p><p>At 14:23 the attacker created a hostname on a Brevo-owned domain. At 14:28 they deployed a Cloudflare Worker, a small script that runs at Cloudflare’s edge and can rewrite a response before it reaches the visitor, and tested it on low-traffic Brevo domains. At 15:01 the Worker was routed to all of brevo.com. At 16:07 it was updated to append a loader to three JavaScript files that Brevo customers embed on their own websites: the forms script, the Conversations widget and the SDK loader.</p><p>Some visitors got a full-screen page dressed up as a Cloudflare “verify you are human” check. It asked them to press Win+R, then Ctrl+V, then Enter, which runs a command the script had already put on the clipboard. That command downloaded malware onto Windows machines. The technique is known as ClickFix. Brevo says the page “was shown selectively, so most visitors and repeat visits saw nothing.” On WordPress sites that embedded a Brevo widget, if the visitor was a logged-in administrator, the script also tried to install and activate a plugin.</p><p>The security incident was opened at 19:33, about four and a half hours after the impact began. The Worker and its routes were gone by 20:30. Brevo lists app.brevo.com, its API, email sending and customer account data as not affected.</p><h3>The key</h3><p>Here is the root cause in Brevo’s words: “A long-lived Cloudflare API key with full account permissions was stored in application source code and was obtained by the attacker. With it, they could create Workers, routes and DNS records on Brevo’s zones without triggering an alert.”</p><p>Two details matter. “Full account permissions” means the key could do far more than whatever job it was made for. And the investigation says the key “was first misused in late August 2026”. Brevo found no injected content before 14 September, but someone had the key for weeks.</p><p>Brevo published all of this plainly, with times, scope and an unglamorous cause. That is the only reason the rest of this piece can be written.</p><h3>The line in my own tool</h3><p>I run <a href="https://notspoofed.com/check?domain=notspoofed.com">notspoofed.com</a>, a checker that reads a domain’s public DNS records (SPF, DKIM, DMARC, MX, MTA-STS and DNSSEC) and says what to fix. This morning I ran it on its own domain. One of the green boxes in the result says notspoofed.com “is signed, so its DNS answers”, every record on the page included, “cannot be forged in transit.”</p><figure><img alt="notspoofed.com result page for notspoofed.com: 1 issue worth fixing, SPF 2 of 10 lookups, DMARC p=reject, DNSSEC signed. Two green boxes read DMARC is at p=reject and DNSSEC is enabled, followed by the SPF, DMARC, MX and DKIM records as published." src="https://cdn-images-1.medium.com/max/1024/1*b7ZQ_cveTM5TyRkHakc8Yg.png" /><figcaption>notspoofed.com checking its own domain on 14 October 2026. Screenshot of my own tool, not an AI-generated image.</figcaption></figure><p>That sentence is true. DNSSEC lets a resolver confirm that an answer came from the zone and was not altered on the way. It cannot tell anyone how the record got into the zone. DNSSEC signs whatever the zone holds, and Cloudflare described in a 2015 blog post how it generates those signatures at the edge, on demand. A record created through the API with a stolen key goes through the same signing as one the owner typed into the dashboard. It comes out signed and valid, and nothing in the answer separates the two.</p><p>The same holds for everything else my checker reads. It reports the SPF record, the DMARC policy and the DKIM keys as they are published at that moment. Suppose someone holding a key like Brevo’s had added an include to an SPF record, or published a DKIM key of their own on a new selector. My tool would have reported a correctly formed record, because it would have been one. It has no idea who wrote a record or when.</p><p>As far as the post-mortem says, Brevo’s attacker did not touch mail records. They created a hostname and pointed web traffic at a script. But the key allowed DNS changes on Brevo’s zones, and mail authentication is made of DNS records.</p><h3>Where the evidence was</h3><p>Brevo’s integrity checks looked at its origin servers and files, and those were clean the whole time. The change lived in configuration: a Worker, its routes, a hostname. An outside DNS check like mine looks at the published result and sees well-formed records. Neither view registers the change as a change.</p><p>The account itself is what recorded it. Look at what Brevo says it is changing:</p><ul><li>“Alerting on every Cloudflare audit event that changes Workers, routes, DNS or account access, reviewed by the security team.”</li><li>Cloudflare logs streamed into its security monitoring.</li><li>Every Cloudflare key and token kept in HashiCorp Vault, “with automatic rotation and no credentials in source code or configuration files.”</li><li>“Integrity protection for versioned embedded assets where technically possible, and regular external scanning of our public pages and scripts for injected content.”</li></ul><p>For a small operator the first item matters most, because an audit event is the only record of who changed a zone and when. The last item is an outside view, the kind my tool takes, and Brevo lists it as one layer among several.</p><h3>What I looked up on my own setup</h3><p>All five of my sites (notspoofed.com, vetthisvendor.com, whattofixfirst.com, subcovered.com and knowyourmouth.com) answer from the same two Cloudflare nameservers. I confirmed that this morning with a plain NS lookup. So Brevo’s question applies to me directly: whoever can edit those zones can change the mail records of all five domains, and every outside check, mine included, would report the result as genuine.</p><p>The part I cannot answer from outside is the part that decides it: which credentials can edit those zones, how widely each one is scoped, and whether a change would alert anyone. That only exists inside the account, in the token list and the audit log. My tool cannot see it, and neither can any other public DNS checker.</p><h3>If your DNS lives behind an API</h3><p>None of this is new, and all of it is easy to put off:</p><ol><li>List every API key and token that can touch your DNS or edge configuration, and what each one is allowed to do. A token that only needs to purge a cache should not be able to create DNS records.</li><li>Keep long-lived keys out of source code. Brevo replaced its key with “narrowly scoped, short-lived tokens.”</li><li>Get alerted when a DNS record, a route or an edge script changes. Brevo’s attacker had more than four hours on brevo.com before an incident was opened.</li><li>Treat an outside check as a snapshot of what is published. A clean result says the records are well formed. It does not say they are the records you put there.</li></ol><h3>The second question</h3><p>The usual question about a DNS record is whether it is correct. Brevo’s post-mortem adds a second one: who else can change it. Signing, a strict DMARC policy and a clean scan all answer the first question. Only the account can answer the second.</p><p>My check of notspoofed.com still shows “1 issue worth fixing”: a 1024-bit DKIM key that my mail provider has to reissue. That one I can see from the outside.</p><p><em>Sources: Brevo, “Post-mortem: malicious “ClickFix” script served via Brevo’s Cloudflare account” (status.brevo.com, 14 September 2026); Cloudflare blog, “DNSSEC Done Right” (29 January 2015). I build notspoofed.com, a free SPF, DKIM and DMARC checker.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=757176ef9aac" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>