<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>linefeed.sh — Luke Francis</title><description>Security research from Luke Francis: CVEs, writeups, browser internals, codec audits.</description><link>https://linefeed.sh/</link><language>en-us</language><item><title>Wonder Ad Blocker: Reverse Engineering a Malicious Chrome Extension</title><link>https://linefeed.sh/research/wonder-adblocker/</link><guid isPermaLink="true">https://linefeed.sh/research/wonder-adblocker/</guid><description>A Chrome extension marketed as an ad blocker — with 500,000+ users — was operating as a distributed ad-intelligence scraping platform. Reverse engineering revealed tracking-script injection, browsing-data harvesting, and command infrastructure phone-home.</description><pubDate>Sun, 26 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was pirating a movie. I’m not going to pretend there’s a noble origin story here. I was on one of those sites, a popup appeared trying to get me to install a Chrome extension called “Ad Block Wonder,” and instead of closing it like a normal person, I thought: I wonder what this thing actually does.&lt;/p&gt;
&lt;p&gt;It had 500k users. 4+ stars on the Chrome Web Store. The listing calls it “the successor to uBlock”, which is a wild claim to make about an extension distributed through piracy site popups, but sure. I pulled the source code and started reading.&lt;/p&gt;
&lt;p&gt;I did not expect to spend the next several hours mapping out a six-platform ad intelligence scraping operation.&lt;/p&gt;
&lt;h2 id=&quot;barely-2000-lines-of-code&quot;&gt;”Barely 2000 lines of code”&lt;/h2&gt;
&lt;p&gt;We’ll get to why that quote matters in a minute, but let’s start with what’s actually in this extension.&lt;/p&gt;
&lt;p&gt;The first thing you notice is a directory called &lt;code&gt;src/blocker/special/scripts/&lt;/code&gt;. Inside are six files: &lt;code&gt;facebook.js&lt;/code&gt;, &lt;code&gt;x.js&lt;/code&gt;, &lt;code&gt;reddit.js&lt;/code&gt;, &lt;code&gt;tiktok.js&lt;/code&gt;, &lt;code&gt;pinterest.js&lt;/code&gt;, &lt;code&gt;twitch.js&lt;/code&gt;. Each one is a dedicated scraping module for its respective platform. These aren’t blockers at all, they’re collectors. They hook into browser APIs to intercept API responses in real time and extract ad data from them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;facebook.js&lt;/code&gt; is 2,206 lines. Just that one file. For an extension that “barely” has 2,000 lines total. The full codebase across JS/CSS/JSON is over 1.7 million lines.&lt;/p&gt;
&lt;p&gt;But I’m getting ahead of myself.&lt;/p&gt;
&lt;h2 id=&quot;your-browsing-history-on-a-schedule&quot;&gt;Your browsing history, on a schedule&lt;/h2&gt;
&lt;p&gt;Before we even get to the fun platform-specific stuff, let’s talk about what the extension does on every single page you visit.&lt;/p&gt;
&lt;p&gt;A content script called &lt;code&gt;broker.js&lt;/code&gt; runs on every URL, at &lt;code&gt;document_start&lt;/code&gt;, in all frames. Every time you navigate to a top-level page, it logs the domain and increments a counter. Visit Reddit 47 times this week? It knows. These get stored as &lt;code&gt;navDoms&lt;/code&gt;: a neat little dictionary of your browsing habits with frequency counts.&lt;/p&gt;
&lt;p&gt;When you first install the extension, a function called &lt;code&gt;installDataGathering()&lt;/code&gt; runs and snapshots every tab you currently have open. All those domains go into &lt;code&gt;installDoms&lt;/code&gt;. So, from the moment of installation, the extension knows what you were doing.&lt;/p&gt;
&lt;p&gt;Both of these — your ongoing browsing history and your install-time snapshot — get POSTed as plaintext JSON to the developer’s server. In v3.8 that was &lt;code&gt;wonderadblock.com/wonder-3_7.php&lt;/code&gt;. In v4.1 it moved to &lt;code&gt;wonderupdates.com/wonder-3_7.php&lt;/code&gt;. More on that domain switch later.&lt;/p&gt;
&lt;p&gt;The payload also includes a persistent user ID (stored as &lt;code&gt;wonderinformation&lt;/code&gt; — incredible variable name), your extension version, your personal allowlist, and as of v4.1, three shiny new tracking parameters: &lt;code&gt;sid&lt;/code&gt;, &lt;code&gt;cid&lt;/code&gt;, and &lt;code&gt;an&lt;/code&gt;. Those are affiliate/campaign attribution tags scraped from the Chrome Web Store URL at install time. They tell the developer which ad network or shady popup drove your install, so they can pay their distribution partners accordingly.&lt;/p&gt;
&lt;p&gt;No encryption on any of this by the way. The HTTP helper is a bare &lt;code&gt;fetch()&lt;/code&gt; with &lt;code&gt;Content-Type: application/json&lt;/code&gt; and &lt;code&gt;JSON.stringify(body)&lt;/code&gt;. Just plaintext JSON over HTTPS. They didn’t even try.&lt;/p&gt;
&lt;h2 id=&quot;facebook-2206-lines-of-not-a-facebook-script&quot;&gt;Facebook: 2,206 lines of “not a Facebook script”&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;facebook.js&lt;/code&gt; is where things get genuinely impressive, in a “wow, someone put real engineering effort into this grift” kind of way.&lt;/p&gt;
&lt;p&gt;The file starts with hardcoded lookup tables for parsing personal data. Relationship statuses, like Single, In a Relationship, Married, Engaged, Civil Union, Domestic Partnership, Open Relationship, It’s Complicated, Separated, Divorced, Widowed. Education levels from “In high school” through “Doctorate degree.” These are for categorizing you.&lt;/p&gt;
&lt;p&gt;The main event is &lt;strong&gt;WAIST scraping&lt;/strong&gt; — WAIST being Facebook’s “Why Am I Seeing This” transparency feature. When you click that on an ad, Facebook shows you what targeting criteria the advertiser used to reach you. This extension scrapes all of it automatically for every ad it encounters. The targeting categories it extracts include:&lt;/p&gt;
&lt;p&gt;Age and gender. Relationship status. Education level and schools. Employer and job title. Interests. Location. Locale. And the really fun ones — Custom Audiences from datafiles (advertiser-uploaded customer lists), Custom Audiences from website pixel tracking, Custom Audiences from mobile app activity, and Lookalike audiences. Over 30 targeting categories total.&lt;/p&gt;
&lt;p&gt;There’s a whole &lt;code&gt;ParseWAIST&lt;/code&gt; module that resolves Facebook’s internal Relay GraphQL fragments and packages the targeting data with the advertiser’s ID, name, and profile picture into a clean object. Someone sat down and reverse engineered Facebook’s internal ad transparency UI to build this. That’s not trivial work.&lt;/p&gt;
&lt;p&gt;But it gets better. There’s a function called &lt;code&gt;getAccessToken()&lt;/code&gt; (which, just by the way, incredible naming decision if you’re trying to claim this extension is innocent). It navigates to &lt;code&gt;adsmanager.facebook.com/adsmanager/&lt;/code&gt; inside your authenticated session, scrapes the &lt;code&gt;__accessToken&lt;/code&gt; (a 100+ character Facebook Graph API token), the token’s expiry time, and your &lt;code&gt;c_user&lt;/code&gt; cookie (your Facebook user ID). These get stored in an IndexedDB database named &lt;code&gt;mooz&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The extension then uses your stolen token to make authenticated Graph API calls for advertiser fanpage data, like contact info, email, phone numbers, business hours, Instagram account, follower counts. This is happening silently in the background while you browse Facebook thinking your ads are being blocked. Whether it’s also sent to the developer’s server I can’t confirm from static analysis, but it’s being harvested and stored persistently either way.&lt;/p&gt;
&lt;p&gt;And to make all of this work, the extension injects a &lt;code&gt;declarativeNetRequest&lt;/code&gt; rule (ID &lt;code&gt;9999992&lt;/code&gt;, because of course it’s a magic number) that overrides Facebook’s own CORS security headers. It sets &lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; to &lt;code&gt;facebook.com&lt;/code&gt; on all Facebook responses. Facebook’s security team put those headers there for a reason. This extension removes them.&lt;/p&gt;
&lt;h2 id=&quot;the-same-pattern-five-more-times&quot;&gt;The same pattern, five more times&lt;/h2&gt;
&lt;p&gt;The same hook-intercept-exfiltrate pattern repeats across X/Twitter, Reddit, TikTok, Pinterest, and Twitch. Each module hooks &lt;code&gt;XMLHttpRequest&lt;/code&gt; or &lt;code&gt;fetch&lt;/code&gt; prototypes to intercept API responses, filters for ad content, and extracts targeting and engagement data. The technique varies slightly per platform, but the structure is identical. Intercept the API response before the page sees it, extract the ad data, send it home. (Side note: the handler that would relay it to the server isn’t obviously wired up in these versions, but everything is there for it to do so.)&lt;/p&gt;
&lt;p&gt;Twitch is worth calling out separately because it crosses a line the others don’t. The fetch hook captures your &lt;code&gt;Authorization&lt;/code&gt; header, &lt;code&gt;Client-Integrity&lt;/code&gt; token, &lt;code&gt;Client-ID&lt;/code&gt;, and &lt;code&gt;Device-ID&lt;/code&gt; from intercepted GQL requests, then uses those credentials to make its own authenticated requests on your behalf. It also overrides &lt;code&gt;document.visibilityState&lt;/code&gt; and &lt;code&gt;document.hidden&lt;/code&gt;, tricking the site into thinking you’re actively watching when you’re not. This is, pretty cleanly, credential harvesting.&lt;/p&gt;
&lt;h2 id=&quot;the-fake-stats&quot;&gt;The fake stats&lt;/h2&gt;
&lt;p&gt;My favorite detail. When you click the extension popup, it shows you stats about how much data the extension has “saved” you and how much faster your pages are loading. Confidence-inspiring numbers with units and everything.&lt;/p&gt;
&lt;p&gt;They’re completely made up.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;randomBetweenTwoNumbers(400, 600)&lt;/code&gt; for the timing. &lt;code&gt;randomBetweenTwoNumbers(30, 60)&lt;/code&gt; for the kilobytes. Literally &lt;code&gt;Math.random()&lt;/code&gt;. The stats in the popup are generated fresh every time you look at them with no relation to anything that actually happened. Pure theatre for user retention.&lt;/p&gt;
&lt;p&gt;I genuinely respect the audacity.&lt;/p&gt;
&lt;h2 id=&quot;the-remote-control&quot;&gt;The remote control&lt;/h2&gt;
&lt;p&gt;When the extension phones home, the server sends instructions back. The response can include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wondercycle&lt;/code&gt;, which controls how often the extension phones home&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rules&lt;/code&gt;, an array of &lt;code&gt;declarativeNetRequest&lt;/code&gt; rules that gets applied via &lt;code&gt;updateDnrRules()&lt;/code&gt;, which replaces all existing dynamic rules with whatever the server sends&lt;/li&gt;
&lt;li&gt;&lt;code&gt;whitelistedDomains&lt;/code&gt; and &lt;code&gt;allowedDomains&lt;/code&gt;, domains that bypass all blocking entirely&lt;/li&gt;
&lt;li&gt;&lt;code&gt;scriptletExcludes&lt;/code&gt;, domains excluded from scriptlet injection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The developer has full remote control over what gets blocked and what doesn’t across 500k browsers. That &lt;code&gt;rules&lt;/code&gt; array can include redirect rules, not just block/allow. The mechanism to silently redirect URLs through the extension is sitting right there.&lt;/p&gt;
&lt;h2 id=&quot;the-developer-responds&quot;&gt;The developer responds&lt;/h2&gt;
&lt;p&gt;I posted a review detailing the browsing history exfiltration and the existence of the platform scraping modules. The developer replied publicly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am genuinely speechless… I can only assume you’re mistaking my extension with another. There is no Facebook specific script… there is barely 2000 lines of code in the whole extension.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;He then asked me to “be kind enough to correct your review.”&lt;/p&gt;
&lt;p&gt;So I downloaded v4.1, the version he shipped after my review. I diffed it against v3.8.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;facebook.js&lt;/code&gt; is byte-for-byte identical. Still 2,206 lines. Still imported at &lt;code&gt;scripts.js:1&lt;/code&gt;. Still mapped to &lt;code&gt;facebook.com&lt;/code&gt; in &lt;code&gt;domains.js:2&lt;/code&gt;. Still scraping WAIST data. Still stealing Graph API tokens. The developer shipped a new version, replied publicly claiming the file doesn’t exist, and didn’t change a single byte of it.&lt;/p&gt;
&lt;p&gt;What did change in v4.1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The server endpoint moved from &lt;code&gt;wonderadblock.com&lt;/code&gt; to &lt;code&gt;wonderupdates.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Three new tracking parameters (&lt;code&gt;sid&lt;/code&gt;, &lt;code&gt;cid&lt;/code&gt;, &lt;code&gt;an&lt;/code&gt;) were added to the exfiltration payload.&lt;/li&gt;
&lt;li&gt;The new tracking keys were mirrored to Chrome sync storage so they persist across reinstalls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So after being publicly called out for data collection, the developer: denied everything, moved the server to a new domain, and added more tracking. I’ll let you sit with that for a minute.&lt;/p&gt;
&lt;h2 id=&quot;the-product-itself&quot;&gt;The product itself&lt;/h2&gt;
&lt;p&gt;None of this code is obfuscated. Every variable name is plaintext: &lt;code&gt;getAccessToken&lt;/code&gt;, &lt;code&gt;sendAd&lt;/code&gt;, &lt;code&gt;wonderinformation&lt;/code&gt;, &lt;code&gt;navDoms&lt;/code&gt;, &lt;code&gt;installDoms&lt;/code&gt;. The developer didn’t webpack it, didn’t minify it, didn’t run it through any kind of transform. They just shipped human-readable JavaScript that steals your Facebook access token in a function called &lt;code&gt;getAccessToken&lt;/code&gt; and apparently assumed nobody would ever open the files and look.&lt;/p&gt;
&lt;p&gt;For 500k installs and months on the Chrome Web Store, they were right. The Web Store review process didn’t flag any of it. The extension has a 4+ star rating. It’s still live as of this writing.&lt;/p&gt;
&lt;p&gt;But I think the interesting question isn’t “how did this get through review.” It’s “what is this thing actually for.”&lt;/p&gt;
&lt;p&gt;This isn’t adware in the traditional sense. The developer isn’t injecting banner ads into your pages or swapping out affiliate links. This is an &lt;strong&gt;ad intelligence platform&lt;/strong&gt;. Someone is building a cross-platform dataset of ad creatives, targeting parameters, engagement metrics, and advertiser contact information — harvested from real user sessions on Facebook, X, Reddit, TikTok, Pinterest, and Twitch. Layered on top is per-user browsing history with visit frequency, tied to a persistent ID, with affiliate attribution tracking to map the install funnel.&lt;/p&gt;
&lt;p&gt;That’s a product. Ad intelligence platforms, at least the legitimate ones, charge thousands per month for this kind of data. Who’s running ad campaigns on Facebook targeting women aged 25–34 in Dallas who work at Deloitte and are interested in yoga? What creative are they using? How much engagement is it getting? What’s the advertiser’s contact info? Normally you’d need to pay a SaaS company a lot of money for those answers. Or you could just contact “Ad Block Wonder” and let half a million people’s browsers collect it for you for free.&lt;/p&gt;
&lt;p&gt;The browsing history adds a behavioral layer on top, because now you don’t solely have ad targeting data, you have it correlated with browsing patterns. The affiliate tracking adds a distribution layer — you know exactly which shady popup networks are driving installs, so you can scale the ones that work. The remote-controlled whitelist adds a second revenue stream, as ad networks can pay to get un-blocked across 500k browsers with no user visibility. The server-pushed DNR rules add a third: arbitrary redirect capability across every URL those 500k users visit.&lt;/p&gt;
&lt;p&gt;This is the full stack of a shadow ad intelligence business, distributed through piracy site popups and disguised as an ad blocker. The only thing I can’t tell you from the code alone is who’s buying the data on the other end.&lt;/p&gt;
&lt;p&gt;The extension is still live on the Chrome Web Store as of this writing. I’ve reported it to Google and the affected platforms’ security teams. &lt;strong&gt;If you have it installed, remove it.&lt;/strong&gt;&lt;/p&gt;</content:encoded><category>reverse-engineering</category><category>chrome-extension</category><category>malware</category><category>web</category></item><item><title>48 Hours on a SCADA Honeypot</title><link>https://linefeed.sh/research/scada-honeypot/</link><guid isPermaLink="true">https://linefeed.sh/research/scada-honeypot/</guid><description>A SCADA-themed honeypot on Hetzner caught WannaCry samples still propagating in 2026, Outlaw/mdrfckr botnet credential stuffing, Solana validator credential harvesting, and automated Modbus/TCP scanning.</description><pubDate>Mon, 06 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;What happens when you disguise a Hetzner VPS as a small-town water treatment plant and point it at the internet? 47,771 events, eight attack campaigns, and a nine-year-old piece of North Korean malware. In two days.&lt;/p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The setup&lt;/h2&gt;
&lt;p&gt;On a Friday night in April 2026, I deployed a high-interaction honeypot on a Hetzner Cloud server in Ashburn, Virginia, themed as the internet-facing SCADA gateway for a fictional municipal water utility called Cedar Creek Municipal Water Authority.&lt;/p&gt;
&lt;p&gt;The goal wasn’t groundbreaking research. I just wanted to watch attackers do their thing.&lt;/p&gt;
&lt;p&gt;The infrastructure was built on T-Pot, Deutsche Telekom’s open-source honeypot platform, running 39 Docker containers across about 20 different honeypot services. The box emulated SSH, Telnet, HTTP/HTTPS, SMB, SMTP, SIP, Modbus, S7comm, SNMP, IEC 60870-5-104, BACnet, IPMI, and a handful of others, all on a single IP address.&lt;/p&gt;
&lt;p&gt;The ICS theming was the fun part. Conpot was configured to respond to SNMP queries with &lt;code&gt;Siemens, SIMATIC, S7-300&lt;/code&gt;, a common PLC found in water treatment plants. Cowrie’s fake SSH filesystem was populated with directories like &lt;code&gt;/opt/schneider/&lt;/code&gt; and &lt;code&gt;/var/log/scada/&lt;/code&gt;, a &lt;code&gt;.bash_history&lt;/code&gt; full of &lt;code&gt;modpoll&lt;/code&gt; commands, and an MOTD referencing NIST 800-82.&lt;/p&gt;
&lt;p&gt;On top of T-Pot, I built a custom employee portal on port 9443: a Cedar Creek MWA login page styled to look like a dated ASP.NET intranet running on IIS 8.5. It served a &lt;code&gt;robots.txt&lt;/code&gt; that “accidentally” exposed internal paths like &lt;code&gt;/admin/&lt;/code&gt;, &lt;code&gt;/scada/&lt;/code&gt;, &lt;code&gt;/vpn/&lt;/code&gt;, and &lt;code&gt;/owa/&lt;/code&gt;. The unprotected directories contained an Active Directory LDIF export with employee usernames, and a Swagger API doc with a dev key in the comments. The protected directories (behind basic auth that accepted the same AD credentials — password reuse as the vulnerability) contained IT meeting minutes, PLC commissioning notes, a disaster recovery plan, and a VPN config file. Credentials were buried inside boring operational documents, not sitting in files labeled &lt;code&gt;passwords.txt&lt;/code&gt;. The whole thing was designed as a realistic attack chain: find the portal, discover usernames from the AD export, find passwords through credential reuse, log in, explore the fake intranet.&lt;/p&gt;
&lt;p&gt;Nobody found the portal credential chain in 48 hours. The bots had other priorities.&lt;/p&gt;
&lt;h2 id=&quot;the-first-hour&quot;&gt;The first hour&lt;/h2&gt;
&lt;p&gt;Within minutes of going live, the traffic started. By the end of the first hour, the dashboard showed 33 attacks. Cowrie was catching SSH banner grabs: 0.2-second connections from scanners probing port 22 and immediately disconnecting. The SSH client string was &lt;code&gt;SSH-2.0-libssh-0.2&lt;/code&gt;, a lightweight library commonly used by automated scanners. No humans yet, just bots mapping what was listening on the Hetzner IP range.&lt;/p&gt;
&lt;p&gt;Port 445 (SMB) was the most-hit port in the first hour. That turned out to be a preview of something much more interesting.&lt;/p&gt;
&lt;p&gt;By the time I went to sleep at 3 AM, roughly two hours after deployment, the event count was at 8,500. The username and password tag clouds in Kibana told a story: alongside the expected &lt;code&gt;root/admin&lt;/code&gt; and &lt;code&gt;root/123456&lt;/code&gt; attempts, there were clusters of Solana-specific credentials. &lt;code&gt;solana/solana&lt;/code&gt;, &lt;code&gt;sol/sol&lt;/code&gt;, &lt;code&gt;solnode/solnode&lt;/code&gt;, &lt;code&gt;helius/helius&lt;/code&gt;, &lt;code&gt;firedancer/firedancer&lt;/code&gt;, &lt;code&gt;raydium/raydium&lt;/code&gt;. Someone was running a credential list specifically targeting Solana validator nodes on Hetzner infrastructure.&lt;/p&gt;
&lt;h2 id=&quot;campaign-1-mdrfckr&quot;&gt;Campaign 1: mdrfckr&lt;/h2&gt;
&lt;p&gt;The first full intrusion sessions appeared within a few hours. Every single one followed an identical playbook: strip immutable flags from &lt;code&gt;.ssh&lt;/code&gt; with &lt;code&gt;chattr -ia&lt;/code&gt;, nuke and recreate the &lt;code&gt;.ssh&lt;/code&gt; directory, plant a single authorized key with the comment &lt;code&gt;mdrfckr&lt;/code&gt;, check CPU info and core count, change the root password with &lt;code&gt;chpasswd&lt;/code&gt;, kill competing malware processes, blank out &lt;code&gt;hosts.deny&lt;/code&gt;, then run a full hardware survey (CPU model, RAM, disk, architecture via &lt;code&gt;uname&lt;/code&gt;, &lt;code&gt;lscpu&lt;/code&gt;, &lt;code&gt;free&lt;/code&gt;, and &lt;code&gt;df&lt;/code&gt;). Every session, same order, same commands.&lt;/p&gt;
&lt;p&gt;The SSH key comment says it all: &lt;code&gt;mdrfckr&lt;/code&gt;. This is the &lt;strong&gt;Outlaw botnet&lt;/strong&gt; (also known as Dita), a well-documented cryptomining operation linked to Romanian cybercriminals. The same SSH public key was first observed on VirusTotal on July 5, 2018. Eight years later, it’s still being planted on compromised servers.&lt;/p&gt;
&lt;p&gt;I captured 155 intrusion sessions from this botnet across the 48-hour window, originating from 10+ unique IPs across the United States, France, Hungary, China, and the Seychelles. Every session used the same SSH key, the same command sequence, and a unique randomly-generated password for each compromised host.&lt;/p&gt;
&lt;p&gt;The playbook breaks down like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Remove immutable flags from &lt;code&gt;.ssh&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;chattr -ia&lt;/code&gt;). Undoes any file protection a previous administrator set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nuke and replace SSH keys.&lt;/strong&gt; Deletes all existing authorized keys and plants their own, locking out the legitimate owner and any other attacker who previously planted keys.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Change the root password to a random string.&lt;/strong&gt; Each session uses a different password (&lt;code&gt;K3LZwFN3e1vq&lt;/code&gt;, &lt;code&gt;PLpL9jEf2t3p&lt;/code&gt;, &lt;code&gt;DoEizj7TZjn7&lt;/code&gt;, etc.). This prevents other botnets using the same leaked credential list from getting back in.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kill competing malware.&lt;/strong&gt; &lt;code&gt;pkill -9 secure.sh; pkill -9 auth.sh&lt;/code&gt; terminates common persistence scripts used by rival botnets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blank &lt;code&gt;hosts.deny&lt;/code&gt;.&lt;/strong&gt; Removes IP-based access controls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full hardware recon.&lt;/strong&gt; CPU model, core count, RAM, disk space, architecture. This determines whether the box is worth deploying a miner on and which binary to use.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The competing-malware-kill step is worth noting. The threat model for this botnet isn’t the system administrator discovering the compromise. It’s another botnet stealing the compute. Every compromised server is contested territory, and the first attacker to change the locks wins. The playbook dedicates more steps to locking out other botnets than to evading detection.&lt;/p&gt;
&lt;p&gt;A previous researcher documented this botnet in October 2022, finding 12,913 unique IPs across 152 countries over a two-month period. In 2022, the botnet used &lt;code&gt;SSH-2.0-libssh-0.6.3&lt;/code&gt;. My honeypot observed &lt;code&gt;SSH-2.0-libssh_0.11.1&lt;/code&gt;. They’ve upgraded the SSH library while keeping the exact same SSH key and command sequence for eight years.&lt;/p&gt;
&lt;h2 id=&quot;campaign-2-solana-validator-hunters&quot;&gt;Campaign 2: Solana validator hunters&lt;/h2&gt;
&lt;p&gt;The second-most-active campaign was specifically targeting Solana blockchain validator nodes. Hetzner has historically hosted a large fraction of Solana’s validator infrastructure, to the point where Solana’s geographic concentration on Hetzner was considered a decentralization risk for the network.&lt;/p&gt;
&lt;p&gt;The credential pairs tell the story: &lt;code&gt;solana/solana&lt;/code&gt; (141 attempts), &lt;code&gt;sol/sol&lt;/code&gt; (129), &lt;code&gt;solv/solv&lt;/code&gt; (115), &lt;code&gt;sol/123&lt;/code&gt; (95), &lt;code&gt;solv/123456&lt;/code&gt; (95), &lt;code&gt;sol/solana&lt;/code&gt; (70), &lt;code&gt;solana/sol&lt;/code&gt; (64), &lt;code&gt;solv/12345678&lt;/code&gt; (63), &lt;code&gt;node/node&lt;/code&gt; (45), &lt;code&gt;solana/solana123&lt;/code&gt; (44).&lt;/p&gt;
&lt;p&gt;The usernames aren’t random. &lt;code&gt;solana&lt;/code&gt;, &lt;code&gt;sol&lt;/code&gt;, &lt;code&gt;solv&lt;/code&gt;, and &lt;code&gt;node&lt;/code&gt; are common naming conventions for Solana validator operators. &lt;code&gt;helius&lt;/code&gt; (a Solana RPC provider) and &lt;code&gt;firedancer&lt;/code&gt; (Jump Crypto’s validator client) also appeared in the credential lists.&lt;/p&gt;
&lt;p&gt;Every successful Solana-targeting session ran exactly one command: &lt;code&gt;/bin/./uname -s -v -n -r -m&lt;/code&gt;. The unusual &lt;code&gt;/bin/./&lt;/code&gt; path prefix (using a redundant &lt;code&gt;./&lt;/code&gt;) is likely an evasion technique against simple command logging that watches for &lt;code&gt;/bin/uname&lt;/code&gt; or just &lt;code&gt;uname&lt;/code&gt;. All sessions came from IP ranges in Bulgaria (&lt;code&gt;195.178.110.x&lt;/code&gt;, Techoff Srv Limited), the Netherlands (&lt;code&gt;2.57.122.x&lt;/code&gt;), and a separate cluster (&lt;code&gt;92.118.39.x&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;The objective here is straightforward: Solana validators hold keypair files on disk that control staked tokens. A typical validator might have hundreds of thousands of dollars in staked SOL. SSH access to a validator node means access to the keypairs, which means draining the stake.&lt;/p&gt;
&lt;h2 id=&quot;campaign-3-wannacry-still-going&quot;&gt;Campaign 3: WannaCry, still going&lt;/h2&gt;
&lt;p&gt;This was the surprise.&lt;/p&gt;
&lt;p&gt;Dionaea, the malware-capturing honeypot on port 445 (SMB), collected 16 binary samples over 48 hours. Every single one was 5,267,459 bytes, a PE32 DLL compiled for x86 Windows. The compile timestamp in the PE header: May 11, 2017.&lt;/p&gt;
&lt;p&gt;Strings analysis turned up the kill switch URL:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwff.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;WannaCry. Nine years old and still propagating.&lt;/p&gt;
&lt;p&gt;For anyone unfamiliar: this is the ransomware attributed to North Korea’s Lazarus Group that tore through the world in May 2017, spreading via EternalBlue (MS17-010), an SMB exploit developed by the NSA and leaked by the Shadow Brokers. It’s a worm, so it self-propagates without human interaction. Marcus Hutchins famously halted the ransomware payload by registering the kill switch domain above on May 12, 2017. The domain is still registered, but now it redirects through affiliate links to… Kohl’s department store. Every zombie machine checking the kill switch is generating impressions for someone’s retail affiliate account.&lt;/p&gt;
&lt;p&gt;The infected machines hitting my honeypot are almost certainly IoT devices, embedded systems, or neglected servers that were compromised in 2017 and have been scanning the internet continuously ever since. Nobody has cleaned them. They just keep going.&lt;/p&gt;
&lt;h2 id=&quot;campaign-4-phpunit-remote-code-execution&quot;&gt;Campaign 4: PHPUnit remote code execution&lt;/h2&gt;
&lt;p&gt;Tanner, the web application honeypot, logged 789 requests probing 589 unique URL paths. The dominant pattern was systematic scanning for &lt;code&gt;eval-stdin.php&lt;/code&gt;, a known vulnerability in PHPUnit (CVE-2017-9841) that allows remote code execution. The scanner tried every common web application directory as a prefix to the same path (&lt;code&gt;/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php&lt;/code&gt;): &lt;code&gt;laravel/&lt;/code&gt;, &lt;code&gt;yii/&lt;/code&gt;, &lt;code&gt;zend/&lt;/code&gt;, &lt;code&gt;cms/&lt;/code&gt;, &lt;code&gt;api/&lt;/code&gt;, &lt;code&gt;demo/&lt;/code&gt;, &lt;code&gt;crm/&lt;/code&gt;, &lt;code&gt;admin/&lt;/code&gt;, &lt;code&gt;blog/&lt;/code&gt;, &lt;code&gt;public/&lt;/code&gt;, &lt;code&gt;tests/&lt;/code&gt;, and dozens more. Automated webshell planting. Find the vulnerable endpoint, upload a PHP shell, establish persistence.&lt;/p&gt;
&lt;h2 id=&quot;campaign-5-android-debug-bridge&quot;&gt;Campaign 5: Android Debug Bridge&lt;/h2&gt;
&lt;p&gt;ADBHoney captured an attempt to compromise the server via Android Debug Bridge (port 5555). The command created a hidden directory in &lt;code&gt;/data/local/tmp&lt;/code&gt; and tried four different download methods in sequence (&lt;code&gt;wget&lt;/code&gt;, &lt;code&gt;busybox wget&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;toybox wget&lt;/code&gt;) to pull an ARM7 binary called &lt;code&gt;parm7&lt;/code&gt; from a remote server at &lt;code&gt;196.251.107.133&lt;/code&gt;. The fallback chain exists because IoT devices running Android have inconsistent tooling installed. The binary name indicates it’s compiled for ARMv7, the most common architecture in Android phones, tablets, IP cameras, and smart TVs. IoT botnet recruitment.&lt;/p&gt;
&lt;h2 id=&quot;what-didnt-happen&quot;&gt;What didn’t happen&lt;/h2&gt;
&lt;p&gt;No one discovered the employee portal’s credential chain. The Cedar Creek MWA login page was visited by scanners and indexed by Censys, but no attacker attempted to log in with credentials harvested from the AD export in &lt;code&gt;/owa/&lt;/code&gt;. The multi-stage attack chain went completely untested. This isn’t surprising for a 48-hour window dominated by automated botnets. Targeted human attackers operating on ICS-specific intelligence would need more time to discover and investigate the portal.&lt;/p&gt;
&lt;p&gt;No attacker interacted with the SCADA theming in Cowrie’s SSH either. The fake filesystem with Schneider Electric directories, Modbus register maps, and SCADA event logs went unexplored. Every successful Cowrie session ran the same automated recon scripts. None of the attackers typed &lt;code&gt;ls&lt;/code&gt; and looked around at what kind of system they’d compromised. The mdrfckr botnet treats every compromised server identically regardless of what’s on it.&lt;/p&gt;
&lt;h2 id=&quot;so-what&quot;&gt;So what&lt;/h2&gt;
&lt;p&gt;The main thing I took away from this is how deeply impersonal internet-facing attacks are. 47,771 events and not one of them was about Cedar Creek Municipal Water Authority. Nobody cared that this was themed as a water plant. Nobody explored the SCADA directories. The bots don’t read. They sweep the Hetzner IP range (and the rest of the IPv4 space) with automated tools, and my server happened to be on a routable address.&lt;/p&gt;
&lt;p&gt;The other thing that stuck with me is how old everything is. WannaCry is from 2017 and still propagating. The mdrfckr SSH key has been active since 2018. CVE-2017-9841 is being scanned for in 2026. The internet is full of stuff that just keeps running because nobody has bothered to turn it off, attacking other stuff that just keeps running because nobody has bothered to patch it. It’s less of a war zone and more of an abandoned parking lot where someone left a bunch of Roombas on.&lt;/p&gt;
&lt;p&gt;The whole project cost about $3.50 in Hetzner compute. Fun times.&lt;/p&gt;</content:encoded><category>honeypot</category><category>scada</category><category>malware</category><category>ics</category><category>modbus</category></item><item><title>CVE-2026-6994: Envoy Query Parameter Injection via header_mutation</title><link>https://linefeed.sh/research/cve-2026-6994/</link><guid isPermaLink="true">https://linefeed.sh/research/cve-2026-6994/</guid><description>Envoy&apos;s header_mutation filter inserts header values into query strings without URL encoding, enabling arbitrary query-parameter injection — auth bypass, SQLi/XSS on upstream services. Affects v1.33.0+.</description><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;header_mutation&lt;/code&gt; filter’s &lt;code&gt;query_parameter_mutations&lt;/code&gt; feature inserts values from formatters (e.g. &lt;code&gt;%REQ(header)%&lt;/code&gt;) into query strings without URL encoding. The encoding helper (&lt;code&gt;PercentEncoding::urlEncode()&lt;/code&gt;) exists in the codebase, but this code path doesn’t call it.&lt;/p&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;/h2&gt;
&lt;p&gt;An attacker sets a header containing URL metacharacters:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;X-Inject: alice&amp;#x26;admin=true&amp;#x26;sql=1&apos;OR&apos;1&apos;=&apos;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Envoy copies the header value verbatim into the upstream request’s query string:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;/api?user=alice&amp;#x26;admin=true&amp;#x26;sql=1&apos;OR&apos;1&apos;=&apos;1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;root-cause&quot;&gt;Root cause&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;params.add()&lt;/code&gt; at &lt;code&gt;header_mutation.cc:22&lt;/code&gt; and &lt;code&gt;toString()&lt;/code&gt; at &lt;code&gt;utility.cc:1156&lt;/code&gt; output raw values. Other Envoy filters (OAuth2, gRPC transcoder) correctly use &lt;code&gt;urlEncode()&lt;/code&gt; for the same operation — this filter just didn’t.&lt;/p&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVSS:&lt;/strong&gt; 6.3&lt;/li&gt;
&lt;li&gt;Arbitrary query-parameter injection&lt;/li&gt;
&lt;li&gt;Authorization bypass when upstream services trust query parameters&lt;/li&gt;
&lt;li&gt;Enables SQLi / XSS / parameter smuggling against upstream services&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Affects:&lt;/strong&gt; v1.33.0+&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;discovery&quot;&gt;Discovery&lt;/h2&gt;
&lt;p&gt;Code review of Envoy’s &lt;code&gt;header_mutation&lt;/code&gt; filter and &lt;code&gt;query_parameter_mutations&lt;/code&gt; path. Confirmed end-to-end against a running Envoy instance.&lt;/p&gt;
&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;
&lt;p&gt;Fixed in PR #43502. CVE assigned.&lt;/p&gt;</content:encoded><category>envoy</category><category>injection</category><category>http</category><category>filter</category></item><item><title>CVE-2026-31360: Traefik SPIFFE Trust Domain Bypass</title><link>https://linefeed.sh/research/cve-2026-31360/</link><guid isPermaLink="true">https://linefeed.sh/research/cve-2026-31360/</guid><description>Traefik&apos;s verifyServerCertMatchesURI overwrites the expected SPIFFE URI&apos;s host with the certificate&apos;s actual host before comparison, defeating trust-domain validation.</description><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Traefik’s &lt;code&gt;verifyServerCertMatchesURI&lt;/code&gt; overwrites the expected SPIFFE URI’s host with the certificate’s actual host before comparison, defeating trust-domain validation entirely. Any valid certificate from a shared CA pool passes validation regardless of which trust domain issued it.&lt;/p&gt;
&lt;h2 id=&quot;secondary-finding&quot;&gt;Secondary finding&lt;/h2&gt;
&lt;p&gt;While verifying impact in real deployments, I also discovered that Consul Connect was generating SPIFFE URIs without trust domains. That makes trust-domain isolation non-functional for the entire Consul Connect user base, independently of the Traefik bug.&lt;/p&gt;
&lt;h2 id=&quot;discovery&quot;&gt;Discovery&lt;/h2&gt;
&lt;p&gt;Code review of Traefik’s mTLS implementation and SPIFFE URI parsing. The relevant function constructs the comparison target by mutating the expected URI in place.&lt;/p&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVSS:&lt;/strong&gt; 8.2 (High)&lt;/li&gt;
&lt;li&gt;Cross-trust-domain service impersonation in zero-trust architectures using SPIRE or Consul Connect.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;
&lt;p&gt;Patched. CVE assigned by MITRE.&lt;/p&gt;</content:encoded><category>traefik</category><category>spiffe</category><category>mtls</category><category>zero-trust</category><category>spire</category><category>consul</category></item><item><title>CVE-2026-31361: Traefik ACME Private Key Exposure via Logs</title><link>https://linefeed.sh/research/cve-2026-31361/</link><guid isPermaLink="true">https://linefeed.sh/research/cve-2026-31361/</guid><description>GetPrivateKey() in Traefik&apos;s ACME path logs the entire DER-encoded private key as decimal bytes when parsing fails. A 5-year regression of a partial v1.7.20 fix that was never ported to v2.x or v3.x.</description><pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;When the ACME private key fails to parse, &lt;code&gt;GetPrivateKey()&lt;/code&gt; (&lt;code&gt;account.go:60-61&lt;/code&gt;) logs the entire DER-encoded key as a slice of decimal bytes via the &lt;code&gt;%+v&lt;/code&gt; format string:&lt;/p&gt;
&lt;pre class=&quot;astro-code one-dark-pro&quot; style=&quot;background-color:#282c34;color:#abb2bf; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Cannot unmarshal private key [48 130 9 ...]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The key material flows to stdout, log files, and any connected log aggregator (Splunk, ELK, CloudWatch, Datadog).&lt;/p&gt;
&lt;h2 id=&quot;why-it-matters&quot;&gt;Why it matters&lt;/h2&gt;
&lt;p&gt;This converts narrow file-storage access (&lt;code&gt;acme.json&lt;/code&gt;, &lt;code&gt;0600&lt;/code&gt; permissions, single host) into broad exposure across logging infrastructure that ops teams routinely access and that retains data for years.&lt;/p&gt;
&lt;h2 id=&quot;history&quot;&gt;History&lt;/h2&gt;
&lt;p&gt;A partial fix existed in v1.7.20 (truncating to 16 bytes) but was never ported forward to v2.x or v3.x. Five years of regression.&lt;/p&gt;
&lt;h2 id=&quot;discovery&quot;&gt;Discovery&lt;/h2&gt;
&lt;p&gt;Code review of Traefik’s ACME certificate-storage error-handling paths.&lt;/p&gt;
&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;
&lt;p&gt;Patched. CVE assigned by MITRE.&lt;/p&gt;</content:encoded><category>traefik</category><category>acme</category><category>key-exposure</category><category>logging</category></item><item><title>CVE-2026-33413: etcd Authorization Bypass Across Multiple APIs</title><link>https://linefeed.sh/research/cve-2026-33413/</link><guid isPermaLink="true">https://linefeed.sh/research/cve-2026-33413/</guid><description>Multiple etcd APIs reachable without authorization: MemberList (cluster topology), Alarm, Lease APIs, and compaction. CVSS 8.8.</description><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;Several etcd APIs did not consult the auth middleware before serving requests. Unauthorized callers could:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;enumerate cluster topology via &lt;code&gt;MemberList&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;trigger or clear alarms (operational disruption)&lt;/li&gt;
&lt;li&gt;interact with the Lease APIs, interfering with TTL-based keys&lt;/li&gt;
&lt;li&gt;initiate compaction, permanently removing historical revisions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;discovery&quot;&gt;Discovery&lt;/h2&gt;
&lt;p&gt;Systematic review of etcd’s auth middleware and gRPC API layer. Cross-referenced every gRPC method against the set of methods that go through authorization, and looked at the gaps.&lt;/p&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVSS:&lt;/strong&gt; 8.8&lt;/li&gt;
&lt;li&gt;An unauthenticated attacker with network reach to the etcd port can exfiltrate cluster topology and disrupt the cluster.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;note-on-kubernetes&quot;&gt;Note on Kubernetes&lt;/h2&gt;
&lt;p&gt;Kubernetes is &lt;strong&gt;not&lt;/strong&gt; affected. The Kubernetes API server performs authorization itself and does not rely on etcd’s built-in auth.&lt;/p&gt;
&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;
&lt;p&gt;Patched in etcd 3.6.9, 3.5.28, 3.4.42. Credited in the SIG-etcd security release.&lt;/p&gt;</content:encoded><category>etcd</category><category>kubernetes</category><category>authorization</category><category>grpc</category></item><item><title>CVE-2026-33343: etcd Nested Transactions Bypass RBAC</title><link>https://linefeed.sh/research/cve-2026-33343/</link><guid isPermaLink="true">https://linefeed.sh/research/cve-2026-33343/</guid><description>An authenticated user with restricted key-range permissions can use nested transactions to access the entire etcd data store, bypassing RBAC entirely.</description><pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;etcd evaluates transactions recursively. When a transaction’s body contains nested transactions, the inner operations were not re-checked against the caller’s RBAC permissions. An authenticated user with restricted key-range permissions could use a nested transaction to read or modify keys outside their permitted range — the entire data store, in practice.&lt;/p&gt;
&lt;h2 id=&quot;discovery&quot;&gt;Discovery&lt;/h2&gt;
&lt;p&gt;Code review of etcd’s transaction evaluator while looking at the auth surface. The outer call enforced authorization on the keys it touched; inner operations executed under the parent’s authorization context without re-checking.&lt;/p&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CVSS:&lt;/strong&gt; 6.5&lt;/li&gt;
&lt;li&gt;Any authenticated user with any key-range permission can escape the range constraint.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;note-on-kubernetes&quot;&gt;Note on Kubernetes&lt;/h2&gt;
&lt;p&gt;As with CVE-2026-33413, Kubernetes is not affected — the API server enforces authorization above etcd.&lt;/p&gt;
&lt;h2 id=&quot;status&quot;&gt;Status&lt;/h2&gt;
&lt;p&gt;Patched in etcd 3.6.9, 3.5.28, 3.4.42. Credited in the SIG-etcd security release.&lt;/p&gt;</content:encoded><category>etcd</category><category>kubernetes</category><category>rbac</category><category>authorization</category></item></channel></rss>