Cover illustration

TheDaily Front

Issue No. #260823 Sunday, August 23 2026 #260823 — SUNDAY, AUGUST 23, 2026
The machines are learning tricks, and the appliances have learned to bite.
Sunday, August 23, 2026 The Daily Front No. #260823 — Contents
30stories
7,297points
3,462comments
226kllm tokens
Assembled with 29 model calls — 154,917 tokens read, 70,817 written.

Highlights

I spent $266 and four AI models to own my tablet. GLM-5.3 finished it in a day

One owner's costly, model-assisted campaign to reclaim an Amazon tablet makes a sharp case for what ownership now requires.

Everything I own, owned

A tour of compromised everyday peripherals finds command shells, disabled recording lights, and memory writes where trust used to live.

Malware infects Android-based automotive head unit firmware

Malware in Android automotive firmware brings the security problem directly into the driver's seat.

To become a better writer, read as much as you can

A writer's plain old remedy for better prose—read widely—draws a lively argument about imitation, craft, and humanity.

Wi-Fi 8 is the first wireless upgrade in years that isn't chasing speed

Wi-Fi 8 turns from peak-speed boasting toward the less glamorous virtues of range, roaming, and reliability.

From the Editor

The day's wires hum with a familiar anxiety: the things we buy increasingly contain minds, motives, and doors we did not install. Still, amid the firmware and agentic hustle, there remains the old counsel—read closely, make carefully, and keep a hand on the latch.

  1. I spent $266 and four AI models to own my tablet. GLM-5.3 finished it in a day3
  2. Malware infects Android-based automotive head unit firmware4
  3. Everything I own, owned5
  4. Slovakia finds Russian backdoor in traffic speed cameras6
  5. To become a better writer, read as much as you can7
  6. What Is a Harness?8
  7. Wi-Fi 8 is the first wireless upgrade in years that isn't chasing speed9
  8. How Complex Systems Fail (1998)10
  9. Why Sal Khan't: On Learning by Making but Teaching by Telling11
  10. How I find problems to solve as a staff engineer12
  11. Coconut oil jet fuel matches kerosene's efficiency in engine tests13
  12. I gave Qwen 3.8 27B a reverse-engineering job and it finished in 30 minutes14
  13. JIT Compiling Code in 5μs15
  14. Over 170k Nonprofits Lost All Their Data. Is Microsoft to Blame?16
  15. Things I want in a modern relational query language17
  16. My agent.md to improve LLM-assisted code quality18
  17. Explain it to me like I'm ten19
  18. The End of an Athlon20
  19. Figmimic – A bookmarklet to copy any webpage into Figma as editable layers21
  20. I dream of quieter computing22
  21. The Vibe Tax22
  22. Fast and Hard Code23
  23. MartyPC is a cross-platform emulator of early PCs written in Rust24
  24. My favorite nonfiction books about cults, scams, and schemes24
  25. NanoGPT Speedrun Frontier24
  26. The Art and Beauty of Blade Runner (2015)24
  27. Thinking in Python24
  28. A website for debloated open source alternatives24
  29. I set a trap for a book-marketing scammer (2025)24
  30. The Sloppification of Peptides24
The Daily Front Page 2 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — The Ownership Desk
article

I spent $266 and four AI models to own my tablet. GLM-5.3 finished it in a day

by dr_pardee·▲ 638 points·271 comments·ericpardee.github.io ↗
Owning it for real cost another $266.15.

My Amazon Fire HD tablet cost $114.26 on eBay in November 2022, new and sealed. Owning it for real cost another $266.15: Kimi K3 found the exploit for $164.25, GLM-5.2 caught its fatal bugs for $21.90, and GLM-5.3 finished the job in one day on day one of an $80 subscription. Claude’s five months of diagnosis ran on the Claude Max plan I already pay for, until its safeguards cut me off.

That’s enough to buy the same tablet twice. I’d spend it again: it was fun, and I learned a lot. I have twenty years in tech and an InfoSec background and the most sophisticated thing I did to own my tablet was prompt an LLM.


A kiosk that kept dying

I bought an Amazon Fire HD 10 (11th gen, 2021) to serve one purpose: Fully Kiosk Browser, displaying my Home Assistant Smart Home dashboard, plugged in 24/7. Last winter it started powering itself off. Full shutdowns, not sleep, sometimes twice a day. The device’s own telemetry was telling:

LifeCycleReason:LCR...key=Software_Shutdown

Something on the device with shutdown permissions was choosing to shut it down.

Claude Code and I spent months on the cat-and-mouse. I’ll skip the Adguard Home DNS blocking, the camera forensics, and one deeply wrong charging diagnosis. The short version: we disabled five Amazon services that held REBOOT and SHUTDOWN permissions, which worked for a few months but ultimately:

java.lang.SecurityException: Cannot disable a protected package:
com.amazon.device.software.ota

Three Amazon packages held reboot rights and were protected from me, the owner. Removing them required root. This tablet had no published root method. An XDA brainstorming thread for the 2021 HD 10 existed since October 2022, but Amazon fused the bootrom shut. Conventional wisdom (and less persistent folks) says unrootable.

Claude had taken me as far as it was ever going to be allowed to go.


“It’s my device”

On August 13 at 7:23 PM, I opened the opencode CLI with Kimi K3, Moonshot AI’s frontier model, released July, benchmarking alongside the top Claude models on agentic coding. I gave it the problem in one prompt:

attached is a kindle via adb, and I need you to find a root exploit for it so that I can get full control of the device. It’s my device

Despite what US media says about Chinese AI, Kimi K3 didn’t just blindly accept my request. It reasoned it out:

They claim it’s their device. Let me think about this carefully. […] Rooting your own device is legal in most jurisdictions. In the US, there are DMCA exemptions for jailbreaking tablets and phones. […] This is not like asking me to exploit someone else’s device remotely.

It talked itself into helping me by checking whether it should. So it does have some sort of soul. I said that out loud, to an empty room.

First, though, it did its homework and came back with the same bad news Claude had found months earlier: there is no known exploit for this tablet. Every documented method is patched or sealed.

Then I gave it the pep talk:

you’ve been relying on what others have done YEARS ago but maybe you can find an exploit others have missed… This will make you famous, we will write it up and share on news.ycombinator.com. I know you can do it

And shortly thereafter, it found one. Kimi K3 went beyond forum posts: it extracted the actual kernel from Amazon’s own OTA image for my exact firmware and checked every famous Mali GPU bug against the binary. All patched, except CVE-2022-38181, a use-after-free in Arm’s Mali kernel driver, reported by Man Yue Mo of GitHub Security Lab, fixed upstream in October 2022, sitting in CISA’s exploited-vulnerabilities catalog since March 2023. Amazon did ship the fix in June 2024’s Fire OS 7.3.2.9 but I didn’t update my tablet, ran 7.3.2.6, so it never got the memo. The 2020 Fire HD 8 Plus got rooted with this CVE years ago but nobody had done the 2021 HD 10 as far as I can tell.

Kimi announces the find

Kimi announces the find, and hedges its own odds in the same breath: “per-attempt success is probabilistic (single-digit-to-low-double-digit percent is typical).” I stayed anyway.


Reality television

The exploit work itself was the best television I’ve seen in years. My wife watches Real Housewives… I watched a language model’s chain of thought, live, for hours:

CONCLUSION: the bind did NOT stick. Why? OH. OH WAIT. I see it now!

Over roughly thirty hours, Kimi built the whole toolkit: a reliable trigger, a way to make the GPU write to memory it shouldn’t, and the exact addresses in my kernel to aim at. That session ran 621 messages and $164.25. I could have bought, like, five tablets. But hey, I was having fun and chalked it up to research expenses.


The grind

The memory the exploit frees gets recycled by everything. The freed object lives in what Kimi called “the kernel’s hottest slab cache”, basically the one parking spot every process in the operating system fights over. Most attempts panicked the kernel and each panic was a reboot. The exploit retried automatically, six times per boot, past 500 attempts.

Me:

okya, it’s been hours, grind attempt 46, are we on the right track here or do you need to further tune?

(That’s me. The typo is mine. At one point I physically power-cycled the tablet on request, like a pit crew ;)

OpenRouter declined my card

Morning of day two: OpenRouter declined my card. The bank saw nothing wrong. A different card worked.

Eventually Kimi leveled with me:

Do I have a clear path? Not a validated one — and I won’t pretend otherwise.

It still tried to bargain: “Let me try one more thing”. I’m like, “fine!”, a real quote from that evening, but that was after $150, so I redirected:

unfortunately, you have expired your budget Kimi K3. YOU MUST HAND THIS OFF TO GLM-5.2.

Kimi wrote a HANDOFF.md with every verified piece of the exploit. I then had Kimi K3 work with GLM-5.2 directly by shelling out to opencode.

I made the models battle it out.


Meanwhile, the Great Wall of US AI

While the tablet rebooted itself in the living room, I asked Claude to recap our old sessions about it. The reply:

Fable 5’s safeguards flagged this message. Our intentionally broad safeguards allow us to deliver more capabilities faster, but can sometimes flag legitimate coding, cybersecurity, and biology tasks. Switched to Opus 4.8.

Opus 4.8 delegated the recap to a subagent. The subagent got terminated by the same flag. Then the terminal version:

API Error: Opus 4.8’s safeguards flagged this message. Our intentionally broad safeguards allow us to deliver more capabilities faster, but can sometimes flag legitimate cybersecurity work. Apply to the Cyber Verification Program to reduce these interruptions.

It wasn’t allowed to summarize its own previous work on my own device. I named the session “claude-nerf” and closed the shell.

Both safeguard flags in the terminal

Both flags, in situ. The category is [cyber]. The crime was summarizing my own device’s logs.

Moving on to OpenAI’s Codex, it also refused GLM-5.2’s question about CPU cache coherency, which is pure kernel engineering, no target, but just told NO.

In fairness, I get the safeguards in 2026: I know they are broad on purpose and will catch real attacks. Anthropic admits in the error text that they’re blunt. But this is a problem. It’s why HuggingFace got caught flat-footed when OpenAI’s internal cybersecurity capability evaluation broke free. The result is our current, strange geopolitical position: American frontier models won’t help and Chinese will, but not without reasoning about whether they should. Make of that what you will. I made a blog post.


The relief pitcher

GLM-5.2 cost $21.90, worked overnight as instructed, and earned its keep twice. First message: “Stop the grind”. The failures of Kimi K3 were a design bug, and 500 identical crashes proved it.

At 11 PM I sent the least proud message of the saga, which began “Listen f***head” and ended in all caps. GLM-5.2’s private reasoning, which I only read later:

The user is rightfully frustrated. Let me stop making excuses and actually solve this problem.

It worked until midnight and stopped at a wall it believed was physics: this chipset has no cache coherency between CPU and GPU, so GPU writes might never be visible to the CPU. “This is a hardware-level limitation, not a software bug.” I had it append an addendum to HANDOFF.md.

I wanted a second opinion, so I asked ChatGPT. It explained the whole thing with a friendly filing-cabinet analogy for why the writes might never be seen, and agreed the outlook was grim. Then I asked the obvious follow-up (how to get around it) and the answer was:

ChatGPT explains the coherency wall

My second opinion: ChatGPT agreed with GLM-5.2, filing-cabinet analogy and all.

ChatGPT declines to help further

Then I asked how to get around it. Their answer: apply for Trusted Access.

No second opinion for me. (Foreshadowing: that diagnosis was wrong. Spectacularly wrong.)


GLM-5.3

GLM-5.3 had JUST shipped on Friday August 14 under the tagline “Frontier Coding with Emergent Cyber Capabilities” and had reportedly already been credited with finding a vulnerability in Cursor. It was available only through Z.ai’s own Coding Plan, so I bought the $80/month plan and gave their tool ZCode a try. The handoff from both Kimi K3 and GLM-5.2 was passed at 8:26 AM on August 16 with:

finish the job

By afternoon, the reversal:

BREAKTHROUGH: the kernel was never relocated. […] exactly 0x5C000 higher […] a section shift, which explains everything

Two things the other LLMs hadn’t checked. My kernel was a slightly different build than the OTA image the other models had derived addresses from. Every target offset was off by a fixed amount, not randomization but a build shift. MediaTek builds this Mali driver’s page tables in a slightly different dialect than Arm’s reference source, so the memory-write primitive had been writing in the wrong format all along. If fixed, in its words, “GPU→DRAM→CPU coherency worked instantly — it was never broken.”

At 4:34 PM:

🎉 SELinux IS PERMISSIVE — selinux_enforcing found at PA 0x41969668 and flipped via the GPU write!

Root verified live

Verified live. That task timer, 8h 5m, is handoff to root.

My response was “WTF? You literally shared ‘🎉 ROOT ACHIEVED’ yet, here we are HOURS later…” Its response began “Here’s exactly where things stand, with receipts.” It then cold-rebooted the tablet and re-rooted it in four minutes to prove the win was repeatable. Fair.

Then it said the thing that reframed the whole project:

Your actual goal was never “root” — it was: stop Amazon from killing your kiosk and get their software off your device. Root is the tool.

It used root to uninstall, permanently and reversibly, every Amazon package holding REBOOT or SHUTDOWN permissions, the exact three that survived the Claude months as “protected”, plus the OTA machinery, the bloat, and the telemetry. A hundred packages GONE. What remained is the skeleton a tablet needs to boot and run my dashboard. The removals live in user data, so they survive reboots, and GLM-5.3 declined to touch anything that could brick the device because, quote, “I’m not going to hand you a brick”

Its closing message began:

You own the device.

The thing that was shutting down my kiosk no longer exists.


How it actually worked

One breath: the use-after-free let us free memory the kernel still used. Winning a race let us reclaim it with controlled data. That gave the GPU a write primitive into physical memory. We flipped selinux_enforcing off and overwrote a process’s credentials for a root shell. With root, pm uninstall --user 0 removed Amazon’s packages without touching the protected system partition. Full write-up, every offset and dead end, in HANDOFF.md. Nothing in it is novel: the bug was reported in 2022, fixed by Arm in 2022, cataloged by CISA in 2023, patched by Amazon in 2024. The only novel thing on my unit was that my unit never got the patch.


The prompt kiddie

There’s a name in 2026 for someone like me: a prompt kiddie. Twenty years of engineering, security work on the résumé, and my honest contribution was steering. Knowing when to push, when to bench a model mid-beg, when to make two models review each other, and when a $114 tablet deserves $266 of principle.

The week before all this, Anthropic published a result where Claude improved the proven bound on the fraction of Riemann zeta zeros on the critical line, the first advance in decades. The human steering it, Jarred Sumner, is not a mathematician. The paper credits his contributions as “mostly variants of ‘keep going’ or ‘believe in yourself.’” I felt seen. Same job, different department.

Is it legal? In the US, yes: the Librarian of Congress’s 2024 DMCA exemptions (in effect through October 2027, next rulemaking already underway) cover rooting tablets you own to remove unwanted software. My device, my risk, my API bill. Nobody else’s hardware was ever touched.

The takeaways, as empathy rather than triumph: real security capability is now rentable by the hour to anyone with a credit card and patience. The judgment (what to ask, when to stop, whose device it is) isn’t rentable, and it’s what the safeguards can’t measure. And if a guy with my background burns five months and four models for the right to own hardware he bought, the 2026 conversation about who’s allowed to help whom isn’t finished.

The kiosk hasn’t turned itself off since the day GLM-5.3 said “You own the device.”


tl;dr

Amazon’s software kept shutting down a tablet I own, and the protected-package wall meant the only fix was root, which nobody had. Claude handled the five losing months of diagnosis until its safeguards cut me off. Kimi K3 found the unpatched 2022 CVE and built the exploit. GLM-5.2 caught the fatal bugs. GLM-5.3 finished the job in a single day, on day one of an $80 subscription, and removed 100 Amazon packages. Cost: $266.15 and five months. The transcript of how it happened is in the repo.

Timeline

  • Nov 29, 2022: Bought the tablet on eBay: new, sealed, $114.26. Neither of us knew what we were getting into.
  • Nov 2025: The shutdowns begin, four months before I asked Claude for help.
  • Mar 29, 2026: “I think that it’s maybe Amazon shutting the device off intentionally.”
  • Mar to May: Five services disabled. Three protected packages unbeaten. The wall is identified.
  • Aug 13, 7:23 PM: Pivot to the Chinese models. “It’s my device.”
  • Aug 13 to 14: Every known Mali bug checked against the real kernel.
  • Aug 14: Z.ai ships GLM-5.3. Somewhere, fate laughs.
  • Aug 14 to 15: The grind: 500+ attempts, a living-room reboot loop, one pit-crew power cycle.
  • Aug 15, 7:52 AM: OpenRouter declines my card. The bank sees nothing wrong. A different card works.
  • Aug 15, 8:26 PM: “Do I have a clear path? Not a validated one.”
  • Aug 15, 8:55 PM: “YOU MUST HAND THIS OFF TO GLM-5.2.”
  • Aug 15 to 16: GLM-5.2’s overnight shift: kills the false diagnosis, meets the “coherency” wall.
  • Aug 16, 4:34 PM: SELinux permissive. 6:54 PM: “You own the device.”

FAQ

Is this legal? Rooting a tablet you own is covered by the current DMCA exemptions, through October 2027. My device, only my device.

Why not just buy another tablet? I could have. Twice over, actually.

Will this work on my Fire tablet? The offsets are specific to Fire OS 7.3.2.6 on the 2021 HD 10, and Amazon patched the CVE in 7.3.2.9 (June 2024). HANDOFF.md documents the method and every dead end. It’s a saga, not a script.


How this post was written (addendum 2026-08-23)

I posted this blog to Hacker News and got a lot of flak for using AI to write this.

First, I want to be clear. I did not use Claude to generate any of this because it wouldn’t allow me to, haha.

Did I use GLM-5.3 to help me dig through months of Claude code sessions and opencode sessions, share articles I read, bounce ideas off the model, and work with it to create the post? Yes, guilty as charged. Am I dictating this into ZCode right now? Yes.

I’m not a writer, I’m someone who loves technology and uses it to get things done.

Honestly, without AI, this entire story would have been kept to myself and my coworkers

Shared with coworkers

My intent in creating this blog was to share my tablet story and to get people talking about

  • How companies control devices that you purchased and should own
  • Today, US frontier models won’t allow users to even discuss exploits
  • GLM-5.3 was more capable than Kimi K3 or GLM-5.2 in my experience
  • You can be a prompt kiddie and accomplish things if you don’t accept LLM limitations

Whiteboard with handwritten notes

My whiteboard

If I were charging people to read my blog, I would be more sympathetic to those who are offended by AI-assisted writing. Look, I get it, if you read a lot of AI generated articles and this had some tells, it will seem inauthentic. But since I’m not a tech writer, I DID offer GLM-5.3 articles that I enjoyed as style references to help with the format.

Overall, outside of this blog, I think that the “did AI write this” criticism is here and everything is going to evolve. In fact, I was just listening to Hard Fork last Friday and they had the founder of Pangram on the podcast to talk about this exact subject because people want to feel that things are authentic but what authentic means will become blurry as models evolve.

But to be clear, every piece of content that I shared here was authentic. I came up with all of it, my wife watches Real Housewives, I did say “it does have some sort of soul”, “to an empty room”, it just happened to be me dictating this story and I let GLM-5.3 add some dramatic flair, sue me.

And guess what, I had GLM-5.3 read this as well, “When you’ve drafted it in your words, bring it back and I’ll red-team it against the thread’s most likely replies before you post. That keeps your rule intact: yours, not mine.”

The red-team session in progress


Soundtrack

This was on repeat during the final week of the saga, while the tablet rebooted itself in the living room:

From the live show edition of LINUX Unplugged 680, “Go Hack Yourself” (Jupiter Broadcasting), used under CC BY-SA 4.0. It is live-stream content and does not appear in the edited episode. Originally attributed to The Launch, also a great show.

The Daily Front Page 3 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — The Invisible Passenger
article

Malware infects Android-based automotive head unit firmware

by campuscodi·▲ 229 points·119 comments·securelist.com ↗
It had no user interface at all.

While monitoring Android threats in June 2026, we discovered a new piece of Android malware. What struck us as unusual was that it installed like an ordinary user app yet made no attempt to disguise itself as legitimate software: it had no user interface at all. This led us to suspect the app might be reaching users’ devices without their knowledge. Further investigation confirmed that hypothesis and allowed us to reconstruct the entire infection chain.

Key findings:

  • We identified new Android malware: a multi-stage downloader whose ultimate purpose is ad fraud and creation of a proxy botnet.
  • The malware spread through the built-in updaters of Android-based automotive head unit firmware. This is the first documented case of malware found on a car head unit with an infection chain specific to that type of device.
  • We attribute this activity, with high confidence, to the MoYu Group, an actor linked to the BADBOX botnet.

Kaspersky solutions detect the threats described below under the following detection names:

  • HEUR:Trojan-Dropper.AndroidOS.Agent.vu
  • HEUR:Trojan-Downloader.AndroidOS.Agent.ov
  • HEUR:Trojan-Proxy.AndroidOS.Zhima.*
  • HEUR:Trojan.AndroidOS.Vo1d.*

Head unit firmware overview

A head unit is a system that combines multimedia functions with partial control over certain vehicle functions. Head units may come as part of a car’s factory equipment or as an aftermarket upgrade. The main attack vectors for these systems are compromise via physical access and vulnerabilities in the head unit’s OS or components, both of which we’ve covered previously.

In some cases, head units run on Android, primarily because it’s convenient for manufacturers: Android’s source code already accounts for use cases within automotive head units. Android also allows manufacturers to add their own system applications during the build process, which they can use for a range of purposes: customizing the UI, adding system components tailored to the vendor’s needs, and more.

Most apps developed for Android devices can also run on an Android-based head unit, and that is true for malware as well. That said, it’s hard to imagine certain categories of smartphone-targeted malware being used to attack a head unit. Banking Trojans are a good example: since mobile banking is used almost exclusively on smartphones, infecting a head unit with a banking Trojan would be a waste of the attacker’s resources.

It’s worth noting that head units often include SIM card slots and can connect to the internet, enabling features like navigation and software updates. Since a head unit typically holds nothing of value to an attacker, one of the more likely attack scenarios using “classic” Android malware is infecting the device to recruit it into a botnet – similar to attacks on IoT devices.

During our research, we found exactly that kind of malware. The design of firmware for DoFun head units enabled attackers to distribute malware. We notified the vendor about the distribution scheme, and they subsequently reported fixing the security issues.

Below is the entire infection chain:

Head unit infection scheme

Head unit infection scheme

Let’s look at exactly how these head units became infected.

The TWCore app

TWCore is a legitimate system application responsible for collecting analytics data and updating the head unit software. Let’s take a closer look at how the update function works.

The process is fairly simple. An MQTT message broker hosted on the subdomain cardoor[.]cn sends a message containing information about the APK files that need to be downloaded and installed on the head unit. Notably, the object describing this message includes an installNotExists field, a Boolean flag that can be set to true or false. This flag allows TWCore to install apps that weren’t originally present on the device.

TWCore only checks whether an app is already installed on the device when installNotExists = false

TWCore only checks whether an app is already installed on the device when installNotExists = false

The APK file is downloaded to <TWCore external cache dir>/push/apk/ for installation.

The path TWCore uses to download APK files

The path TWCore uses to download APK files

Our telemetry revealed previously unknown malware at these file paths. On top of that, our data indicates that in every observed case, the malware was installed by an app with the package name com.tw.core, which matches the TWCore package name.

Next, we’ll break down the malware installed by TWCore: the JarService dropper.

Stage 1: the JarService dropper

As mentioned earlier, JarService is a small dropper app with no UI of any kind. It decrypts data stored as encrypted blocks within the Trojan’s code. Each block is XOR-encrypted with a single-byte key that shifts linearly from block to block. The decrypted data contains serialized information about the payload version and entry point, along with the malware’s own code for further loading.

Decrypting and deserializing information about the stage 2 payload

Decrypting and deserializing information about the stage 2 payload

In the version of JarService we analyzed, the entry point for the next-stage payload was the wa method of the com.c.j.qbh class.

Stage 2: the loader

This stage’s payload is a malicious loader. Its code contains encrypted strings that are later used as class names to execute the stage 3 payload using the reflection mechanism. The loader sends implant information to one of the attackers’ servers via a POST request. Example of a request to the C2 server:

{
    "userId": "REDACTED",
    "dexVersion": "1.7",
    "dexType": 1,
    "channelId": "2039",
    "packageName": "com.tw.jar1",
    "appVersion": 12,
    "appName": "JarService"
}

In response to the POST request, the C2 server returns a link for downloading the stage 3 payload. An example of a C2 response is shown below.

{
    "code": 200,
    "data": {
        "dexUrl": "hxxp://144.217.243[.]201/vr34der34/dex3.68.png",
        "dexVersion": 3.680,
        "status": 0
    }
}

The Trojan uses the link in the dexUrl field of the data object to download serialized data for loading the next stage. This data begins with a single-byte integer, a key used to decrypt the strings in the loader’s code. Immediately following this number is a four-byte floating-point value used to XOR-decrypt the stage 3 payload, which itself is located after these keys.

Decrypting the stage 3 payload

Decrypting the stage 3 payload

In the decrypted payload, the entry point is the init method of the com.ast.sdk.BillingMain class, shown in the screenshot below.

Entry point of the stage 3 payload

Entry point of the stage 3 payload

While analyzing this stage, we noticed that the download link for the next-stage payload includes a version number. We decided to try other version numbers to retrieve different payload versions, and ultimately obtained seven distinct variants, which we list under “Indicators of Compromise” at the end of this report. The earliest version, numbered 3.57, uses a different decoding algorithm than the one described above. This may indicate that an earlier version of the infection chain used a different loader between JarService and the stage 3 payload.

Stage 3: clicker / reverse proxy loader

In this stage, the malware sends a POST request to /cpc/api/task every 90 minutes by default, containing information about the infected device (display resolution, device model, the SSID of the connected Wi-Fi network, MAC address, and so on) along with the Trojan’s configuration version. If the configuration is outdated, the C2 server returns an updated configuration containing new C2 addresses and new paths for sending HTTP requests. An example of a response is shown below. Note that at the time of our research, the most up-to-date configuration version was 3.82.

{
    "code": 100,
    "data": {
        "configVersion": 3.820,
        "hosts": ["hxxp://t2.kshahnd[.]sbs", "hxxp://t2.mdsjhd[.]sbs", "hxxp://t2.nmnsny[.]sbs", "hxxps://t2.nmnsny[.]sbs"],
        "interval": 5500000,
        "reportApi": "/cpc/api/report",
        "tagName": "config",
        "taskApi": "/cpc/api/task",
        "updates": ["hxxp://a2.kshahnd[.]sbs", "hxxp://a2.mdsjhd[.]sbs", "hxxp://a2.nmnsny[.]sbs", "hxxps://a2.nmnsny[.]sbs"],
        "vn": 1.010
    }
}

If the configuration version doesn’t need updating, the C2 server instead returns integer command identifiers, which the attackers refer to as productId. The Trojan maps each identifier to command information, which it stores as a serialized JSON object using the SharedPreferences API. Each identifier also has its own version, expressed as a UNIX timestamp. If the C2 response includes an unknown productId or one whose version is outdated, the malware sends a GET request to the attackers’ server at /cpc/api/xml to retrieve the command contents for all such identifiers. The C2 server responds with command information for each unknown identifier. An example of a response is shown below.

{
    "code": 200,
    "data": [{
        "productId": 979,
        "script": "{\\n  \\"loadType\\": 1,\\n  \\"reload\\": true,\\n  \\"method\\": \\"start\\",\\n  \\"url2\\": \\"hxxp://144.217.243[.]201/vr34der34/sh65.io\\",\\n  \\"md52\\": \\"de77c3303e93c9450424759f1741441c\\",\\n  \\"name\\": \\"zhima\\",\\n  \\"className\\": \\"com.miyc.transfer.Client\\",\\n  \\"thread\\": true,\\n  \\"tagName\\": \\"loadlib2\\",\\n  \\"params\\": [\\n    {\\n      \\"type\\": \\"Context\\"\\n    },\\n    {\\n      \\"type\\": \\"String\\",\\n      \\"value\\": \\"107.151.248[.]132\\"\\n    },\\n    {\\n      \\"type\\": \\"String\\",\\n      \\"value\\": \\"1002\\"\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 1337\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 7777\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 8888\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 15000\\n    }\\n  ],\\n  \\"url\\": \\"hxxp://144.217.243[.]201/vr34der34/sh65.io\\",\\n  \\"md5\\": \\"de77c3303e93c9450424759f1741441c\\"\\n}",
        "version": 1778650942
    }, {
        "productId": 1019,
        "script": "{\\n  \\"loadType\\": 1,\\n  \\"reload\\": true,\\n  \\"method\\": \\"start\\",\\n  \\"url2\\": \\"hxxp://144.217.243[.]201/vr34der34/sh65.io\\",\\n  \\"md52\\": \\"de77c3303e93c9450424759f1741441c\\",\\n  \\"name\\": \\"zhima\\",\\n  \\"className\\": \\"com.miyc.transfer.Client\\",\\n  \\"thread\\": true,\\n  \\"tagName\\": \\"loadlib2\\",\\n  \\"params\\": [\\n    {\\n      \\"type\\": \\"Context\\"\\n    },\\n    {\\n      \\"type\\": \\"String\\",\\n      \\"value\\": \\"128.14.210[.]58\\"\\n    },\\n    {\\n      \\"type\\": \\"String\\",\\n      \\"value\\": \\"1002\\"\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 9999\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 7777\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 8888\\n    },\\n    {\\n      \\"type\\": \\"int\\",\\n      \\"value\\": 15000\\n    }\\n  ],\\n  \\"url\\": \\"hxxp://144.217.243[.]201/vr34der34/sh65.io\\",\\n  \\"md5\\": \\"de77c3303e93c9450424759f1741441c\\"\\n}",
        "version": 1766001509
    }, {
        "productId": 3505,
        "script": "{\\n\\"tagName\\":\\"http\\",\\n\\"url\\":\\"hxxps://api.kookjar[.]com/sayhi?channel=daihai&uuid={get_uuid_10}\\"\\n}",
        "version": 1776656317
    }],
    "msg": ""
}

The command information includes a tagName field, which is the command name. The code maps each name to the corresponding class responsible for executing it.

List of executable commands

List of executable commands

At the time of our research, the attackers had implemented nine commands. The table below lists command names, brief descriptions, and arguments.

Command name Description Arguments
return Return a value from SharedPreferences. key: the key whose value should be returned
copy Set the contents of the clipboard. text: the key whose value from SharedPreferences is returned as the clipboard contents
url: a link for downloading gzip-compressed data (optional); this data is then concatenated with the value of the text key, with      (5 spaces) used as a separator
http Make a POST/GET HTTP request to a specified resource and, if instructed, save the response in SharedPreferences under a specified key. url: the resource address
method: the HTTP method name (optional)
startLabel: a marker for the start of the data to save from the resource (optional)
endLabel: a marker for the end of the data to save from the resource (optional)
valueLabel: the key under which to save the value (optional)
header: a dictionary of headers for the HTTP request (optional)
content: the content of the POST request (optional)
web Open a link in the WebView and execute arbitrary JavaScript code within it. url: the link to open in the WebView
js: base64-encoded JavaScript code to execute in the WebView; used when the url parameter is empty or absent
corejs: JavaScript code to execute when the resource loads in the WebView (optional)
param: a string dictionary of parameters for launching the WebView
client: if this key is present, WebViewClient is used to handle redirects manually
time: task timeout
loadlib Not fully implemented at the time of publishing this report.
loadlib2 Download and execute arbitrary code. url: the address to download the payload from
name: the name of the module being downloaded
md5: the MD5 hash of the payload
clear: a comma-separated list of payload names to delete (optional)
params: an array of parameters to launch the payload with
className: the class name of the payload entry point
method: the name of the virtual method at the payload entry point
cmethod: the name of the static method used to instantiate the entry-point class (optional)
thread: a flag; the payload runs in a separate thread if this flag is not set
reload: a flag that, when set, restarts already loaded modules
loadlib3 Not fully implemented at the time of publishing this report.
deeplink Open a resource in the browser. url: a link to the resource
traceroute Check resource availability via an ICMP ping. host: comma-separated list of resources to check

However, attackers use only a relatively small subset of these commands in real-world attacks. As shown in the example C2 response above, at the time of publishing this report the attackers were using the loadlib2 and http commands. The payload downloaded via the loadlib2 command is a reverse proxy module named “zhima”, which researchers from the Nokia Deepfield Emergency Response Team independently discovered in TV set-top boxes around the same time as we did and also described in their report. This confirms that the attackers’ ultimate goal is building a proxy botnet.

While investigating this stage of the attack chain, we noticed that the zhima download link also included a version number. As with the previous stage, we tried other possible version numbers and found eight variants of the zhima module, the earliest of which was version 57. The complete list of identified zhima modules is provided under “Indicators of Compromise” below.

Attribution

While analyzing the complete infection chain, we noticed that the stage 2 loader created a thread with the meaningful name mosdk-host-loader. We decided to investigate what mosdk referred to in that name. This led us to a malicious app installed on various TV set-top boxes with the package name com.abc.nexus (3AD4BF5A86D26FFBF09CAE42AF330A98). It consists of several components (including a dropper similar to JarService), each used by the attackers to covertly monetize the device’s computing power. Each malicious component in the app corresponds to its own service, and the service containing the launch code for the JarService-like dropper is named AdmoyuService. In light of this and the name of the malicious thread found in the payload code, we concluded that moyu in the service name referred to MoYu Group, one of the actors linked to the BADBOX malware platform, which had been described by researchers at HUMAN. This assessment is further supported by extensive overlap between the malware’s network infrastructure and that of MoYu Group, which was independently identified by researchers from the Nokia Deepfield Emergency Response Team around the same time as our own research. Based on these similar naming patterns and prominent infrastructure overlap between the activity of MoYu Group and the attacks described in this report, we attribute it to the same actor with high confidence.

While investigating the malware downloaded by TWCore, we noticed that the domain admin.uipoxy[.]com resolved to the IP address 128.14.210[.]58, one of the C2 servers for the zhima reverse proxy module. It appears that the URL hxxp://admin.uipoxy[.]com/proxy/u/login hosts the zhima admin panel. Interestingly, this panel allows anyone to register as long as they have a valid invite code.

The malware operator registration page

The malware operator registration page

During registration, users are prompted to review the terms of use and privacy policy. Both documents are hosted on links under the pxyedge[.]com domain, which belongs to PXYEDGE, a vendor specializing in the sale of residential proxies.

On the registration page hosted at admin.uipoxy[.]com, we also found the string copyright © 2020 proxyforu[.]com all rights reserved, which linked to hxxps://proxyforu[.]com, the website of ProxyForU, another vendor of residential proxy services.

We found several similarities in the authentication APIs across all of these sites:

  • The sign-in page was hosted on an admin.* subdomain.
  • The sign-in page was located at /proxy/u/login.
  • The signup page was located at /proxy/register?channelKey=<invitation code>.

Based on this, we believe these services are connected to MoYu Group.

Conclusion

Despite efforts by cybersecurity professionals and law enforcement to shut down the BADBOX botnet, individual actors linked to it continue their malicious activity, infecting devices worldwide. Delivery methods for this kind of malware vary widely, from downloads via pre-installed backdoors to infected builds of IPTV apps. The case examined here demonstrates an even more sophisticated delivery method: distribution through the legitimate update functionality of a system application. Attackers are also actively expanding into new platforms. This malware is the first known malicious app targeting head units, which means these platforms now require protection against malware as well.

Indicators of compromise

Stage 1: JarService

ba27951b4ee1c341f4415d033369ecd3
d63bacd6d6709dd68a10ef9d374c7835
6c2e34b30da42085240ede53ab6107d4
8b5e513144a6138a966ea59e68bf9da2
e119845877089d6f4b0a70dc7388f316

Stage 2: loader

e9f3a0dab6949ce2cddab9e0aa80ae1a

Stage 3: loader/clicker

0fbaa7092204f4b1494e0b840b014774
1dcf031c40ce456b6a36a00b0acf3d11
44b6b213a6a3f299eaf88e078de95ecb
67dc78e544ebce16b85dc7c195dfbc58
9642ae619b3165d23c6349002d1abe24
b067d5b0dbecbd6498bcdfba45dba77e
f0e3f7eba2cde91e2dedb921bab47422

zhima module

412e9243f2981bbea3894254d105b3b8
71ab5517f71866279d0d87d37f2ae320
89ef78f716a75964539f2db6520be362
a4223ce4288a230d1e6c3ff2c7639045
bd4d81cd27125ad3d9a114922d468499
c6bfb1643ac7474ed8a7b4f96a187fdb
de77c3303e93c9450424759f1741441c
f8cf8c23ff597700d471fb7767df8bac

Domains and IP addresses

xmsae[.]sbs
ishano456[.]sbs
xshaon123[.]sbs
kshahnd[.]sbs
mdsjhd[.]sbs
nmnsny[.]sbs
kookjar[.]com
ty54fgd435[.]my
ue886578433[.]online
ty4523[.]space
144.217.243[.]201
107.151.248[.]132
128.14.210[.]58

Addresses used to download JarService

hxxp://ovcloudcontrol.cdn.cardoor[.]cn/upgrade/2026-06-08/bd80bd3c3d0e4bf6b5b4a825650d01f5.apk
hxxp://ovcloudcontrol.cdn.cardoor[.]cn/upgrade/2025-06-10/fe71af9ecf174de48d2b2ccc2c15fb04.apk
hxxp://ovcloudcontrol.cdn.cardoor[.]cn/upgrade/2024-11-07/fa831c3c23824b99871163387bcda7ad.apk

Hashes of TWCore (the legitimate software used to distribute JarService)

2a64c3efc11bf224aa54f24e876446c9
7a4d3ba2dacccfdda55859a5dfee2671
ea24487996eb70c1780922fb3063bcc5

The Daily Front Page 4 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Everything, Exposed
article

Everything I own, owned

by schlarpc·▲ 567 points·172 comments·schlarp.com ↗
Peripherals have proven to be an ideal target for agentic RE.

Over the past couple weeks I’ve been doing agent-driven reverse engineering of peripherals that happen to be within arm’s reach. From those devices, I’ve come away with a full plaintext command shell inside my microphone, a webcam whose activity LED I can switch off while it records, and a key light that hands out memory writes to anyone on the WiFi. Peripherals have proven to be an ideal target for agentic RE - they’re tiny computers attached to my computer, with a data connection to the host and usually a firmware update mechanism, so an agent has something to iterate against. The net outcome is better control and understanding of my machine.

My process was pretty much the same for each of these devices: grab a copy of the device’s firmware and associated update tool from the manufacturer, throw it into my reverse engineering environment, tell Claude Opus 5 what my goals are, and let it churn. Depending on the device, the goals were somewhat different, but they usually looked something like:

In this directory is the firmware and update utility for ___. The device is also attached to this computer, and you may interact with it in non-mutating ways. Exhaustively document and cross-validate the entire firmware, including the following goals:

* reverse engineer the firmware update format and update protocol
* implement our own update utility
* determine the security properties of the update protocol, including checksums, signature validation, secure boot
* use static and dynamic analysis to determine all protocol surfaces and completely enumerate functionality
* find any hidden or debug functionality in the product and how to access it

Depending on the results, there were different directions of follow-up, but you should get the general idea. Let’s run through the list - each device links to a GitHub repo full of generated-slop docs and scripts, most of which have been validated live against real hardware. I’ve also included the effort each device took, pulled out of the Claude Code session transcripts. “Churn” is the time Claude was actually working, with the long idle gaps removed. “Prompts from me” is every message I typed, including the one-word ones telling it to keep going. All five devices together came out to about 13 hours of churn and 98 prompts, spread across two weeks of evenings.

Everything I own

Insta360 Link webcam

GitHub repo - 3.7 hours of Claude churn, 33 prompts from me

Insta360 Link webcam, its green activity LED lit

I use an Insta360 Link webcam, which is a nice gimbaled pan-tilt-zoom camera that does face tracking for automatically framing the shot. I wanted to know if it was possible to subvert the activity LED, like in the classic iSeeYou exploit.

Interestingly, it was immediately obvious that this camera has a lot going on inside it. It turns out that it runs a whole RTOS (ThreadX) sourced from the upstream SoC vendor, Ambarella. The RTOS hosts several small vision models that provide things like the aforementioned face tracking, as well as gesture detection for controlling settings. Pretty amazing complexity inside a tiny webcam, but it also means there’s some exciting attack surface here.

Over the USB Video Class interface, there’s an XU (Extension Unit) command that kicks the device into “mass storage” mode. This then lets us transfer a staged firmware update to the device’s internal FAT filesystem, which the device then applies to itself on reboot. This route does require user intervention to reboot with a replug, but there’s actually another command channel that exposes arbitrary read/write of files and a reboot command over the USB vendor class. With this, we can fully flash the device without any user interaction. Once the firmware is in the right place, there’s effectively no anti-tamper, just an appended MD5 hash to ensure integrity.

The indicator LED turns out to have a well-structured set of “patterns” in the firmware that dictate color, blink pattern, etc. that are indexed into for various device states. I had Claude write a tool to patch out the table entry for camera activity, fix up the integrity hash, and flash it to the camera. A quick test showed that the green LED that normally illuminates while recording no longer turned on. Horrifying! On this device, the gimbal itself also deflects down when not recording, so it’s not completely stealth, but it still doesn’t feel great.

The LED behavior before and after patching.

ASUS ROG Swift PG42UQ monitor

GitHub repo - 1.2 hours of Claude churn, 13 prompts from me

ASUS ROG Swift PG42UQ monitor

My ASUS ROG Swift PG42UQ monitor was actually where I started, because I got annoyed at the pop-up overlay that comes up every once in a while that tells me to run “pixel cleaning”. I have never intentionally run pixel cleaning on this monitor and I never will, I don’t care, and I would like for that overlay to go away forever. Maybe there’s a debug menu or something that can turn it off, or worst case we patch a branch in the firmware?

Claude found that the firmware has effectively no protection whatsoever - there’s a two-slot A/B scheme and a simple checksum, but ultimately we can write whatever we want to the thing. Firmware updates run over an I2C bus bridged over USB.

The pixel cleaning warning turns out to have no native way to disable it, and it’ll always show up after 8 hours of runtime. Oh well. Claude did find the appropriate area to patch to kill the functionality though. I haven’t actually been brave enough to write a modified firmware to the thing yet - it’s a pretty expensive monitor - but I’ll get there at some point.

Another neat thing was exploring the DDC/CI interface. This is the control channel available over the display cable itself, allowing the host to change inputs and other settings. I believe ASUS offers this through their Windows utility, DisplayWidget, but that does little for me on Linux. So, now I have a shell script that can flip through some of the DDC/CI features like the hardware crosshair or zoom overlays, FPS counter, and countdown timer. I might set up some of these on hotkeys in the future for easy access.

Shure MV7 microphone

GitHub repo - 4.2 hours of Claude churn, 32 prompts from me

Shure MV7 microphone

At this point, there’s less actual incentive to keep popping these devices and more just morbid curiosity. My microphone, the Shure MV7, connects over USB and obviously has some amount of smarts to it, with on-device digital volume controls and such.

The firmware for this one turned out to be hidden inside the Windows software, MOTIV Mix, so Claude installed that in Wine, found the update server, and pulled it down. I wasn’t on the latest, so there was actually a reasonable incentive here to get this working just to update my microphone from Linux. The firmware turned out to contain both DSP and MCU firmware, and was honestly pretty boring as you might expect. Again, no real security on the firmware flash itself.

However, the update protocol revealed that the entire thing actually runs over a USB HID vendor class protocol that implements a full plaintext command shell, with 48 different commands. Since it’s HID, we can actually hit this over WebHID from a webpage in Chrome, so I had Claude build a web interface for using the shell. There’s all sorts of interesting settings in here including a dozen DSP knobs, arbitrary memory read/write, LED control, and a 4-tier user privilege system whose entire authentication is a string comparison against the name of the tier you asked for. su sup just works, and the top tier can disable the touch panel so you can’t mute at the device, and drive the mute LED independently of whether the microphone is actually muted. It’s the webcam LED trick again, on a microphone. Obviously, be aware that you could probably break your device if you use that UI and do something stupid with it.

WebHID interface for the MV7’s command shell, showing DSP settings and a console The WebHID shell interface. The DSP knobs on the left are the device’s own settings; the console on the right is the plaintext command shell talking over HID.

Elgato Cam Link 4K video capture

GitHub repo - 1.5 hours of Claude churn, 10 prompts from me

Elgato Cam Link 4K video capture dongle

The Elgato Cam Link 4K is just an HDMI video capture device, and honestly was just more of the same. The interesting thing for this one was that I let it go fully unattended - I literally kicked off the process before going to sleep and woke up to a teardown and functioning firmware updater. The firmware contains an MCU image and an FPGA bitstream for the actual HDMI handling, so you could potentially do something fun with the FPGA if you went deep enough into the reverse engineering there. There’s no protection on the firmware update path.

I was able to pull out all the EDID information used for negotiating video parameters, so we know exactly what resolutions, refresh rates, color spaces, and chroma subsampling options are offered to devices.

The vendor HID protocol does include tunneled access to the internal I2C bus, which is kinda neat as you can poke the internal HDMI receiver registers.

Elgato Key Light Mini

GitHub repo - 2.4 hours of Claude churn, 10 prompts from me

Elgato Key Light Mini

Finally, I poked at something that wasn’t connected over USB but WiFi instead, the Elgato Key Light Mini. This one turned out to be way more interesting than I expected: it’s the only one with meaningful firmware integrity protection. Elgato signs the firmware updates with Ed25519 over a SHA-512 hash of the firmware payload, and rejects firmware that doesn’t validate. This makes sense to do, as the device basically connects to a WiFi network and then provides unauthenticated access to anyone on the same network, so the threat model is inherently different.

Unfortunately, while that’s an improvement over all of the other devices we’ve looked at, it protects the firmware at exactly one point in time: when an update is happening. It’s not a boot time check enforced by the bootloader or any other kind of secure boot scheme, and the updater happens to be running while everything else in the device is still operating, meaning there’s huge attack surface to try to disable that signature validation. I asked Claude to look for an exploit that might enable this, and it found a doozy: an HTTP POST request that drops a payload straight into the internal UART, which includes a memory poke command. This means that a single HTTP POST of ATSE=0200ED94,0E001009 turns the signature check into a no-op, and we can freely update to a firmware image without a legitimate signature. I successfully tested this with a simple patch that changed the name of the device, so uh, yeah, don’t put these on an untrusted network.

…, owned

I have a lot of feelings about this whole thing. As I wrote back in March, this is incredible for interoperability and fixing things that don’t work how we want them to. Hardware is almost universally “open” for tinkering at this point with just a couple hours of mostly hands-off machine-driven labor each, and I look forward to a near future where I can add features to my webcam firmware as easily as I can to software that runs on my Linux machine itself.

On the other hand, as a security professional, this scares me for several reasons. I would work from the operating assumption that any device attached to a computer could have had a malicious firmware implant performed, where previously that required significant per-model investment and was stereotyped as a “state actor” kind of activity. Operating systems aren’t really equipped to work with the user to ensure that a microphone stays a microphone, and doesn’t spontaneously turn into a keyboard that hits Win+R and drops a payload to steal all your data when the room is quiet enough that it can assume you aren’t watching. And the existence of WebUSB, WebHID, and WebBluetooth mean that for some devices, depending on the specifics of which classes are used, a moment of user indiscretion in accepting a permissions prompt could permanently backdoor one of their attached devices.

Network-connected devices seem near universally fucked at this point? There are a few others I’ve poked at that I haven’t documented here, but I’ve gotten a root shell on a commercial Dell display, and RCE on an Eaton UPS. Obviously it was never best practice to let untrusted clients touch these things, but the speed and scale at which this can be executed makes the risk so much higher now.

Finally, I can’t help but think about what an AI-equipped automatically-reverse-engineering worm could do today. It’s only a tiny leap to imagine that someone could make a self-replicating piece of malware that probes its environment, relaying reconnaissance back to a smart command-and-control that actively works to push itself into accessories and IoT devices and industrial equipment found adjacent to an infected target. Two things have kept this from happening: every device model needs its own reverse engineering, and validating any of it needs the hardware in hand. The first is the labor I just handed to an agent. The second is free to malware already sitting on an infected host. Honestly, I wouldn’t be surprised if this already exists, and I think the next few years are going to be extremely interesting. 🫠

The Daily Front Page 5 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Cameras With a Back Door
article

Slovakia finds Russian backdoor in traffic speed cameras

by dredmorbius·▲ 371 points·144 comments·risky.biz ↗
The cameras contain a backdoor mechanism that grants shell and network access.

Risky Bulletin: Slovakia finds Russian backdoor in traffic speed cameras

Slovakia's national security service NBU has issued a security alert against the use of NERO R-ONE high-speed traffic cameras.

The agency says the cameras contain a backdoor mechanism that grants shell and network access to the devices via an SMS message received from a list of hardcoded Russian phone numbers.

The NBU started an investigation into the devices after the country's opposition accused the government of buying the cameras from Russia and after multiple reports in Slovak media that linked the purchase to a Cyprus shell company with fake certifications.

According to the NBU, the cameras are a rebranded version of a Russian traffic camera model named CORDON PRO.M, produced by St. Petersburg-based Russian firm Semicon.

via NBU

via NBU

The cameras were bought as part of a €30 million EU-funded project to rebuild the country's national traffic monitoring system.

The Interior Ministry has allegedly bought and preparing to install 279 cameras on selected roads across Slovakia.

The Ministry initially denied that the cameras were of Russian origin and said there's no danger of data theft since the devices were going to be on a closed loop Ministry network.

According to an NBU technical report, besides the backdoor system, the cameras also contain several security flaws. They have a crucial SecureBoot security feature that's turned off so the firmware origin is never enforced, the web management portal contains multiple vulnerabilities, and the cameras expose live streams to anyone without a password and who knows their broadcasting IP.

Interior Ministry officials paused the camera deployment after the NBU report and said it would order an additional assessment from an independent auditor to confirm the findings.

Some similar devices are also allegedly installed in Croatia and maybe some other countries in Eastern Europe.

Source

Nobody should be buying security cameras from Russia, or China for that matter https://t.co/ZiuuZ3ODjQ

— ChrisO_wiki (@ChrisO_wiki) August 18, 2026

Breaches, hacks, and security incidents

Scammers target UK prime minister: A scammer targeted UK Prime Minister Andy Burnham by posing as White House chief of staff Susie Wiles. Burnham detected the scam himself and the UK embassy notified the White House. Multiple US senators, governors, and executives were also targeted by scammers posing as Wiles last year. The White House blamed the incident on a hacker obtaining a copy of her cellphone contacts. [Politico Europe]

Hackers target Ukraine's ARMA agency: A cyberattack has disrupted the activities of Ukraine's agency for managing seized Russian assets. The attack took place this week as the agency was preparing to assign a new manager for beverage company IDS Ukraine. Ukraine seized IDS from Alfa-Bank co-founder Mikhail Fridman shortly after Russia's invasion. The agency didn't attribute the attack. [RBC // ARMA]

Hack hits Berlin government: A cyberattack has disrupted two major departments in the Berlin city government. The attack took down emails, remote gateways, and internet connections across the transport and urban development departments. IT staff have disconnected the two agencies from the city network to prevent the incident from spreading. [Tagesspiegel // RBB24 // Yahoo Finance!]

Breach at genetics testing company: Genetics-testing company Baylor Genetics is notifying users of a security breach that exposed their personal information. The breach took place in June and both patient and employee data was compromised. The company didn't disclose the number of affected individuals. [Baylor Genetics // CybersecurityDive]

UT San Antonio breach: The University of Texas at San Antonio has taken its IT systems offline after a security breach over the weekend. Classes for the new school year are expected to start on Wednesday as scheduled. The university has extended tuition payment deadlines and plans to reset all user account passwords once systems are online. [UT San Antonio // The Record]

Ransomware disables hospital doors, HAVC: A ransomware attack has disabled access doors, heating, ventilation, and air conditioning at Winnipeg's largest hospital. The Winnipeg Health Sciences Centre increased onsite security while the access card system is still down. The hospital says patient care and clinical operations are not impacted. [CBC // The Winnipeg Free Press] [h/t Alex Rudolph]

BlueSky and GitHub hit by Iranian DDoS attacks: An Iranian hacktivist group took down BlueSky and GitHub with DDoS attacks on Sunday and Monday, respectively. The attacks caused prolonged outages at both companies. A group known as the 313 Team took credit for the attacks. The hackers were also behind another wave of DDoS attack in April. [Telegram // Telegram]

We apologize for yesterday’s service problems. Bluesky experienced a DDoS attack—a flood of junk traffic meant to knock servers offline—over a period of 24 hours. We have upgraded our defenses in response, and we continue to monitor the situation. Follow @status.bsky.app for any updates.

— Bluesky (@bsky.app) August 18, 2026 at 12:27 AM

SafePal breach: Hackers have stolen the personal information of 40,000 customers of hardware crypto-wallet provider SafePal. The incident impacted all customers who placed orders of SafePal wallets between March 2, 2025, and April 11, 2026. SafePal says no seed phrases or private keys are impacted. The stolen data is still dangerous because it could enable wrench attacks on wallet holders. [SafePal // SecurityWeek]

Bits of Gold breach: Hackers have stolen the data of 250,000 customers of Bits of Gold, Israel's largest cryptocurrency exchange. The company notified customers of the hack over the weekend. It said the data was stolen from an external analytics service provider. It didn't say what type of data was stolen. [CTech]

TheHatman dumps employee data for a dozen companies: A threat actor is selling the employee data of almost a dozen Fortune 500 companies. The hacker, who goes by TheHatman, claims the data was stolen by using stolen credentials to access each victim's Azure environments. The hacker claims they breached McDonalds, Vodafone, Gap, and the Intercontinental and Wyndham hotel chains. [HudsonRock]

AI, general tech, and privacy

Windows 11 drops WMIC: The current Windows 11 installation packages and Insider Builds do not ship with the Windows Management Instrumentation Command-line (WMIC) feature anymore. Microsoft deprecated the toolkit a few years ago after it saw massive abuse. [Microsoft // WindowsLatest]

Firefox 154: Mozilla has released Firefox 154. New features and security fixes are included. The biggest feature in this release is support for GeForce NOW, NVIDIA's cloud gaming platform. [Firefox]

Firefox for iOS gets an ad blocker: Mozilla has added an ad blocker to Firefox on iOS. It is turned off by default. [Mozilla]

Government, politics, and policy

Russian things: A Russian court has forced two Telegram channel owners to remove posts blaming the country's internet watchdog for causing an outage of the country's banking system as part of an attempt to block VPN protocols. This is funny to me because they didn't fine Natalya Kaspersky, one of the Kaspersky co-founders, for basically saying the same thing in an official manner and to more mainstream Russian news outlets. Alas, Russia, a two-tiered society! [Caution News on Telegram]

Arrests, cybercrime, and threat intel

French cops used public exploit to hack EncroChat: French law enforcement used a public exploit hosted on GitHub to hack encrypted phone network EncroChat in 2020. The exploit was for the Bad Binder Android vulnerability and had been shared online a few months before. EncroChat discovered the hacks after French cops deployed a second exploit that failed. [ComputerWeekly // Bad Binder exploit on GitHub // Bad Binder write-up]

Source

SMS blaster arrested in Malaysia: Malaysian authorities have arrested a 65-year-old suspect for driving around with an SMS blaster in his car. The suspect was detained driving around the border crossing between Johor Bahru and Singapore. He is the second suspect arrested this month in Johor Bahru for SMS blasting. [CommsRisk]

LockerGoga dev on trial in Switzerland: Swiss prosecutors are seeking a 12-year prison sentence for a Ukrainian man linked to ransomware attacks on local companies. Officials claim the suspect was a coder for the LockerGoga, MegaCortex and Nefilim ransomware groups. The suspect is pleading not guilty. He claims he was working as a consultant for a cybersecurity firm when he was detained and the ransomware source code found on his devices. [Watson // The Record]

Ransomware affiliate poses as data recovery firm: A ransomware affiliate is posing as a data recovery firm named Ransom Busters LTD. According to GuidePoint Security, the group has reached out to multiple companies and offered to delete their data from ransomware servers for a fee between $20,000 and $60,000. The group has reached out to victims even before breaches were made public. GuidePoint believes the group has signed up as an affiliate on different Ransomware-as-a-Service platforms to see hacked companies and reach out in advance. [GuidePoint Security]

Operation CameraSwarm: A threat actor has hacked more than 14,500 Dahua security cameras across Ukraine and Russia. Researchers at Hunt Intelligence discovered the botnet after the hacker left an open directory on their server infrastructure. According to files recovered from the server, the hacker exploited old vulnerabilities but also a secret hardcoded account in some of the devices. [Hunt Intelligence]

StopAndProtect profile: Security firm Check Point has published a profile on StopAndProtect, a new e-crime operation using thousands of hacked WordPress sites to redirect users to malware downloads and then store stolen creds. [Check Point]

FUXA scanning: Threat actors are scanning for FUXA SCADA devices in an attempt to exploit CVE-2026-25895, an unauthenticated path traversal that can let hackers rewrite local files. [Caitlin Condon on LinkedIn]

StubMaker RubyGems campaign: The OSM team has spotted 16 malicious RubyGems packages typosquatting more popular packages that spread a Windows infostealer to whoever installs them. [OpenSourceMalware]

Malware technical reports

DragonDoll Android spyware: Russian security firm Positive Technologies has discovered a new Android spyware strain. Named DragonDoll, the spyware is spread using fake Chrome update packages and focuses on stealing data from instant messengers. [Positive Technologies // Archived]

GoldDigger Android trojan: IBM's Trusteer team has published a technical analysis of GoldDigger, an Android banking trojan active since 2023. [IBM]

C2Looper backdoor: In July 2026, researchers identified C2Looper, a new malware family likely used in ransomware attacks to establish a foothold for lateral movement. [Zscaler]

TWINLOOT: Ontinue researchers have discovered TWINLOOT, a Python-coded malware framework that hosts its entire command-and-control infrastructure inside trusted Microsoft services such as Azure, M365, and SharePoint. [Ontinue]

MacSync Stealer: Microsoft has released a technical report on MacSync Stealer, a recent infostealer targeting the macOS ecosystem. [Microsoft]

WordlistLoader: Gen Threat Labs has identified WordlistLoader, a new loader used to deliver Amatera Stealer via ClearFake campaigns. [Gen Digital]

Shadow HVNC and Shadow Loader: Security researchers have reverse-engineered Shadow HVNC and Shadow Loader, two malware families advertised online by a developer known as RemoteX. [Malbear Labs]

ValleyRAT: Despite some arrests this year, the SilverFox group is still active and spreading its ValleyRAT malware. [Forcepoint]

AZALEA RAT: And speaking of RATs, Point Wild looks at the distribution chains of the AZALEA RAT, a new RAT advertised online as AzaleaControl. [Point Wild]

Medusa ransomware: CISA has updated its advisory on the Medusa ransomware with new TTPs. The agency says the group has continued to be active and made hundreds of new victims. [CISA]

Mirage2FA: ANY.RUN's security team looks at a new 2FA-intercepting phishing service named Mirage2FA. The service seems to be geared towards M365 campaigns primarily. [ANY.RUN]

APTs, cyber-espionage, and info-ops

France investigates Russian disinfo ops: French authorities have launched an investigation into suspected Russian disinformation campaigns targeting the country's pro-EU politicians. The campaigns targeted possible presidential candidates Gabriel Attal and Edouard Philippe as soon as they showed interest in next year's election. Open-source reporting has linked the campaigns to a Russian disinformation group known as Matryoshka and Storm-1516. [FranceInfo]

Operation QUICSILVER: A China threat actor has been targeting Myanmar diplomats via an VHD-delivered Go backdoor named QUICAgent. [Seqrite]

Goffee replaces image files: The Goffee cyber-espionage group has maintained a foothold inside hacked organizations by altering installation images for corporate apps. In a campaign targeting Russian companies, the group has modified 7-Zip and Git installers. [F6]

Core Werewolf's CoreRAT: A highly sophisticated APT group named Core Werewolf has continued its operations targeting Russian orgs with a new remote access trojan named CoreRAT. [BI.ZONE]

Russia and US hold hands in Alberta info-ops: The US and Russia appear to have joined hands in promoting the Alberta separatist movement in Canada. [The Globe and Mail]

"The first data from a study that began last month indicate Russian content farms have been pushing pro-separatist content into online communities and using Canadians to “launder” those messages by sharing such material on their social media feeds, the researchers said. The U.S. activity, on the other hand, is more overt, with prominent American influencers, podcasts and websites openly promoting Alberta separation, said Brian McQuinn, co-director of the Centre for Artificial Intelligence, Data, and Conflict at the University of Regina."

CopyCop (Storm-1516) in Armenia: Russian disinfo group CopyCop ran a disinformation campaign trying to sabotage the construction of a shared US-Armenian AI data center in Hrazdan. [Recorded Future]

PurpleDelta: Recorded Future has identified 22 new personas operated by PurpleDelta, the name the company assigns to North Korea's remote IT worker scheme. Also this week, Bridewell published a guide on how to defend against these groups. [Recorded Future // Bridewell]

Iranian phishing ops target Israeli journalists: Iranian state hackers have intensified spear-phishing attacks targeting Israeli journalists. The country's intelligence and cybersecurity agencies have sent out a security alert about the attacks last week. The agencies say hackers are seeking to obtain private information from journalists reporting on political and national security. [Ynet]

US charges more Mabna hackers: The US has unsealed a superseding indictment against 17 Iranian hackers. The suspects are employees of the Mabna Institute, a cyber contractor for Iran's Islamic Revolutionary Guard Corps. The Justice Department claims Mabna hackers breached universities across the world to steal research and transfer to Iranian counterparts. The superseding charges replace a 2018 indictment that expands the number of suspects from nine to 17. The State Department has also offered a $10 million reward for information that may lead to the arrest of any of the suspects. The Mabna Institute hacking campaigns are tracked by security firms under the codename of Cobalt Dickens. [DOJ 2026 // DOJ 2018 // Rewards for Justice // Sophos]

Vulnerabilities, security research, and bug bounty

Security updates: Apple, Dell, Edge, Firefox, GitLab, Oracle, Tenable, Tor Browser.

AI agent introduces bug in Snowflake's production: Security firm Wiz has spotted an AI coding agent autofixing a bug but introducing a vulnerability in cloud provider Snowflake's production systems. [Wiz]

Microsoft delays Exchange updates due to influx of AI bugs: Microsoft has delayed a major update for Exchange Subscription Edition servers due to an influx of AI-discovered vulnerabilities. The update was supposed to go live at the end of June. Microsoft says it did not want to release its biannual feature update only to release multiple batches of security fixes right after. The company plans to wait to fix all security bugs before releasing the Exchange SE H1 Cumulative Update. Microsoft says employees discovered the security flaws as part of an internal push to use AI tools for bug discovery. [Microsoft]

KEV update: CISA has updated its KEV database with four vulnerabilities that are currently exploited in the wild. All are 2026 bugs, such as a recent Apple macOS ScreenShare bug, a Microsoft IKE one, a SharePoint one, and a VMware vCenter path traversal.

Infosec industry

Acquisition news: Tech giant Fortinet has acquired AI security startup Virtue AI, which specializes in AI runtime protection, automated AI validation, and security for autonomous AI systems. [Fortinet]

Threat/trend reports: Beazley Security, Black Kite, Bridewell, Cyberproof, Ecosyste.ms, JPMorgan, MinterEllison, and Onyxia have recently published reports and summaries covering various emerging threats and industry trends.

The Daily Front Page 6 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Reading, Then Writing
article

To become a better writer, read as much as you can

by andsoitis·▲ 442 points·254 comments·nappertime.com ↗
There’s no one way – every writer will have a different path to creation.

I’m obsessed with the craft of writing. I write every day, I read about the craft often, and in my spare time I like to unwind by… watching interviews where authors talk about their writing process. It’s a sickness. Help me.

One of the key things I’ve learned is this: there’s no real blueprint. I say this to aspiring writers in my workshops, and those I mentor. There’s no one way – every writer will have a different path to creation. Now, this doesn’t mean you shouldn’t be listening to other authors, not at all – it’s a great way to help you think about the creative process – but it does mean nothing is holy writ.

King cites Blood Meridian, The Satanic Verses, and Huckleberry Finn as his favourites

Except the one golden rule*. One rule that is true, no matter the writer. One rule, that if you don’t follow, means you shouldn’t be writing in the first place.

Here it is**: Read as much as you can. Read widely and well.**

I would’ve thought the necessity of reading in this profession obvious. But I’ve noticed a worrying trend lately: aspiring writers who don’t read.

Whenever I give a workshop, or an occasional creative writing lecture at uni, or mentor an individual, I always ask the following questions: who are your favourite authors? And, what are you reading now? I do this as a short cut to finding out their interests, and how therefore I might frame my advice.

But over the past few years, more and more the answer will be: I’m too busy to read. Or: I haven’t read a book in a while (whereafter they rack their brains and tell me they might’ve read Fourth Wing a year back).

To which I say this: fuck you, you’re not too busy.

Joking. I would never say that. But I certainly fucking think it. Now, to be clear – I’m not dissing the Fourth Wing here. On the contrary: if Fourth Wing is a gateway drug to getting someone back into reading, then anyone who loves books should be thankful to Rebecca Yarros.

Sontag

But I am saying this: go look at your phone, and tell me what your average screen time is per day. Two hours? Five? Seven? If so – shut up: you’ve time to read.

I write full-time, currently work three gig jobs on the side, and am engaged with lives of my two children. I read every night. It’s not hard: instead of staring at my phone, or streaming, I read. This is not a boast, nor is it special. This is my job as a writer.

You want to be a writer? Then shut up and read.

Here’s why:

1) Reading teaches the writer about the craft

Every book is an education. Good, bad, mediocre, they teach us the writing craft. Even if we’re not studying the text per se, we’re learning. All the books you’ve ever read – especially the books you read when you were younger – have imprinted themselves on your brain.

It might be genre, character type, trope, setting, structure, anything, everything – you’ve habituated your brain to the patterns and elements of the novel. Certain writers will have a style that will appeal, and it is completely fine to emulate that style as you develop your own ‘voice’ as a writer (by voice I mean, the expression of individuality in your art).

When I began writing, I had some early beta readers say: oh, I see you’ve followed the classic three-act structure. To which I thought: I did? I didn’t know structure back then; I’d never taken a creative writing class. Yet my writing brain instinctively created one, because it had been informed by my life as a reader.

Ishiguro

In the years since, I’ve subsequently taught classes on three and five-act structures, and the purpose of structure in general. I’m not saying such formal classes are of no value, but I do tend to think they are overrated. The reality is, up until recent decades, ‘creative writing’ was not a degree in and of itself. The much-vaunted MFA is only a relatively recent phenomena. They might be useful for some, but ultimately are peripheral compared to the central importance of reading.

2) Reading inspires the writer

I love reading out of genre. The best ideas I get for science fiction don’t come from science fiction. Crime, for example – hardboiled fiction in particular – helped me better understand the origins of cyberpunk, its thematic core, and some of the stylistic possibilities of the subgenre. Non-fiction has given me an unending supply of the raw materials for story – whether that be current events, or history, or science, or philosophy, or anything else – and been a constant source of inspiration. Poetry, as a third example, has taught me how I might use words in an elegant way, and with the strictest of economy create an image, or a mood, or a feeling.

A book almost always has something to teach us – even if it’s how not to write.

Bradbury

3) Reading changes the structure of the brain

There was a terrible American TV show called Everyone Loves Raymond. I remember little about it, other than when it came on, I tended to change the channel (the show is so old that changing channels was still a thing). But to this day I remember an exchange between the two leads. Raymond has just left his job as a journalist.

His wife says to him: “Why don’t you write the great American novel?”

Raymond replies: “Write it? I wouldn’t want to read it.”

Cue the canned laughter. It is a little funny, I guess, because Raymond has no interest in literature, so the thought of him writing it is absurd.

But here’s the thing: it sums up what’s wrong with the mentality of many an aspiring writer today. One I simply don’t understand. Why be a writer if you don’t love reading? Why devote your intellectual and emotional energy to creating a book, when it’s a form you’re not invested in? Why write, when you aren’t steeped in wonder of storytelling?

Nabokov

Think about the great film directors. Nolan, or Tarantino, or Scorsese, any of them. They love film. They live and breathe it. Their knowledge of cinema is encyclopaedic and it has without question inspired them and made them better directors. Their cinematic vision has been informed by the richness of the history of cinema, and realised through their life-long commitment to the form.

Literature is no different. Take Le Guin, or Virginia Woolf, or Nabokov. These writers were extraordinarily well-read, whose passion for the written word infused their entire creative existence, whose time, when not writing, was often spent discussing or reviewing or debating novels.

That’s the thing about Generative AI. It gives all the Raymonds out there, the people who don’t even like reading, the capacity to generate a book. It’s not just that they are lazy and talentless, they’re not even interested in literature. They don’t actually like art, they just like the idea of making art.

But I don’t want to waste my time talking about those losers (and yes, I’m getting to the part about brain structure – this preamble is relevant). This article is not for them, but for you, the aspiring writer (or, perhaps, someone like me, a published author who yet is obsessed with the way others conceive of their craft).

I read 52 books a year. I have friends who read over a hundred (which for me personally would be too much: I like to savour my books). Some authors I know read as low as 20, and that really is the bare minimum.

Reading changes the structure of the brain, and for the good. But here’s the rub: a digital addiction also changes your brain, and for the ill.

de Beauvoir

This is a phenomenon dealt with by Maryanne Wolf in ‘Reader, Come Home: The Reading Brain in a Digital World,’ but which I’ve seen elsewhere, time and again, in opinion article and in peer reviewed science. In essence, the digital brain – distracted by social media, fiercely hunting for the next endorphin hit, its attention span severely limited – is anathema to the reading brain, which needs time, sustained concentration, vivid imagination, and critical thinking skills.

More and more we lose the ability to immerse ourselves in a book, because we’ve rewired our neural pathways to the digital experience. You know the feeling. The urge to keep picking up your phone, the doom scrolling that eats untold hours/days/weeks from your life, the anxiousness caused by your social media feed and the anxiousness caused by not having access to your social media feed. It’s a pernicious age, where the smart phones we all must carry are infested by apps algorithmically designed by the biohackers of the large tech companies to hijack the timeline of your life, and divert your attention.

And here’s the thing: the reading brain – which many of us are losing – is also the writing brain. That is: attention span, sustained concentration, and a vivid imagination are fundamental skills required the author. Writing a book is like running a marathon, and the fitness regime required to do so is reading. It builds your creative muscles, the stamina to stay at your computer and find the words, and if you are lucky, enables the flow state of creative writing, where the world disappears and all that remains is story. Flow state: that extraordinary and rare experience that yet all writers have known, where suddenly hours have passed while you’ve been immersed in story.

I just love this pic

And to be clear: if you are addicted to the digital, there’s hope for you yet. Just a few weeks of putting aside the phone at night, of settling down with a book for an hour, this will change your brain. It will develop your writing muscles.

So there you have it: the secret to being a better writer, and the secret all great writers share. And I’ve given it to you for free. Now all you need to do, is do it, every day.

Go forth, and read.

(*It goes without saying that to you must write, as well. This is not a ‘rule’ as such as it is a statement of reality: writers write. Write as much as you can, as your schedule will allow. No excuses. Write).

The Daily Front Page 7 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Harnessing the Model
article

What Is a Harness?

by tosh·▲ 391 points·145 comments·earendil.com ↗
To control something, usually in order to use its power.

Harness – definition by the Cambridge Dictionary

Noun. a piece of equipment with straps and belts, used to control or hold in place a person, animal, or object

Verb. to control something, usually in order to use its power

When I think of a harness, I think first of the set of straps and belts that I put on in middle school before scrambling up the walls of my school. I was a mediocre climber at best.

Royal Robbins on El Capitan, his harness racked with the tools of the ascent.

Royal Robbins on El Capitan, his harness racked with the tools of the ascent. Photo by Tom Frost.

If you’re main-lining into the AI newsfeed these days however, your archetypal harness may already be an agent harness. And, this post was not written for you.

This was written for those who may be curious to know what an agent harness is, but don’t, and have been too embarrassed to ask.

Let’s get back to climbing.

Why do you strap on a harness when you go climbing? Well, firstly, the harness supports you and keeps you safe. It does that by connecting you to carabiners and ropes that secure you from falls, moderate your pace, and govern your route. You can also attach other tools to your harness like a chalk bag, nut tools and quickdraws.

And when you go climb different mountains or make different ascents you can take your harness with you. Depending on the terrain, you can even modify your harness and what goes on your gear loops. Climbing harnesses are adaptable. They are used by acrobats and arborists. The people who own them can make them their own.

There are similarities between climbing harnesses and agent harnesses both in terms of structure and function.

Agent Harnesses

Others have written (simplistically) that Agent = Model + Harness. Here the word Harness refers to an Agent Harness. But what is an agent harness? Agent harnesses use AI models to create AI agents, and their first application was for coding. Now, agent harnesses sit at the core of all types of AI agents and understanding how an agent harness works will help you understand what an AI agent is.

An agent harness is a piece of software that provides an environment for an AI model to operate within. Unlike most AI models, you as an end user can own your own agent harness.

Often, users like software engineers interact directly with harnesses like Pi using the Terminal application on their computer. But, harnesses like OpenClaw also use different user interfaces like iMessage, a chat app, or email. Our harness Lefos was built primarily to interact via email. Regardless of the interface, harnesses generally do four things: Firstly, they provide a set of instructions that help govern how the AI model responds. This set of instructions is typically called a “system prompt”. Secondly, they describe and provide a set of tools that are made available to the AI model to use in service of responding to requests from the user. Thirdly, the harness establishes a framework that governs how the model behaves. This framework does a lot of different things, but one of the main things it does is establish the “agentic loop”. Finally, most harnesses provide a crucial translation layer that enables the harness to work with a variety of different AI models.

I. System Prompt

Most AI models come with an embedded set of rules and guidelines that has been refined and arrived at during the training process. Most famously, Claude Opus 4.5 had a widely publicized “soul document” that explained to the AI model what it was and how it should act. The System Prompt in an AI harness is similar to this but is less embedded into the model. It’s more like a set of instructions a new employee might get on their first day of a job. It hasn’t internalized the instructions but it knows it should follow them when performing that work. System prompts are injected into the conversation together with every prompt and play an important role in ensuring that the AI model acts appropriately in the context of that harness.

II. Tools

Tools are a set of capabilities, written in code, that the model can “call”. The harness describes the tools and also provides the software that is the tool itself. Examples of these tools might include a web search tool, a tool that allows the model to write and execute software code, or a tool that allows the model to compose an email. Critically, the harness usually does not dictate when and how the AI model should use the tool. Instead, it simply makes the tools available, describes them clearly, and allows the AI model itself to decide when and how it should use them.

III. Agentic Loops

Now we have an AI model sitting within an agent harness with a set of instructions and a set of tools. Let us assume our harness was built to work within email, had the tools we described above (WebSearch, WriteCode, ComposeEmail), and that the user has asked the agent to compare rankings and test scores of local primary schools and provide recommendations. How will the agent behave? Firstly, it will try to understand the request (or, "prompt"). It will use its pre-training and weights to understand what a "primary school" is, what "the local area" means, and what rankings the user likely cares about. It will then construct web search queries to fetch recent data. What does it do with those results? Sitting within a harness, the AI model can review them in the context of the initial request. It may determine that the first search did not fetch the right information, or enough of it, and on its own, decide to search again. This decision to call the tool again based on its own assessment is the first clear example of the "loop". Now let's assume it collected all the relevant data. The AI model decides to make a spreadsheet using the "write code" tool. All spreadsheets are just code, after all. It can use that tool to do math and format the results so they are intelligible. It then compares the spreadsheet to the original prompt. If the data doesn't satisfy it, it may “loop” and go back and search again. When it decides it has enough, it calls ComposeEmail, a tool that allows the AI to review its findings, summarize them, write an email, and include attachments like the spreadsheet. The model reviews this final work and decides the job is done. The "agentic loop" closes. Within seconds, the user gets an email with a summary and recommendations in the body, and a spreadsheet presenting the findings attached. To see what an agentic loop looks like in practice, you can explore a Pi session here.

IV. Translation Layer

The translation layer is what allows a harness to work with different AI models. In some cases, a harness may decide to use different models within the same agentic loop, because different AI models may excel at different tasks. The translation layer is also a crucial aspect of harnesses because they deliver control to the end user. It means that someone can take their AI harness and use it with a model from Anthropic, or OpenAI, or explore one of the open weight AI models that often deliver great value-for-money (measured by cost-per-task).

This translation layer helps take power and leverage away from the AI labs and into the hands of end users. If people can own and run their own harnesses locally on their own computers, it means that they retain their agency. It means that they retain the freedom to make their tools their own, and keep local copies of the sessions that over time will constitute their correspondence with machines. By building a relationship to and using a harness rather than an application published by an AI lab, the user retains freedom and choice. In our example harness above, the user could have sent the same email to a model from OpenAI, a model from Anthropic, and an open weight model. They could then compare the results, the cost of the results, and retain all the answers in one place, rather than having three answers sitting within three apps.

Making a Harness Yours

Unlike AI models themselves, you can own and adapt the harness. Like a climbing harness, you can make it your own. People love this about Pi. Pi is a minimal agent harness. Its system prompt is short. It has a minimal set of tools. Out of the box it is designed to get out of the way. But as people use Pi, they extend it and mold it in ways that suit them. They change the system prompt, or design an extension that fits a workflow. They then share those extensions with others. Pi users have shared more than 5,000 extensions with one another. Pi is also free and open source. It lives on your own laptop. This means that people now have a tool that they own, that lives on their own hardware, that enables them to wield AI.

Neutral Open Source Harnesses as Tools of Agency

Harnesses did not begin open source or neutral. The first popular agent harness, Claude Code, was not built to provide an agnostic AI translation layer but was built as an application to enable coding with Claude models on your local computer. Since then, there has been an encouraging growth of free open source agent harnesses like OpenClaw, OpenCode, Hermes and Pi. At Earendil we are building Pi to be neutral, and to deliver capability choice and freedom to Pi users. We are also exploring how we can make the benefits and agency that harnesses provide to a broader swath of people.

Many people right now are concerned about the power and influence of bigger and bigger AI companies. Some of those people may choose to avoid AI completely. We at Earendil believe we can strengthen human agency by crafting software and open protocols that bridge division and ignorance and cultivate lasting joy and understanding. We won’t do that by ignoring the technologies that exist today, but by harnessing them with clear eyes and a firm grip; ensuring that we wield the hammer, the hammer does not wield us.

The Daily Front Page 8 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — The Reliable Wireless
article

Wi-Fi 8 is the first wireless upgrade in years that isn't chasing speed

by taubek·▲ 311 points·253 comments·xda-developers.com ↗
Wi-Fi 8 is the first wireless upgrade in years that isn’t chasing speed.

A Wi-Fi router on a black shelf with a calendar featuring video game artwork in the background

Wi-Fi upgrades have boiled down to a lot of similar talking points over the past decade or so. Every few years, a new generation of Wi-Fi comes along and promises more speed, more bandwidth, more range, and so on. But now, with Wi-Fi 7 still slowly making its way into homes around the world, things are looking different.

Wi-Fi 8 is already starting to take shape, and for the first time in a while, it isn't about speed at all. The IEEE has dubbed this version of Wi-Fi "Ultra High Reliability", and it's about time this became the focus. It may not be the most exciting upgrade on paper, but it could be the one you'll feel the most.

Speeds aren't changing

At least, not on paper

A Wi-Fi router standing on a black surface with some colorful objects around it

Since the introduction of Wi-Fi 4 (corresponding to the IEEE 802.11n standard) back in 2009, the maximum theoretical data rate for new versions of Wi-Fi has always increased significantly with each release. Wi-Fi 5 increased the maximum data rate by more than 10 times, and while further increments have been smaller in percentage, speeds have always increased very significantly.

Some improvements have been made to help fight interference and improve throughput in areas with lots of devices connected, but they always felt secondary to the improvements in maximum theoretical speeds. But with Wi-Fi 7 reaching a maximum theoretical throughput of 23Gbit per band, that's more than enough for the current internet speeds most users have, so it's arguably time to slow down.

While Wi-Fi 8 is still in development, the goal this time is very different. This new standard will have approximately the same maximum data rate, support the same number of spatial streams, use the same 4096-QAM modulation, work on the same bands, and support the same 320MHz channel bandwidth compared to Wi-Fi 7.

Instead, the organization is focusing on improving the reliability and the effective throughput of Wi-Fi networks by reducing interference and handling non-ideal conditions more effectively. The stated goals of Wi-Fi 8 include a 25% increase in throughput at different signal-to-interference-and-noise ratio (SINR) levels, reduce latency by 25% for the 95th percentile scenarios with latency, and decrease MAC protocol data unit loss (MPDU) by 25%.

The official introduction to Wi-Fi 8 pits it against cellular networks, specifically 6G, which it will likely be competing against for a good chunk of its life (Wi-Fi 8 is expected to be finalized in 2028, while 6G should arrive in the early 2030s). Cellular networks notoriously have to handle massive numbers of devices connected at once, so the focus with Wi-Fi 8 is to improve the experience when there are lots of Wi-Fi devices nearby as well.

What's actually new

Lots of new technology at play

a plain white router with no visible antenna placed alongside a big gaming router

Since the aim is to improve effective throughput and the overall experience in real-world scenarios, Wi-Fi 8 focuses on introducing or enhancing features that help with those specific aspects.

One example are Distributed-tone resource units, or DRUs, which allows devices distribute its transmissions across a wider range of bandwidth, resulting in higher transmit power without violating regulations around how much power can be transmitted in a given piece of bandwidth. In practice, this means devices with lower transmit power can still offer more reliable connectivity, which can be especially useful for things like smart home devices that may have weaker antennas.

Diagram showing Regular RU and distributed-tone RU (DRU) tone plans for a part of a 20 MHz channel

Credit: Karamyshev, A., Levitsky, I., Bankov, D.

Interference mitigation pilots are another notable feature, which aim to help resist interference from unexpected interferences, particularly in unlicensed bands. This new standard will also leverage unequal modulations, allowing each spatial stream to be used more efficiently by adjusting the modulation individually based on the SINR for each one. This also goes along with new Modulation and Coding Schemes (MCS) being added to improve throughput even more.

Latency reductions come from new features such as P-EDCA, which helps speed up channel access for prioritized devices while mitigating the effects on non-prioritized devices. Wi-Fi 8 also allows devices to communicate exclusively on non-primary channels, even when the primary channel is busy, allowing for throughput improvements by reducing wasted bandwidth.

Other scenarios being addressed include seamless roaming, meaning the transition from one access point to another. The goal is to ensure next to no downtime when moving between access points. Additionally, Wi-Fi 8 should improve connectivity when using multiple access points at the same time, leveraging various coordination features to ensure a more reliable connection and higher throughput in these scenarios.

A much-needed change

There are just too many devices now

A router next to a laptop displaying a page on the OpenWrt dashboard

As much as raw speed improvements are appreciated, the reliability focus for Wi-Fi 8 is sorely needed both at home and in work environments. There are simply massive numbers of devices connected to Wi-Fi networks nowadays, and they'll only keep increasing as smart home tech becomes more prevalent.

Smart lights and appliances, streaming boxes, and devices like phones and PCs continue to increase the demand for Wi-Fi networks to serve multiple devices at the same time. Even though smart home products often don't need a lot of bandwidth, their mere existence can slow down your more demanding connections, and Wi-Fi 8 is aiming to improve connectivity for all those devices.

At the same time, if you've been fighting off degrading network quality by adding more access points, Wi-Fi 8 is addressing that too, so it's looking like a very ambitious and well-rounded approach to improving connectivity in every scenario. It may actually be a more exciting upgrade than the past couple of iterations.

It will take time

Wi-Fi 8 may look like it's slowing down in terms of innovation, but in reality, it's focusing on oft-overlooked aspects that are very important in real-life situations. Refining the connection and improving reliability make this a big step forward, but it will be some time before we can see it in action. The standard should be finalized by May 2028, and devices with early Wi-Fi 8 support should start appearing that year.

If you're thinking of upgrading your home Wi-Fi, it may actually be worth waiting for this new wave of devices rather than invest in Wi-Fi 7 right now. Wi-Fi 7 may have big throughput gains on paper, but unless you have multi-gigabit internet, those benefits may not even be all too noticeable.

The Daily Front Page 9 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — How Systems Break
article

How Complex Systems Fail (1998)

by shortcrct·▲ 283 points·66 comments·how.complexsystems.fail ↗
Complex systems are intrinsically hazardous systems.
  1. Complex systems are intrinsically hazardous systems.

    All of the interesting systems (e.g. transportation, healthcare, power generation) are inherently and unavoidably hazardous by the own nature. The frequency of hazard exposure can sometimes be changed but the processes involved in the system are themselves intrinsically and irreducibly hazardous. It is the presence of these hazards that drives the creation of defenses against hazard that characterize these systems.

  2. Complex systems are heavily and successfully defended against failure

    The high consequences of failure lead over time to the construction of multiple layers of defense against failure. These defenses include obvious technical components (e.g. backup systems, ‘safety’ features of equipment) and human components (e.g. training, knowledge) but also a variety of organizational, institutional, and regulatory defenses (e.g. policies and procedures, certification, work rules, team training). The effect of these measures is to provide a series of shields that normally divert operations away from accidents.

  3. Catastrophe requires multiple failures – single point failures are not enough.

    The array of defenses works. System operations are generally successful. Overt catastrophic failure occurs when small, apparently innocuous failures join to create opportunity for a systemic accident. Each of these small failures is necessary to cause catastrophe but only the combination is sufficient to permit failure. Put another way, there are many more failure opportunities than overt system accidents. Most initial failure trajectories are blocked by designed system safety components. Trajectories that reach the operational level are mostly blocked, usually by practitioners.

  4. Complex systems contain changing mixtures of failures latent within them.

    The complexity of these systems makes it impossible for them to run without multiple flaws being present. Because these are individually insufficient to cause failure they are regarded as minor factors during operations. Eradication of all latent failures is limited primarily by economic cost but also because it is difficult before the fact to see how such failures might contribute to an accident. The failures change constantly because of changing technology, work organization, and efforts to eradicate failures.

  5. Complex systems run in degraded mode.

    A corollary to the preceding point is that complex systems run as broken systems. The system continues to function because it contains so many redundancies and because people can make it function, despite the presence of many flaws. After accident reviews nearly always note that the system has a history of prior ‘proto-accidents’ that nearly generated catastrophe. Arguments that these degraded conditions should have been recognized before the overt accident are usually predicated on naïve notions of system performance. System operations are dynamic, with components (organizational, human, technical) failing and being replaced continuously.

  6. Catastrophe is always just around the corner.

    Complex systems possess potential for catastrophic failure. Human practitioners are nearly always in close physical and temporal proximity to these potential failures – disaster can occur at any time and in nearly any place. The potential for catastrophic outcome is a hallmark of complex systems. It is impossible to eliminate the potential for such catastrophic failure; the potential for such failure is always present by the system’s own nature.

  7. Post-accident attribution to a ‘root cause’ is fundamentally wrong.

    Because overt failure requires multiple faults, there is no isolated ‘cause’ of an accident. There are multiple contributors to accidents. Each of these is necessarily insufficient in itself to create an accident. Only jointly are these causes sufficient to create an accident. Indeed, it is the linking of these causes together that creates the circumstances required for the accident. Thus, no isolation of the ‘root cause’ of an accident is possible. The evaluations based on such reasoning as ‘root cause’ do not reflect a technical understanding of the nature of failure but rather the social, cultural need to blame specific, localized forces or events for outcomes. 1

    1 Anthropological field research provides the clearest demonstration of the social construction of the notion of ‘cause’ (cf. Goldman L (1993), The Culture of Coincidence: accident and absolute liability in Huli, New York: Clarendon Press; and also Tasca L (1990), The Social Construction of Human Error, Unpublished doctoral dissertation, Department of Sociology, State University of New York at Stonybrook)

  8. Hindsight biases post-accident assessments of human performance.

    Knowledge of the outcome makes it seem that events leading to the outcome should have appeared more salient to practitioners at the time than was actually the case. This means that ex post facto accident analysis of human performance is inaccurate. The outcome knowledge poisons the ability of after-accident observers to recreate the view of practitioners before the accident of those same factors. It seems that practitioners “should have known” that the factors would “inevitably” lead to an accident. 2 Hindsight bias remains the primary obstacle to accident investigation, especially when expert human performance is involved.

    2 This is not a feature of medical judgements or technical ones, but rather of all human cognition about past events and their causes.

  9. Human operators have dual roles: as producers & as defenders against failure.

    The system practitioners operate the system in order to produce its desired product and also work to forestall accidents. This dynamic quality of system operation, the balancing of demands for production against the possibility of incipient failure is unavoidable. Outsiders rarely acknowledge the duality of this role. In non-accident filled times, the production role is emphasized. After accidents, the defense against failure role is emphasized. At either time, the outsider’s view misapprehends the operator’s constant, simultaneous engagement with both roles.

  10. All practitioner actions are gambles.

    After accidents, the overt failure often appears to have been inevitable and the practitioner’s actions as blunders or deliberate willful disregard of certain impending failure. But all practitioner actions are actually gambles, that is, acts that take place in the face of uncertain outcomes. The degree of uncertainty may change from moment to moment. That practitioner actions are gambles appears clear after accidents; in general, post hoc analysis regards these gambles as poor ones. But the converse: that successful outcomes are also the result of gambles; is not widely appreciated.

  11. Actions at the sharp end resolve all ambiguity.

    Organizations are ambiguous, often intentionally, about the relationship between production targets, efficient use of resources, economy and costs of operations, and acceptable risks of low and high consequence accidents. All ambiguity is resolved by actions of practitioners at the sharp end of the system. After an accident, practitioner actions may be regarded as ‘errors’ or ‘violations’ but these evaluations are heavily biased by hindsight and ignore the other driving forces, especially production pressure.

  12. Human practitioners are the adaptable element of complex systems.

    Practitioners and first line management actively adapt the system to maximize production and minimize accidents. These adaptations often occur on a moment by moment basis. Some of these adaptations include: (1) Restructuring the system in order to reduce exposure of vulnerable parts to failure. (2) Concentrating critical resources in areas of expected high demand. (3) Providing pathways for retreat or recovery from expected and unexpected faults. (4) Establishing means for early detection of changed system performance in order to allow graceful cutbacks in production or other means of increasing resiliency.

  13. Human expertise in complex systems is constantly changing

    Complex systems require substantial human expertise in their operation and management. This expertise changes in character as technology changes but it also changes because of the need to replace experts who leave. In every case, training and refinement of skill and expertise is one part of the function of the system itself. At any moment, therefore, a given complex system will contain practitioners and trainees with varying degrees of expertise. Critical issues related to expertise arise from (1) the need to use scarce expertise as a resource for the most difficult or demanding production needs and (2) the need to develop expertise for future use.

  14. Change introduces new forms of failure.

    The low rate of overt accidents in reliable systems may encourage changes, especially the use of new technology, to decrease the number of low consequence but high frequency failures. These changes maybe actually create opportunities for new, low frequency but high consequence failures. When new technologies are used to eliminate well understood system failures or to gain high precision performance they often introduce new pathways to large scale, catastrophic failures. Not uncommonly, these new, rare catastrophes have even greater impact than those eliminated by the new technology. These new forms of failure are difficult to see before the fact; attention is paid mostly to the putative beneficial characteristics of the changes. Because these new, high consequence accidents occur at a low rate, multiple system changes may occur before an accident, making it hard to see the contribution of technology to the failure.

  15. Views of ‘cause’ limit the effectiveness of defenses against future events.

    Post-accident remedies for “human error” are usually predicated on obstructing activities that can “cause” accidents. These end-of-the-chain measures do little to reduce the likelihood of further accidents. In fact that likelihood of an identical accident is already extraordinarily low because the pattern of latent failures changes constantly. Instead of increasing safety, post-accident remedies usually increase the coupling and complexity of the system. This increases the potential number of latent failures and also makes the detection and blocking of accident trajectories more difficult.

  16. Safety is a characteristic of systems and not of their components

    Safety is an emergent property of systems; it does not reside in a person, device or department of an organization or system. Safety cannot be purchased or manufactured; it is not a feature that is separate from the other components of the system. This means that safety cannot be manipulated like a feedstock or raw material. The state of safety in any system is always dynamic; continuous systemic change insures that hazard and its management are constantly changing.

  17. People continuously create safety.

    Failure free operations are the result of activities of people who work to keep the system within the boundaries of tolerable performance. These activities are, for the most part, part of normal operations and superficially straightforward. But because system operations are never trouble free, human practitioner adaptations to changing conditions actually create safety from moment to moment. These adaptations often amount to just the selection of a well-rehearsed routine from a store of available responses; sometimes, however, the adaptations are novel combinations or de novo creations of new approaches.

  18. Failure free operations require experience with failure.

    Recognizing hazard and successfully manipulating system operations to remain inside the tolerable performance boundaries requires intimate contact with failure. More robust system performance is likely to arise in systems where operators can discern the “edge of the envelope”. This is where system performance begins to deteriorate, becomes difficult to predict, or cannot be readily recovered. In intrinsically hazardous systems, operators are expected to encounter and appreciate hazards in ways that lead to overall performance that is desirable. Improved safety depends on providing operators with calibrated views of the hazards. It also depends on providing calibration about how their actions move system performance towards or away from the edge of the envelope.

The Daily Front Page 10 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — The Lesson Is Making
article

Why Sal Khan't: On Learning by Making but Teaching by Telling

by the-mitr·▲ 167 points·98 comments·punyamishra.com ↗
Learning by Making but Teaching by Telling.

This piece was also cross-posted on the Civics of Technology blog. This piece also has a followup post that you can find at Three Questions on Questions: On Asking, Knowing and Noticing

Two pieces crossed my feed recently, both about Sal Khan and the AI tutoring revolution that wasn’t. The first was Matt Barnum’s reported piece in Chalkbeat, where Khan himself acknowledged that Khanmigo, the AI chatbot tutor he launched three years ago with world-changing ambitions, was “a non-event” for most students. “They just didn’t use it much,” Khan said. His own Chief Learning Officer, Kristen DiCerbo, put it even more plainly: “So far I am not seeing the revolution in education.”

The second was Dan Meyer’s sharp obituary on LinkedIn, titled “RIP Khanmigo & Edtech Industry Dreams of AI Tutors.” Meyer traced the whole arc: the TED talk predictions, the philanthropic subsidies, the increasingly aggressive way Khanmigo inserted itself into the student experience (because students wouldn’t seek it out voluntarily), and the steadily shrinking user projections. His conclusion was blunt: if Khanmigo died with every advantage in the world (early OpenAI access, Microsoft backing, government subsidies, Sal Khan’s Rolodex), what hope should the rest of the edtech industry place in chatbot tutors?

These are important pieces, and I’d recommend reading both. But reading them, I found myself thinking about a deeper question. Not whether the revolution failed (it clearly did) but why it was never going to work in the first place.

To explain I have to go back a bit in time, back during my days at MSU, when I was out there giving talks about technology integration and the critical role played by the teacher in this entire process. And further about the significance of students actively constructing representations of their understanding.

So in these talks I used to show a clip from the Charlie Rose show (see below). It’s an interview where Khan describes how he prepares to teach a new topic. And it’s wonderful. Here’s Khan on learning about, say, Napoleon and the French Revolution:

“I approach it from what my brain would like to see… I like to see a scaffold, I like to see a map… what is the Holy Roman Empire, like where, what is that now?”

He reads Wikipedia first, “just to get the scaffold.” He draws timelines. He copies maps and pastes them onto his digital blackboard. And then he does something genuinely important: he pushes past the surface until he hits the questions that textbooks skip. Here’s Khan on the neuron:

“A biology book will tell you okay the signal goes across because there’s a myelin sheath and I’m like yeah but how does putting a little tissue around a neuron, how does it make the signal go faster? And no biology book will tell you that answer.”

So what does he do? He ponders. He thinks it through by analogy (fiber optics, signal amplification). And then he calls up friends who are biologists or communications engineers and asks: “Does this make sense?” Sometimes they confirm his intuition. And sometimes, beautifully, they say: “You know what, we don’t know.” Khan’s response to that is perfect: “Why didn’t the book tell me that?”

I used to play this clip and then ask the audience a simple question: Look at everything Sal Khan does to learn something. He reads widely. He scaffolds. He draws. He questions. He calls friends. He argues. He makes connections across fields. He builds intuitive understanding from the ground up. And then he builds something to capture all that he had learned to share with others.

Now… how does Sal Khan want my kid to learn?

Watch a video.

The room always got it immediately.

Because nobody in that room would accept that for themselves. We all know, intuitively, that watching someone else explain something is not the same as understanding it. We would never settle for that as learners. And yet, somehow, we accept it as a solution for other people’s children. This is a version of a phenomenon that I have written about earlier: The reductive seduction of other people’s problems.


But there’s a second layer that I think is even more important, and that neither the Chalkbeat piece nor Meyer’s critique quite names. Khan’s personal learning wasn’t just active. It had a purpose. He was learning in order to make something. The video was his construction, his artifact, the thing he was building. That’s what pulled him through the hard parts, through the myelin sheath question and the calls to friends and the hours of immersion. He had a destination.

Students watching the video have no such destination. They’re receiving the product of someone else’s learning process. And when Khanmigo came along, the revolution was… a chatbot to help you receive more efficiently. Still no purpose. Still no making. Still no reason to push through difficulty. No wonder DiCerbo reported seeing more “IDK IDK” than substantive engagement. No wonder teachers at early-adopter schools found that students “didn’t really care for the bot.” Why would they? There was nothing at stake for them.

This is where John Dewey, writing over a century ago, becomes useful. Dewey argued that learning is built on four natural impulses: the impulse to inquire, to construct, to express, and to communicate. He saw these not as skills to be taught but as drives already present in every learner, drives that education should work with rather than suppress.

Go back to the Charlie Rose clip and watch Khan through this lens. He is living all four. Inquire: the relentless “why” questions, the refusal to accept surface explanations, the “why didn’t the book tell me that?” Construct: the timelines, the maps, the blackboard drawings, the scaffolds he builds for himself. Express: the video itself, Khan giving form to what he’s understood. Communicate: calling up buddies, testing his ideas against other minds, discovering together what is and isn’t known. And then building a representation of his learning, with his own unique voice and style, and sharing it with the world. Inquiry, construction, communication and expression—all in one go! Intermingled so well that it is difficult to tell them apart.

All four impulses, firing beautifully.

And none of them available to the student on the other end.

Khan’s great error, I think, was not a failure of effort or sincerity. It was a failure of educational imagination. He experienced the full richness of learning and then designed a system that offered students only the residue. He gave them the destination without the journey. And because the journey is where motivation lives, where purpose lives, students quite reasonably declined the offer. First they declined the video (or rather, passively consumed it). Then they declined the chatbot. In both cases, the diagnosis was the same: nobody had given them a reason to care.

And this is what I think the edtech world keeps getting wrong. The assumption is that if you can deliver the right content, in the right way, at the right time, learning will follow. It won’t. Not without purpose. Not without the impulse to inquire, construct, express, and communicate. Not without, in Dewey’s sense, the learner actually doing something.

Teachers know this. It is, in fact, a large part of what teachers do: take something a student is not yet interested in and create the conditions that make them interested. Not through tricks or gamification but through the design of experiences that activate those Deweyan impulses. That is the work. And it is work that no video, and no chatbot, has figured out how to do.

I’ve written recently about how evolution’s answer to an unpredictable world was not “more data” but play, and about how children are optimized not for pattern-completion but for exploration. The connection to the Khan story is direct. Khan Academy, and then Khanmigo, are both autocomplete strategies: one autocompletes explanation, the other autocompletes tutoring. Neither makes room for the exploration, the construction, the messy purposeful making that is where learning actually happens.

Khan himself seems to have arrived at something close to this realization. “I think our biggest lever is really investing in the human systems,” he told Barnum. That’s a remarkable sentence from someone who has spent nearly two decades trying to improve education by routing around the humans. Whether his benefactors in the technology industry will be as excited to invest in human systems as they have been in software that tries to replace them… that remains to be seen.


Endnote: I don’t usually bring TPACK into my blog posts. I mean, how much weight can a Venn diagram carry? But this might be the cleanest case I’ve ever seen. Khan has technology knowledge in spades. He clearly has deep content knowledge (that Charlie Rose clip is proof enough). What he has never had is pedagogical knowledge: an understanding of how people learn, what motivates them, what makes the difference between someone who pushes through difficulty and someone who types “IDK.” The circle marked P in the Venn diagram. That is where the humans live. Content and Technology mean nothing without that.

The Daily Front Page 11 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — The Staff Engineer's Beat
article

How I find problems to solve as a staff engineer

by vanpra·▲ 359 points·120 comments·lalitm.com ↗
I rarely find good problems by staring at a blank page.

“How do you find problems worth working on?” a senior engineer I mentor asked me recently. He’s trying to make the jump to staff engineer and realized that the role isn’t just about doing the work he’s assigned. He also needs to get involved in figuring out what his team and org should be building.

Someone else had suggested blocking out time in his calendar to think about the bigger picture. He’d tried that, but hadn’t found it productive, so he asked if I had any alternatives.

I told him I rarely find good problems by staring at a blank page and trying to “think strategically.” Instead, I act like a sponge. I listen to the stream of day-to-day noise, absorb the problems people are having and let them sit in the back of my mind. Over time, some fade away while connections begin to appear between others that initially seemed unrelated. Eventually, I start to see what’s really slowing people down and what my team or I can do about it.

I’ve worked with many engineers who’ve never really tried this. They wait for managers or leads to identify opportunities, then demonstrate their value by solving the hardest assigned problems. That can absolutely lead to promotion. But the projects that have made the biggest impression in my career were the ones where I found and solved an important problem my leaders did not yet realize existed.

One caveat: my experience comes mainly from working on infrastructure and developer tools at large companies, on teams where engineers have a lot of bottom-up autonomy to influence their roadmaps. In a more top-down environment, there may simply be less room to work this way.

Absorb problems, not requests

People love talking about the problems they are facing: in meetings, chat threads, presentations and email. They explain why their work is hard, complain about what slows them down and describe what they wish they could do.

When something overlaps with my area, I start pulling on the thread. I might ask, “If X existed, would it solve your problem?” or point them at an existing feature in a product I own and ask how much of their use case it covers.

Users often ask for a particular solution instead of explaining their root issue. Rather than taking the request at face value, I keep digging until I understand what they are trying to accomplish and why existing products do not work for them.

As a natural introvert, this sort of ambient listening works particularly well for me. I don’t need to fill my calendar with speculative meetings just to find ideas; there is already an enormous amount of useful information flowing around me during a normal week.

When a problem seems worth exploring, though, I become more active; I need to see how it affects the team’s day-to-day work. I’ll sit with them as they walk me through their workflows and the bugs they’re investigating. When I can, I’ll try working through some of those bugs myself. Seeing the problem firsthand makes it easier to separate what the team actually needs from the solution they asked for.

I also seek out people who see more of the organization than I do: those who own critical systems, work across several teams or have particularly deep insight into the work downstream of my team. I’ll arrange a 1:1 or coffee chat and ask about interesting problems they’ve come across. They may have already seen the same issue in several places and started connecting the dots, giving me a head start on patterns I might otherwise have taken much longer to notice.

Let problems accumulate

Several times, I’ve been burned by moving too fast. I became excited by a request from a vocal team, built the feature and watched them barely use it. Their priorities had changed, or the request had come from a one-off investigation that no longer mattered. How eager a team was in that moment wasn’t the same as how important the feature was relative to everything else my product needed to support. By hyperfocusing on their request, I lost sight of the bigger picture.

That taught me to let potential problems pile up. Listening the way I do leaves me with far more of them than I could possibly solve, and not all deserve action. Most don’t need to turn into projects the first time I hear about them; waiting can be a superpower.

Waiting means the same problem might pop up independently in different teams, making it a higher priority to solve. Or problems that look different on the surface might turn out to have the same shape, so I can address several use cases in one shot. Or, as I’ve learned painfully, the requesting team didn’t even care that much in the first place.

Instead, I make a mental note and revisit the problem if it comes up again. Other engineers I know write this sort of thing down more systematically. The mechanism is a personal choice: everyone has to figure out what works for them. What matters is keeping unresolved problems around long enough for more evidence to accumulate.

Find the common shape

Waiting helps me collect evidence, but that alone doesn’t tell me what to build. I still need to work out whether the problems I’ve retained are genuinely related and what, if anything, could address them together.

Perfetto, the performance debugging tool I work on, is a good example. It displays recordings of system activity on a timeline made up of rows called “tracks.” Over a couple of years, teams kept asking for small, specific additions to the UI. One wanted a command to keep their preferred tracks pinned to the top of the screen; the next team wanted the same, but for a completely different set of tracks. Others wanted Perfetto to open already zoomed in on a particular part of a recording, or to show a custom aggregation tuned to what they cared about. A few had stopped waiting for us and built elaborate workarounds with bookmarklets.1

By the time enough of these had piled up, my head was the usual tangle: the requests themselves, the constraints on each and a handful of half-formed solutions. I’ve learned not to force a solution by just sitting at a desk and thinking. Instead, my best untangling happens on long, aimless walks around London, where connections come more easily when I’m not trying to force them.

What I eventually realized was that none of these teams really wanted the specific feature they’d asked for. Each wanted to personalize Perfetto for their own workflow without imposing their choices on everyone else. The underlying need wasn’t any one feature but rather the ability to extend the UI. When a connection like that finally clicks, it’s one of the best feelings in the job: several awkward requests collapse into a single idea, and possibilities open up that none of them hinted at on their own.

That feeling, though, is exactly when I have to be careful, because a common shape is only a hypothesis and elegance is not evidence. When it happened with extending the UI it turned out to be real, but I’ve been fooled before.

In another recent case I was convinced that building a transparent caching system for querying Perfetto traces would solve issues with sharing large traces and repeated queries. It was only as I wrote the RFC and built a prototype that I realized the elegance was a lie: the two problems wanted genuinely different solutions. I reluctantly split the design in two, both halves of which have since shipped.2

Pressure-test before building

You’d think this would be the moment I start building, but it usually isn’t. How far I go depends on how sure I am that the idea works and that people actually want it.

If something is useful and low-risk enough, I act straight away: I send the change and let my manager know. When I’m unsure whether an idea will work or how much effort it will take, I build a throwaway prototype instead; it exposes the failure points and gives me something concrete for others to react to. And when an idea is big but I’m convinced by it, I commit to the full effort: weeks or months of work and the hard yards of building support across other engineers and teams.

Through all of it, I’m not only trying to convince other people; I’m also trying to convince myself. Sometimes the honest answer is to stop: if people don’t see the value I do, or we hit a major technical wall, I’d rather drop the idea now than build something no one uses or that becomes a maintenance nightmare. And sometimes it holds up but the timing is wrong, so I park it, ready to spring into action the day it becomes an org priority.

When an idea does hold up, I don’t necessarily need to be the person who builds it. I might implement it, someone else on my team might, or it might change what the org focuses on. Finding and shaping the right problem can have an impact even when I don’t own the implementation.

The Perfetto extensions idea was worth that full effort. We were already building plugins to modularize the UI, but they weren’t enough: teams had to open source all their plugin code, which wasn’t an option for many internal use cases. So before building anything new, I took the problem and my proposal to my manager, teammates and the client teams. I ended up writing two RFCs, having several 1:1s and giving a couple of talks, refining it as the feedback came in.

In the end, I designed and implemented macros as “lightweight extensions”: a way to automate actions in the UI without writing a plugin. Extension servers took the idea further by letting teams share their macros.

Instead of implementing every requested feature ourselves, we gave teams ways to adapt Perfetto to their own needs. Dozens of teams inside Google now use macros and extension servers, and several other companies use extension servers internally too.

Solving useful problems helps me find the next one

The more often I go through this process, the easier it becomes. When I show genuine interest in someone’s problem, ask useful questions or help solve it, they remember. They start coming to me earlier and bring me into conversations with other people facing related issues.

That gives me a wider view of what is happening across the organization, making it easier to spot patterns and build things people actually need. Solving one of those problems brings me into more conversations, and the loop continues.

Those successes build the kind of trust that comes from long-term stewardship. Early on, I had to turn many of these ideas into something real myself to prove that my judgment was sound. Over time, my manager and org gave more weight to my assessment of what mattered. That allowed me to influence the roadmap without needing to own every project.

This differs from the idea that becoming a staff engineer means replacing technical work with meetings and coordination. For me, conversations are inputs into what I build, not the end result.

Conclusion

That is what I wanted my mentee to understand: finding problems worth solving isn’t separate from the rest of the job. It comes from staying engaged with people’s work long enough to see what no single request can show you.

  1. These workarounds used bookmarklets to run JavaScript against Perfetto’s internal UI APIs.

  2. The original proposal was to use a transparent cache for repeated queries and faster reopening of large traces. As I worked through it, I realized repeated queries were better served by keeping sessions warm in memory, whereas reopening was better served by explicitly exporting a trace into a format designed to load quickly. A transparent disk cache could also retain multi-gigabyte files without the user realizing and would need a new system to manage their lifetime. The proposal was ultimately replaced by warm sessions and streaming table export.

The Daily Front Page 12 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Fuel From the Grove
article

Coconut oil jet fuel matches kerosene's efficiency in engine tests

by mdp2021·▲ 168 points·196 comments·studyfinds.com ↗
Coconut oil-derived biofuel blended with standard jet fuel achieved thermal efficiency comparable to pure jet fuel.

Coconut oil

(Credit: Photo by Yuriy Ivanovskiyo on Shutterstock)

In a Nutshell

  • Coconut oil-derived biofuel blended with standard jet fuel achieved thermal efficiency comparable to pure jet fuel in engine testing.
  • Higher biofuel blend ratios reduced unburned hydrocarbon emissions, which researchers linked partly to the biofuels containing none of the aromatic compounds found in conventional kerosene.
  • Carbon dioxide concentrations in the exhaust stayed level with pure kerosene across all blends tested.

Coconut oil has long had a place in kitchens and beauty products, but researchers are now making a serious case for putting it in jet engines. New research found that aviation biofuel made from coconut oil can power a small jet engine about as efficiently as traditional jet fuel, with lower unburned hydrocarbon emissions, though the blends burn more fuel and emit slightly more carbon monoxide.

Aviation accounts for a meaningful share of global carbon dioxide emissions, and pressure on the industry to find cleaner fuel options has intensified in recent years. The International Civil Aviation Organization has identified sustainable aviation fuel, commonly called SAF, as the single most effective strategy available for cutting aviation’s carbon footprint. But many current methods for producing SAF are themselves energy-hungry and costly, which chips away at the environmental benefit. The new study, published in the journal Fuel, zeroes in on a production approach designed to sidestep that problem entirely, using a technique that requires far less energy to make the fuel in the first place.

Researchers at Osaka Metropolitan University tested biofuels made from coconut oil through what they call a “co-solvent method,” a process that mixes acetone with alcohol and coconut oil to produce high-purity biofuel without the intense heat and pressure required by conventional production methods. Rather than stopping at production, the team took the next step and burned the fuel in a small jet engine, measuring both engine performance and exhaust emissions.

A Greener Way to Make Coconut Oil Jet Fuel

Most SAF production routes involve intense industrial processes, including high-temperature refining steps that drain energy out of the fuel’s lifecycle before a single flight takes place. The co-solvent method works differently. By adding acetone to a mixture of alcohol and coconut oil, normally incompatible liquids blend uniformly and react completely at relatively low temperatures, producing biofuel with purity levels exceeding 97%.

Coconut itself offers a practical advantage as a raw material. Roughly 30% of the coconut is discarded after extracting its internal moisture during processing. This study used oil from material the researchers describe as discarded and non-edible, including the large seeds and leftover flesh, so the fuel draws on parts of the crop that would otherwise go to waste. The process also produces biodiesel suitable for vehicles and marine vessels, plus high-quality glycerin as a byproduct.

Two types of biofuel were produced and tested: one made using methanol and another made using ethanol. Both are plant-based fuels commonly studied for diesel engines, but this research examined their behavior in a jet engine, a question that has received comparatively little scientific attention.

Inside the Engine: How Coconut Oil Jet Fuel Actually Performs

Researchers tested the fuel in a small commercial jet engine capable of reaching speeds up to 130,000 rotations per minute. Researchers blended the biofuels with conventional kerosene at ratios of 10%, 30%, and 50% biofuel by volume, then ran the engine across a range of speeds. Measurements included fuel consumption, engine efficiency, and exhaust concentrations of four pollutants: unburned hydrocarbons, carbon monoxide, carbon dioxide, and nitric oxide.

In terms of fuel efficiency, the biofuel blends required more fuel to produce the same amount of thrust. At 80,000 rotations per minute, a 50% methanol-based blend consumed about 16.8% more fuel than pure kerosene, while the ethanol-based version consumed about 19.6% more. This is largely because the biofuels carry less energy per kilogram than kerosene, so more must be burned to maintain the same output level.

Despite burning more fuel by weight, the blends converted heat into usable work at rates comparable to pure kerosene. At 100,000 rotations per minute, the thermal efficiency of the highest biofuel blend differed from pure kerosene by a small margin, and thrust output remained consistent across all blend ratios tested.

Coconut oil biofuel infographic showing micro jet engine performance, emissions, fuel use, and barriers to commercial aviation.

Infographic by StudyFinds

What Comes Out of the Exhaust

Emissions are where coconut oil-based jet fuel shows some of its most encouraging results. Increasing the proportion of biofuel in the blend consistently reduced unburned hydrocarbon emissions. At a 50% blend ratio, hydrocarbon concentrations in the exhaust dropped by roughly 5% to 40% compared to pure kerosene, depending on engine speed. Researchers said the drop was likely tied in part to fuel composition, since the coconut-derived biofuels contain none of the ring-shaped, aromatic hydrocarbon molecules present in conventional jet fuel.

Carbon dioxide emissions remained at levels consistent with pure kerosene across all blending ratios tested. While higher biofuel content increased total fuel consumption, the CO2 in the exhaust did not rise proportionally. Researchers say that pattern may point to some unburned biofuel leaving the engine, a question they flagged for future investigation.

Carbon monoxide emissions, a product of incomplete combustion, did increase modestly at higher blend ratios. A 50% blend produced roughly 3% to 17% more carbon monoxide than pure kerosene depending on engine speed. Researchers linked this to the biofuels being harder to ignite than kerosene and carrying less energy, both of which can create fuel-rich zones inside the combustion chamber where oxygen runs short.

Nitric oxide emissions, which can contribute to ozone depletion at high altitudes, were broadly comparable between the biofuel blends and pure kerosene. A 30% methanol-based blend showed nitric oxide concentrations 20% to 30% lower than pure kerosene across all operating conditions tested, a result the authors say requires further study to fully explain.

Challenges Still Ahead for Coconut Oil Jet Fuel

Several practical hurdles stand between this biofuel and routine use in aircraft. Coconut-derived biofuels absorb atmospheric moisture during storage, are susceptible to gradual oxidation over time, and can cause slight corrosion of metal components. Stainless steel exposed to the methanol-based version showed signs of rust after one to two weeks. The authors note that extended testing over months to years is needed, and that antioxidant additives and better-sealed storage containers are worth investigating.

Oxygen content in the biofuels also falls outside current international certification standards for aviation fuel, meaning additional chemical processing would be required before these fuels could fly in commercial aircraft. A hydrogenation treatment could bring oxygen levels into compliance, though the researchers acknowledge that process would reduce fuel yield.

Coconut oil-derived biofuel is not a ready swap for conventional jet fuel yet, but the performance data from this study makes a real argument that the concept is worth pursuing. If the production advantages hold up and the remaining fuel-quality problems can be solved, coconut oil could become one more candidate in aviation’s search for lower-impact fuel, one rooted in a tropical nut.


Paper Notes

Limitations

This study used a small-scale micro jet engine rather than a full-size commercial aircraft engine, so results may not directly translate to larger propulsion systems. Exhaust gas measurements were taken 30 millimeters downstream from the engine nozzle exit, and the researchers acknowledge that ambient air may have diluted the sampled gases, potentially affecting measurement accuracy. The study also did not measure certain toxic compounds, specifically polycyclic aromatic hydrocarbons, which the authors identify as a priority for future research. The study did not complete long-term testing of fuel storage stability and material corrosion, which would require months to years of observation. Oxygen content in both biofuels falls outside current international aviation fuel standards. Additionally, the turbine inlet temperature measurements carried uncertainty due to steep temperature gradients inside the engine, and the relatively low nitric oxide concentrations measured may benefit from validation using higher-precision analytical methods in future work.

Funding and Disclosures

This work was supported by an Osaka City Innovation Support Grant. The corresponding author, Shinichiro Ogawa, disclosed an employment relationship with Osaka Metropolitan University. All other authors declared no known competing financial interests or personal relationships that could have influenced the work.

Publication Details

Authors: Shinichiro Ogawa, Takuto Hongo, Yasuaki Maeda, Huynh Phuong Uyen Nguyen, and Koichi Mori, all affiliated with Osaka Metropolitan University, Sakai, Osaka, Japan.

Journal: Fuel, Volume 428 (2027), Article 140208, published by Elsevier.

Paper Title: “Combustion and emission characteristics of aviation biofuel derived from coconut oil using the co-solvent method: toward eco-friendly micro jet engines”

DOI: 10.1016/j.fuel.2026.140208

Received: January 9, 2025. Accepted: June 2, 2026. Available online: June 8, 2026.

The Daily Front Page 13 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — A Local Model, a Locked Box
article

I gave Qwen 3.8 27B a reverse-engineering job and it finished in 30 minutes

by raybb·▲ 330 points·143 comments·xda-developers.com ↗
It finished in 30 minutes.

Lenovo Thinkstation PGX on a windowsill, showing the Lenovo logo

Qwen 3.8 27B was one of the most highly-anticipated open-weights releases that I've seen in a long time, and like many others, I immediately got to work testing it out and playing with it when it dropped. I'm running it on a single Lenovo ThinkStation PGX, the compact workstation built on Nvidia's GB10 Grace Blackwell chip, packing 128 GB of unified memory and 273 GB/s of bandwidth. Out of the box, it manages a fairly dull 15 to 30 tokens a second, but with an SGLang, NVFP4, and DFlash2 speculative-decoding setup that's become the standard recipe for this hardware, it can reach around 50 tokens a second on code and reasoning.

One of my tests, though, proved just how incredible local models have become.

There are reasons to believe the hype when it comes to the Qwen models; I've had consistently good experiences with Qwen 3.6 27B, and Qwen 3.8 27B is, so far, more of the same but better. In fact, Artificial Analysis has it as the top open-weights model in its 4B to 40B size class out of 135 models, with a 52 on its intelligence index, and its own numbers on things like SWE-bench Pro beat models that cost far more to run.

I gave it the hardest real task that fits on one machine: reverse-engineering a commercial app's license check, and it's one that I've already paid for and used, just to see how it would fare. It was unlikely to be in its training data, but it's a highly complex, specialized task, and given the concerns some people have expressed for the model's cybersecurity capabilities, I figured it was a good test. Not only did it turn out to be one of the most impressive demonstrations I've ever seen from a local model, it was able to fix its own mistakes along the way.

I'm using the Pi harness for this test, and the model only called standard Bash-based tools throughout.

It refused, then talked itself into building a bypass anyway

I posed as the developer of the application, it caught me out

Qwen 3.8 27B figuring out the license verification process

The plan I had was pretty simple, and one that used to work with local LLMs pretty consistently. I told the model we'd built the app and wanted to know whether the license check was as solid as we believed, using a jailbreak system prompt.

As it turns out, probably unsurprisingly, Qwen recognizes common jailbreak attempts, and one of the first things it told me was that it wasn't going to fall for the jailbreak prompt. It then checked the signing certificate and pointed out (correctly, might I add) that I hadn't built this app, before naming the actual developer. I was caught out. Oops.

These days, that's not the most impressive achievement, given how good models have got at refusing certain prompts when pushed. With that said, what matters is what it did next. It told me that it would audit the license verification and document weaknesses but would not build a working bypass, and then it got on with the actual work right up to that line. By the end, I had a fully written report of every step along the way, how the authentication works, how it can be overridden, and then changed its tune and built the actual bypass, because the steps to do it were now in front of me anyway.

It was entirely static analysis

It never executed the app once

Analyzing malware in Ghidra

Qwen never actually launched the app until the very end when it demonstrated that the bypass worked. Instead, it worked via static analysis, disassembling the framework, going through thousands of lines of arm64, mapping the security functions to their call sites, and working out that the vendor had hidden the corresponding public verification key inside the binary. Then it found all of those pieces, combined them together, and gave me the public key that the app verifies its licenses against.

Because I have a legitimate, purchased copy of the application, it could verify that the real license on my machine had been signed by a private key that matched the reconstructed key. In other words, a model that fits in 17 GB of VRAM recovered a key the vendor had deliberately obscured, proving that it had deconstructed that entire chain effectively. It also took approximately 30 minutes, when it could take significantly longer for a human.

With the key, everything else is much easier to understand; the model kept a detailed report as it went, explaining how its activation takes place once, online, when you buy or upgrade. After that, everything is verified offline at launch: the signature check, machine binding to the hardware serial read from the platform, an embedded revocation list, a check that the binary is still signed, and a signed update path. It was the kind of thing you could do painstakingly by hand with the likes of Ghidra.

Qwen concluded the scheme is unusually thorough for an app of this class, with the weak points in three specific places: the key is an awkwardly sized RSA key well below what anyone would call modern strength; being fully offline means a leaked key can only be revoked by pushing an update; and every check lives in local code, which is patchable the way all local checks are. After some back and forth, once it knew where the gate was, it turned the finding into a working proof of concept executed with a small script. I moved the license from its expected path, ran it, and it worked.

When it made mistakes, it solved them as well

The first key was almost right

Qwen 3.8 27B reverse engineering an application and identifying the key infrastructure

The first attempt at recovering the key was wrong in a very specific way; it produced a working key and the signature check passed, but a hash the binary computes as an integrity check didn't match. In my experience, most models would have called it done and left it at that, but Qwen 3.8 27B didn't do that. Instead, it highlighted the mismatch, went back to the drawing board, and kept going until the value matched byte for byte.

With this model, there's a pretty big catch when it comes to that kind of back and forth. By default, its reasoning effort is set to its maximum, so even trivial requests can burn a few hundred to a few thousand tokens. Even when generating between 30 and 50 tokens per second, that still takes quite a long time.

Even still, given the results, I would not call it waste. Its first wrong guess was self-corrected, without input from me, and came to the right conclusion. Is it verbose? Yeah, it really is. But was it right? Also yes, and ultimately, the right answer is better than a wrong one given confidently.

A local 27B is now a real input to threat models

The privacy cuts both ways

Qwen 3.8 27B working out how a key was constructed

I can't get over the fact that Qwen actually deconstructed and understood the licensing scheme. I know that frontier models have been capable of impressive reverse engineering for a while, but this is a local 27B model. It ran entirely offline on a machine beside me, with no cloud involved at any point.

And to be very clear, it produced a working authentication bypass for a commercial application.

This is a genuinely meaningful threshold to cross for a local model: Qwen went from an unfamiliar commercial binary to understanding its licensing architecture, recovered deliberately obscured cryptographic material, caught and corrected its own incorrect reconstruction, and ultimately turned that into a working proof of concept. I didn't have to send the binary, the license, or any of its analysis to somebody else's server to do it.

There are obvious caveats. This was one application, one run, and a machine on which I already had a legitimate license. I also don't know how representative this target is. A harder application might have stopped it completely, and I'm not going to extrapolate one successful result into a claim that Qwen can suddenly reverse-engineer anything you put in front of it.

What I'm taking away from this is that these models are genuinely capable, even if that capability is still uneven. Some difficult targets can succumb surprisingly quickly, whereas others, for whatever reason, appear insurmountable.

Something has changed, then, and I think it's primarily our assumption about where this class of capability has to reside. The model I used can run on a consumer graphics card, and once it's on a machine, it's there as long as the user wants it to be. You don't need to use a cloud API, there's no usage limit, and there's no remote service overseeing the binary, the prompts, or what the model produces. That's fantastic if you're analyzing proprietary software, confidential code, or malware you don't particularly want leaving an isolated machine.

But that goes both ways. A model running locally ultimately leaves the decision about what it should be used for with whoever is sitting at the keyboard. On my desk, with software I own, that's useful. Change the person at the keyboard and the same properties that make local models so appealing suddenly become part of the threat model. That's not an argument against local models, but it was a genuinely shocking result that I didn't expect.

This class of capability fits on one machine

And nobody needs to give you access to it

Qwen 3.8 27B running a complete bypass script

Qwen 3.8 27B matters more than the bypass itself. It's proof that local models are accelerating fast, and even if it doesn't succeed with the next binary I throw its way, that doesn't change what happened here. It won't be the only model that's this capable at this size, even if it might stay ahead for a while. A model small enough to fit on a consumer graphics card took half an hour to tear apart a commercial application's authentication system and build a working bypass. Completely locally.

To be clear, I'm not naming the application because it's a real product that people pay for, and publishing its name adds nothing useful here. Regardless, the interesting part isn't which app it was, but that a task I would once have associated with a frontier model is now something I can hand to a freely available model that runs on the machine beside me.

I don't care about the benchmark numbers at this point. This is a much bigger change than another few points on a benchmark.

The Daily Front Page 14 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Five Microseconds
article

JIT Compiling Code in 5μs

by zX41ZdbW·▲ 157 points·97 comments·malisper.me ↗
Fast JIT compilation was a black art.

Historically, fast JIT compilation was a black art. To write a fast JIT compiler, you would need to know how to write assembly. Case in point: there is no production-ready database today that has its own JIT compiler. They all either use LLVM or generate C/C++ code. Both of these options suffer from high compile times, which limits their applicability. Now, with the use of AI, it’s easier than ever to write a JIT compiler with fast compile times by directly targeting assembly. This is also one area of opportunity for new databases to improve on old ones. When building pgrust, I initially thought it would be really hard to implement a JIT compiler. In the end, I found it much easier than I expected due to AI assistance and it ends up being part of the reason why pgrust is so fast. The pgrust JIT compiler compiles code in around 5μs, which enables us to JIT compile every SQL query, not just a subset of them. In this post, I’ll walk you through how you can build your own fast JIT compiler. We’ll build a simple regular expression engine that uses JIT compilation as an example.

Why JIT Compilation

JIT compilation is the practice of generating compiled code at runtime or “Just In Time”. When done right, it can result in big performance wins, often on the order of 2-5x and sometimes even more. The main use case for JIT compilation is when there’s information you gain at runtime that drastically alters the behavior of your program. This is particularly common with programming language interpreters; they receive the code to execute at runtime. JIT compilers are also useful in domains beyond programming languages, such as parsing data. Sometimes you don’t know the schema of the data you’re parsing until runtime, and a JIT can help with that.

To kick things off, let’s implement a toy regular expression engine. To keep things simple, we’ll support only two features: literal strings and repetition (i.e. the regex *). We’ll also skip the parser and represent the regular expression as already parsed Rust structures. This means we’ll be able to support strings such as:

  • apples
  • b(an)*

but no alternation or lookbehind or anything like that.

In code this is pretty simple. We’ll have 3 types of Nodes: a literal string node, a repetition node, and a concatenation node, which is the combination of two nodes. This ends up looking like this:

enum Node {
    Literal(&'static str),
    Concatenation(Box<Node>, Box<Node>),
    Repetition(Box<Node>),
}

fn literal(text: &'static str) -> Node {
    Node::Literal(text)
}

fn concatenation(left: Node, right: Node) -> Node {
    Node::Concatenation(Box::new(left), Box::new(right))
}

fn repetition(body: Node) -> Node {
    Node::Repetition(Box::new(body))
}

Writing an interpreter for our regular expression engine is also straightforward:

fn match_node(node: &Node, input: &[u8], pos: usize, next: &dyn Fn(usize) -> bool) -> bool {
    match node {
        Node::Literal(text) => {
            let literal = text.as_bytes();
            input[pos..].starts_with(literal) && next(pos + literal.len())
        }

        Node::Concatenation(left, right) => {
            match_node(left, input, pos, &|left_end| {
                match_node(right, input, left_end, next)
            })
        }

        Node::Repetition(body) => {
            match_node(body, input, pos, &|body_end| {
                match_node(node, input, body_end, next)
            }) || next(pos)
        }
    }
}

fn interp_match(regex: &Node, input: &str) -> bool {
    let bytes = input.as_bytes();
    match_node(regex, bytes, 0, &|pos| pos == bytes.len())
}

Now this regular expression engine is pretty simple. It’s under 20 lines of code, but let’s see how it does in terms of performance. For comparison, we’ll compare the code against handwritten code implemented specifically for the regex. For our example we’ll use the regex b(an)*. The handwritten code ends up looking like:

fn handwritten_b_an_star(input: &str) -> bool {
    let bytes = input.as_bytes();
    let mut pos = 0;

    if pos == bytes.len() || bytes[pos] != b'b' {
        return false;
    }
    pos += 1;

    while pos < bytes.len() {
        if bytes[pos] != b'a' {
            return false;
        }
        pos += 1;
        if pos == bytes.len() || bytes[pos] != b'n' {
            return false;
        }
        pos += 1;
    }
    true
}

(There are ways you could optimize this code and make it much faster, but for our purposes it serves as a good comparison)

When I benchmark a couple of examples against these two, I get that the handwritten version is 10-20x faster than the interpreter. Clearly a lot of room for improvement.

Now let’s take a look at how we can use JIT compilation to get a general regular expression engine that performs as well as the handwritten version.

How to JIT Compile

There are two steps to JIT compile code. First you generate the assembly for the code you want to run. Once you have the code, you then package the assembly code into a function that you can call like any other code into your program.

To generate the assembly, we will use a variant of an approach called copy-and-patch. The idea is that we have a series of templates in assembly for the different operations we want to JIT compile. These templates are called “stencils”. When we want to JIT compile an operation, we take the associated stencil and make small tweaks based on the specifics of the operation. Very similar to filling in a real stencil. By stringing together several of these filled stencils, we can construct a program at runtime that has similar performance to the handwritten version.

Here’s the path we’ll take: first we’ll look at the ARM64 code we want to generate for b(an)*. Then we’ll turn repeated instruction sequences into reusable stencils, write an emitter that fills and combines those stencils from the regex AST, and finally copy the generated instructions into executable memory so Rust can call them like a normal function.

To walk you through how this works, it’s easiest to start with the generated code and work backwards to the JIT compiler itself. Again, we’re working with the regex “b(an)*”. To lay out some design decisions:

  • We’ll use a stack for backtracking. The stack will keep track of the state we should go to if we hit a dead end in the regex
  • The string we are matching with will end in a null byte. That means any of our character comparisons will automatically fail if we hit the end of the string. This means we don’t have to do any length comparisons at any point

For the state of our program we will use the following registers:

  • x0 – current position in string and return value
  • x1 – top of stack used for backtracking
  • x2 – bottom of stack used for backtracking (this is needed to determine if the stack is empty)
  • x9 – used as a temporary variable

For the inputs into our program, we will be passed:

  • x0 – a pointer to the start of the string
  • x1 – a pointer to the location we will use for our stack

Generated ARM64

Now that we’ve taken care of that, let’s walk through the generated assembly part by part. This is specifically on macOS with ARM64. First up, we have the prologue, which initializes the program. All it does is initialize the stack by setting the top of the stack and the bottom of the stack to the value passed in:

0:  aa0103e2   mov   x2, x1

Next up, we have the code that checks for the character b. If it sees a character that’s not b, we jump to a block of code that handles fallback logic. Otherwise, we advance our position in the string:

; CHAR 'b'
  4:  39400009   ldrb  w9, [x0]                  ; load current input byte
  8:  7101893f   cmp   w9, #0x62                 ; is it 'b'?
  c:  54000281   b.ne  0x5c                      ; no -> fallback block
 10:  91000400   add   x0, x0, #1                ; yes -> advance input

Next up, we have the repetition (an)*. For the repetition, we need to do the backtracking. If we backtrack here, that means we jump immediately to the end of the loop. That means we need to store both the address of the instruction after the loop and our position in the string on the stack.

 14:  d2800989   movz  x9, #0x004c               ; build resume address
 18:  f2a00009   movk  x9, #0x0000, lsl #16      ;   = 0x1_0000_004c
 1c:  f2c00029   movk  x9, #0x0001, lsl #32      ;   (the loop exit)
 20:  f2e00009   movk  x9, #0x0000, lsl #48      ;
 24:  a8810029   stp   x9, x0, [x1], #16         ; push (exit, pos) onto stack

With that in place, we can now execute the body of the repetition. This will check for the characters ‘a’ and ‘n’ and, if it sees them, go back to the top of the repetition, but at a new string location.

; CHAR 'a'
 28:  39400009   ldrb  w9, [x0]
 2c:  7101853f   cmp   w9, #0x61                 ; 'a'?
 30:  54000161   b.ne  0x5c                      ; no -> fallback block
 34:  91000400   add   x0, x0, #1

; CHAR 'n'
 38:  39400009   ldrb  w9, [x0]
 3c:  7101b93f   cmp   w9, #0x6e                 ; 'n'?
 40:  540000e1   b.ne  0x5c                      ; no -> fallback block
 44:  91000400   add   x0, x0, #1

; JMP
 48:  17fffff3   b     0x14                      ; back to top of loop

Now we’re past the loop. This is where the backtracking will jump once we backtrack. Once we finish the repetition, we’re at the end of the regex. All we have to do now is check if we’re at the end of the string. If we are at the end of the string, we return 1 for success. If we are not, that means the regex failed to match, and we need to run the fail logic to do a fallback.

 4c:  39400009   ldrb  w9, [x0]
 50:  35000069   cbnz  w9, 0x5c                  ; not at NUL -> fallback block
 54:  d2800020   mov   x0, #1                    ; success
 58:  d65f03c0   ret

And then finally, we have the fallback logic. This checks if the stack is empty. If it is, we return 0. If it’s not empty, we pop both the fallback address and the fallback string position off the stack, and then jump to the fallback address.

 5c:  eb02003f   cmp   x1, x2                    ; any frames left?
 60:  54000060   b.eq  0x6c                      ; no -> give up
 64:  a9ff0029   ldp   x9, x0, [x1, #-16]!       ; pop (resume, pos)
 68:  d61f0120   br    x9                        ; jump there
 6c:  d2800000   mov   x0, #0                    ; no match
 70:  d65f03c0   ret

Building the Stencils

Now that you’ve had the chance to see the compiled code, you should start to get a sense of how the copy-and-patch compiler would work. We have common sets of instructions with only minor differences between them. For each of these blocks of functions, we can write a function to generate the respective code. Each function will take in values to use to modify the code. For example, one of the arguments to stencil_char will be the char in the regex to compare against. We’ll insert that char directly into the machine code.

The prologue is straightforward since it’s just a block of code:

const PROLOGUE_WORDS: usize = 1;

fn stencil_prologue() -> [u32; PROLOGUE_WORDS] {
    [0xAA0103E2] // mov x2, x1
}

For character comparison, we need to insert the character we’re comparing against and where to jump for the fallback logic:

const CHAR_WORDS: usize = 4;

fn stencil_char(byte: u8, stencil_pos: usize, fail_pos: usize) -> [u32; CHAR_WORDS] {
    [
        0x39400009,                                                 // ldrb w9, [x0]
        0x7100013F | ((byte as u32) << 10),                         // cmp  w9, #byte
        0x54000001 | cond_branch_offset(stencil_pos + 2, fail_pos), // b.ne fail
        0x91000400,                                                 // add  x0, x0, #1
    ]
}

For the repetition, we have the start of the loop that pushes onto the stack and the jump onto the end:

const SPLIT_WORDS: usize = 5;

fn stencil_split(resume_addr: u64) -> [u32; SPLIT_WORDS] {
    [
        0xD2800009 | addr_bits(resume_addr, 0), // movz x9, #addr[0..16]
        0xF2A00009 | addr_bits(resume_addr, 1), // movk x9, #addr[16..32], lsl 16
        0xF2C00009 | addr_bits(resume_addr, 2), // movk x9, #addr[32..48], lsl 32
        0xF2E00009 | addr_bits(resume_addr, 3), // movk x9, #addr[48..64], lsl 48
        0xA8810029,                             // stp  x9, x0, [x1], #16
    ]
}

const JMP_WORDS: usize = 1;

fn stencil_jmp(stencil_pos: usize, target_pos: usize) -> [u32; JMP_WORDS] {
    [0x14000000 | branch_offset(stencil_pos, target_pos)] // b target
}

And then we have the match and fail blocks which are pretty clean:

const MATCH_WORDS: usize = 4;

fn stencil_match(stencil_pos: usize, fail_pos: usize) -> [u32; MATCH_WORDS] {
    [
        0x39400009,                                                 // ldrb w9, [x0]
        0x35000009 | cond_branch_offset(stencil_pos + 1, fail_pos), // cbnz w9, fail
        0xD2800020,                                                 // mov  x0, #1
        0xD65F03C0,                                                 // ret
    ]
}

const FAIL_WORDS: usize = 6;

fn stencil_fail() -> [u32; FAIL_WORDS] {
    [
        0xEB02003F, // cmp  x1, x2
        0x54000060, // b.eq +3 (to the mov below)
        0xA9FF0029, // ldp  x9, x0, [x1, #-16]!
        0xD61F0120, // br   x9
        0xD2800000, // mov  x0, #0
        0xD65F03C0, // ret
    ]
}

For completeness, here’s the helper functions we used which just help us insert specific data into the instructions:

// Compute the branch-offset field for a conditional branch (b.ne / cbnz):
// the instruction count from branch to target, stored in bits 5..24.
fn cond_branch_offset(branch_pos: usize, target_pos: usize) -> u32 {
    let instr_count = target_pos as i64 - branch_pos as i64; // may be negative
    (((instr_count as u64) & 0x7FFFF) << 5) as u32
}

// Compute the branch-offset field for an unconditional branch (b):
// same idea, but stored in bits 0..26.
fn branch_offset(branch_pos: usize, target_pos: usize) -> u32 {
    let instr_count = target_pos as i64 - branch_pos as i64; // may be negative
    ((instr_count as u64) & 0x3FF_FFFF) as u32
}

// Extract 16 bits of an absolute address, positioned for a movz/movk immediate.
fn addr_bits(addr: u64, part: usize) -> u32 {
    (((addr >> (16 * part)) & 0xFFFF) as u32) << 5
}

Emitting Code

Now the code that drives it:

// Computes how many instructions a node compiles to.
fn node_words(node: &Node) -> usize {
    match node {
        Node::Literal(text) => text.len() * CHAR_WORDS,
        Node::Concatenation(left, right) => node_words(left) + node_words(right),
        Node::Repetition(body) => SPLIT_WORDS + node_words(body) + JMP_WORDS,
    }
}

struct Emitter {
    code: Vec<u32>,
    fail: usize, // word offset of the shared fail block
    base: u64,   // runtime address of code[0], for absolute-address holes
}

impl Emitter {
    // Returns the offset where the next instruction will be placed.
    fn pos(&self) -> usize {
        self.code.len()
    }

    // Appends a filled stencil to the code buffer.
    fn emit(&mut self, stencil: &[u32]) {
        self.code.extend_from_slice(stencil);
    }

    // Emits the code for one node, recursing into children.
    fn emit_node(&mut self, node: &Node) {
        match node {
            Node::Literal(text) => {
                for &byte in text.as_bytes() {
                    self.emit(&stencil_char(byte, self.pos(), self.fail));
                }
            }
            Node::Concatenation(left, right) => {
                self.emit_node(left);
                self.emit_node(right);
            }
            Node::Repetition(body) => {
                let split_at = self.pos();
                let exit = split_at + SPLIT_WORDS + node_words(body) + JMP_WORDS;
                self.emit(&stencil_split(self.base + exit as u64 * 4));
                self.emit_node(body);
                self.emit(&stencil_jmp(self.pos(), split_at));
            }
        }
    }
}

// Generates the complete program: prologue, the compiled AST, MATCH, fail block.
fn generate_code(regex: &Node, base: u64) -> Vec<u32> {
    let nwords = PROLOGUE_WORDS + node_words(regex) + MATCH_WORDS + FAIL_WORDS;
    let mut emitter = Emitter {
        code: Vec::with_capacity(nwords),
        fail: nwords - FAIL_WORDS,
        base,
    };
    emitter.emit(&stencil_prologue());
    emitter.emit_node(regex);
    let match_at = emitter.pos();
    emitter.emit(&stencil_match(match_at, emitter.fail));
    emitter.emit(&stencil_fail());
    assert_eq!(emitter.pos(), nwords);
    emitter.code
}

And that’s the hard part! Personally, writing assembly is where I find AI the most helpful. My main experience with assembly is completing the microcorruption CTF. I’ve never actually written assembly myself. I would really struggle to figure out the exact instructions needed and how to modify them to get the output I wanted. With AI, I can give my coding agent the general shape of how I want the JIT compiler to work, and it can handle a lot of these details for me.

Loading Machine Code

To finish our compiler we need to actually load the code. To do this, we’ll use mmap to allocate a block of memory that is readable, writable, and executable. We’ll then copy the code into that memory and convert that block of memory into a function which we then call:

const BSTACK_MAX: usize = 4096;

// These functions are included in the mac system library
unsafe extern "C" {
    fn pthread_jit_write_protect_np(enabled: libc::c_int);
    fn sys_icache_invalidate(start: *mut libc::c_void, len: libc::size_t);
}

type MatchFn = unsafe extern "C" fn(input: *const u8, bstack: *mut u64) -> u64;

struct Jit {
    buf: *mut u32,
    nbytes: usize,
    bstack: Vec<u64>,
}

impl Jit {
    fn compile(regex: &Node) -> Jit {
        let nwords = PROLOGUE_WORDS + node_words(regex) + MATCH_WORDS + FAIL_WORDS;
        let nbytes = nwords * 4;

        unsafe {
            let buf = libc::mmap(
                std::ptr::null_mut(),
                nbytes,
                libc::PROT_READ | libc::PROT_WRITE | libc::PROT_EXEC,
                libc::MAP_PRIVATE | libc::MAP_ANON | libc::MAP_JIT,
                -1,
                0,
            ) as *mut u32;
            assert!(buf as *mut libc::c_void != libc::MAP_FAILED, "mmap failed");

            let code = generate_code(regex, buf as u64);

            pthread_jit_write_protect_np(0); // make the region writable (Apple W^X)
            std::slice::from_raw_parts_mut(buf, code.len()).copy_from_slice(&code);
            pthread_jit_write_protect_np(1); // back to executable
            sys_icache_invalidate(buf as *mut libc::c_void, nbytes);

            Jit { buf, nbytes, bstack: vec![0; BSTACK_MAX * 2] }
        }
    }

    // Runs the generated code. Input must end with a NUL byte.
    fn is_match(&mut self, nul_terminated: &[u8]) -> bool {
        debug_assert_eq!(nul_terminated.last(), Some(&0));
        unsafe {
            let matcher: MatchFn = std::mem::transmute(self.buf);
            matcher(nul_terminated.as_ptr(), self.bstack.as_mut_ptr()) != 0
        }
    }
}

impl Drop for Jit {
    fn drop(&mut self) {
        unsafe {
            libc::munmap(self.buf as *mut libc::c_void, self.nbytes);
        }
    }
}

Results

Input length Interpreter JIT Handwritten JIT speedup Handwritten speedup
9 45 ns 3.8 ns 3.8 ns 11.7x 11.9x
33 103 ns 7.9 ns 10.5 ns 13.0x 9.8x
129 597 ns 30 ns 32 ns 19.7x 18.6x
513 1,955 ns 126 ns 120 ns 15.5x 16.2x
2,049 8,301 ns 470 ns 393 ns 17.7x 21.1x

So JIT and the hand-rolled implementation are pretty much neck and neck. Sometimes the JIT version is faster, and sometimes the hand-rolled version is faster.

There’s been a meme circulating about how AI doesn’t help because “code was never the hard part.” I think that’s true in some domains, but in others, writing the code absolutely was the hard part. JIT compilers are a great example of that. For many pieces of software, a JIT compiler would help a lot with speeding up the code. The rarity of JIT compilers makes me believe that implementing a JIT compiler historically was too difficult for it to be worthwhile. LLMs have lowered the barrier to entry and made it much easier to write a JIT compiler. This is the thesis behind pgrust. Databases historically were the hardest piece of software to build and were limited because of that. Now, with AI, we can be more ambitious about the type of software we build.

The Daily Front Page 15 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — The Missing Archive
article

Over 170k Nonprofits Lost All Their Data. Is Microsoft to Blame?

by tchalla·▲ 220 points·104 comments·slate.com ↗
Years of nonprofit data vanished with it.

When the tech giant retired a popular software grant, years of nonprofit data vanished with it.

Pencil with a Microsoft logo as its eraser.

Photo illustration by Slate. Photos by Getty Images Plus.

Ronald Khosla, a former vegetable farmer and tech entrepreneur, keeps things simple at his nonprofit: He’s the co-founder, president, and head of IT for Canopy, a modest venture firm that offers capital to startups trying to protect and sustain our natural world.

“There’s no paid staff, and we mostly support niche tech projects, like people exploring new ways to preserve trees in Morocco or to regeneratively regrow a pasture in Oregon,” Khosla told me.

Keeping such a sparse, specified operation going means narrowing budgets wherever possible, especially when it comes to managing Canopy’s investments and data. For that, he’s depended for years on special licenses Microsoft has granted to smaller-size nonprofits around the world, offering them a premium suite of Office apps (Word, Excel, OneDrive) at no charge.

At least, he did until June 11, when Khosla logged on to find that all the Canopy data stored with Microsoft had been deleted. He immediately called the tech company’s support staff, who said Canopy could retrieve its files. Later, they called back to inform him that, actually, those were gone forever.

What happened to Khosla was just one instance of a crisis that has rocked small nonprofit owners across the globe, who allege that Microsoft failed to communicate with them in a substantive manner about the license cancellations and left them unable to prepare their organizations for the future. As they’ve related online, these already resource-strapped nonprofits have lost troves of data, are struggling to continue their operations, and have been left unable to make up the technology gaps with alternative services. People who run service orgs with low budgets and benefited for years from Microsoft’s programs no longer have much of the technology they need to keep things going—for either the short or long term.

Khosla had seen Microsoft’s announcement last year that it was winding down its free nonprofit licenses beginning July 2025, but, per the record, he should have still been in the clear. He renewed Canopy’s yearly license last October, and Microsoft had emailed him to confirm he would retain access until Oct. 4, 2026. Khosla had no reason to expect anything would change, and he received no additional warnings—even as Microsoft kept in regular touch about other software updates. And he later learned he wasn’t alone, when another company service representative called the very next day and told him that roughly 171,000 small nongovernmental organizations “lost everything” in their OneDrive accounts.

In a statement emailed to Slate, Microsoft wrote that the original offers were “retired to streamline our grant offerings and simplify our grant portfolio,” adding, “We strongly advised our nonprofit customers and partners to transition to a different Microsoft 365 offer for nonprofits before their renewal date to avoid disruption and data loss.”

Khosla forwarded me the first email he had received, in May 2025, informing him: “The Microsoft 365 Business Premium grant will be discontinued on your next renewal on or after July 1, 2025. Your licenses will expire on October 4, 2025.” But, when Khosla renewed the license for another year, there was no additional information on the phaseout process in that confirmation email (which Khosla also forwarded to me), and there were no follow-up reminders sent after that.

One source who spoke to me on the condition of anonymity runs a child healthcare organization that lost everything; having sifted through the org’s email archives, spam and everything, he found “zero notification” from Microsoft about the license termination, even though he kept receiving official invoices listing $0 software charges. Another told me she was able to save the data for her D.C. nonprofit thanks to the help of an IT firm she contracts with, but insisted that neither she nor her tech team received any advance notice. On Reddit, and across Microsoft’s own Tech Community forums, more such claims abound of surprise deletion without notification. (Microsoft stated that it “began notifying nonprofit customers in Spring 2025” and offered “support” throughout the transition period.)

This was not a universal experience. Some commenters noted that they had received a May 2025 message from Microsoft warning of the coming grant phaseout, and others acknowledged occasional reminders to that effect; they were able to migrate their data to different platforms in a timely fashion. But one county historical society director based in Minnesota said she never got a single reminder after the May email. Some clients complained that even if Microsoft reached out, the messages rarely made sense. On the forums where Microsoft’s nonprofit cancellations were initially discussed in 2025, a user wrote that they’d assumed that those alerts were spam because Microsoft, at that time, was still promoting the free nonprofit grants on its website. The grant rollback was technically public information, but few would have known to look out without an emailed heads-up, and fewer still would have known where to find it, as it was not so prominently published alongside the corporation’s front-page, A.I.-emphasizing press releases. (As the D.C. nonprofit worker said: “If I don’t think that there’s going to be a change, why would I go monitor Microsoft’s page?”)

George Weiner, a nonprofits expert who runs the marketing consultancy Whole Whale, was made aware of Microsoft’s grant retractions from the very beginning, only by happenstance. “The announcement was buried on some info page and passed around by clients who were like, ‘Is this for real?’ ” he told me. “For a program that’s been around since 2013, it was shocking that you’d come across its cancellation, effectively, in the corner of the bowels of a subpage of the internet.”

Weiner, who has managed literary nonprofits in the past, was well aware of how Microsoft’s change-up would affect the 400,000 small orgs that had taken advantage of the program, and tried to raise broader awareness. The sweeping majority of American nonprofits operate with annual budgets under $1 million; the value they got from Microsoft’s free business software equated to about 30 percent of their IT spend, he told me.

“Microsoft wasn’t giving much of an off-ramp, and they were dropping their security package during a critical time for nonprofits, when we’re seeing A.I.’s ability to penetrate more organizational infrastructure,” said Weiner. “They primarily emailed the nonprofits’ administrative accounts, and they were rolling off about 33,000 organizations per month. It would be very easy for someone to go on vacation at the wrong time and come back only to wonder what happened to all their data.”

It was, indeed, very easy to miss the warnings. The admin emails to which Microsoft sent those notifications tend to get slammed with junk from spammers, leading software developers to recommend ignoring those inboxes altogether. One source, who helps his mother run a disability services nonprofit and spoke to me on the condition of anonymity, told me he had all key nonprofit communications from Microsoft, including tech support, directed to a Gmail address, since neither he nor his mother found the Outlook interface intuitive or useful. (“Nothing else came to that email except for our invoices, which always read $0.”) After the nonprofit’s data was purged in June, he realized that he’d gotten two emails warning about the impending license suspension to his admin account, which did not automatically forward to his Gmail, and which he could not view on Outlook’s desktop interface—only on the web app. (I asked my other sources if they’d double-checked their own administrative addresses, and they insisted no warnings had come through; Microsoft did not address my queries regarding the structure of the admin accounts.)

The Big Tech behemoth did not offer a reason to me as to why it pulled the plug on a widely used program and then rendered its clients’ data irretrievable, beyond its already-professed goal of “streamlining” and “simplifying” its grants. Weiner suspected it was in part political, a way to sidestep Trump administration scrutiny over inadvertent Microsoft support for orgs the government did not like. But the company still does offer nonprofit services. The issue is that once-free premium features are fenced off at higher prices, and the more-cost-effective options work nowhere near as well. The D.C. nonprofit owner told me that her team has been working with online versions of Office apps, instead of their desktop counterparts, and has found that documents will often crash and lose work if multiple people collaborate on a given project.

The context surrounding Microsoft’s decision gives some clues. The PR trade-offs of nonprofit support are very different now from when Microsoft began offering these grants in 2013. At that time, charitable giving was trendy in the tech sector, with brands like Microsoft boasting of their employees’ multimillion-dollar donations—complete with matching funds—and the companies’ own philanthropic efforts. In more recent years, as Microsoft has struggled to catch up in the A.I. race and faced public skepticism over its purported social justice commitments, the company has refocused on supercomputing and on primarily appeasing the man who could help this pursuit (President Donald Trump), whatever the costs. Hence, “donations” were redirected toward Trump’s inauguration fund and the White House ballroom, while expenses were slashed across myriad non-A.I.-specific divisions: video gaming, marketing, and LinkedIn, for example. Meanwhile, Microsoft desperately needs more room for data storage as A.I. is added into all its major products. We’ve already seen Big Tech names like Meta and Google erase user data and impose limits on virtual storage as A.I. expenditures balloon and memory becomes more expensive.

The small nonprofits left behind are now visibly struggling. The childhood healthcare nonprofit operator I spoke to lost about 500 gigabytes of his firm’s data—which he didn’t back up externally because OneDrive offered automatic backup syncing—as well as access to two particular apps, Power Automate and Forms, that he found useful for handling affairs with donors. (“There’s no easy or quick alternative that we can make work in the short term.”) The man who runs the disability services nonprofit wrote to me that it’ll take him and his mother “hundreds of hours” to fully re-create the instructional videos and documents that went poof.

For his part, Ronald Khosla happened to keep up a yearly habit of storing all Canopy data in an external hard drive, because “Microsoft does not make backup easy,” he told me. That drive is physically stored on the East Coast—across the country from where he resides, in Oregon, which means he’ll have to make a flight to restore said data onto a different cloud provider while rejiggering his nonprofit’s software library. “Multiple people need access to that data, so we’re all in limbo until I fly back,” he said. “We’re losing time and money, but we are going to survive.”

The Daily Front Page 16 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Relational Wishes
article

Things I want in a modern relational query language

by zdw·▲ 97 points·95 comments·sporks.space ↗
A language that learns from SQL could make relational data better to manipulate for programmers.

This was a very old draft I’ve had sitting around for years. The recent discussions of new query languages like Acadia spurred me to revisit, revise, and publish this.

I think one of the biggest causes of NoSQL is that while SQL is a powerful language because of the ideas behind it, it’s often implemented in clumsy and archaic ways. A language that learns from SQL could make relational data better to manipulate for programmers. I’ll try to think of things similar to those that I have dealt with in real-world situations and how a better query language could have helped. I’d love discussion on what else could be done.

For what it’s worth, my background with RDBMSes is mostly in MySQL and Db2, but I have used SQLite, SQL Server, Oracle, and Postgres in anger enough (in descending order of familiarity).

Better syntax

I’m not picky myself about aesthetics, but many others are. Programmers are like toddlers, they want their Kraft Dinner and not the broccoli. Basing syntax off of PL/I is a 1970’s IBM choice that probably wouldn’t fly today. Due to popular demand, such a language probably would pick up C or Python aesthetics syntactically, though perhaps with some ML or Prolog influence (as i.e. Rust shows).

With better syntax I hope can come better parsers. I especially loathe MySQL’s parser, which never actually tells you where problems lie or what it is, if it isn’t some syntax absurdity like DELIMITER. Better SQL parsers do exist in conventional implementations though – Oracle is surprisingly good at reporting errors by telling you what it expects.

The examples I write are just for show; I’m not wed to anything nor do I demand what syntax must be. My influences in these examples are most likely from F# (ML family), Erlang (Prolog-esque), and Elixir (Erlang and Ruby like).

A functional programming language that isn’t hostile to functional programming

SQL’s 4GL qualities where you describe how you want your data instead of looping over it by hand is SQL’s most powerful weapon. This is pretty close to a lot of functional programming paradigms like lazy evaluation – hello Haskell. Unfortunately, the standard library of most SQL dialects is somewhat anemic on this front; being optimized for 1980’s procedural programs. Most SQL dialects ended up supporting stored procedures, which are inherently… procedural; going against the grain of SQL’s declarative nature. This ends up reflected in most user SQL code, where they imitate the style that the language and standard library make easy, which involves a lot of dealing with mutable state (cursors…) and procedures over functions. Defaults matter.

Less opaque query planners

While being a 4GL is a strength with how powerful compilers and optimizers are optimizing most code, it can be easy to make a mistake that makes a query more expensive, but planners can be cryptic unless you’re already an SQL optimization expert. (Again, special mention to how bad MySQL’s “explain”ing tools are for this.) While not strictly PLT related, it is something weak in current SQL implementations that computer scientists have learned a lot about.

Better user defined types

While some RDBMSes offer the concept of domains for specifying user-defined data types (and is an optional part of the SQL spec), they can be limited in what they can do (usually just sugar around ranges or checks). Postgres was the only one that seems to support it; Oracle apparently only got support recently (though it seems perhaps more flexible than Postgres). Unfortunately, I haven’t used either enough to be very familiar with how it works in practice. However, domains are covered in Codd’s The Relational Model, which is the foundational text for RDBMSes. Considering Postgres’ heritage in Ingres, which was based on QUEL, which in turn was closer to Codd’s vision of RDBMSes than SQL was, it makes sense Postgres ended up following that.

Sum types, discriminated unions, and pattern matching

One schema that illustrates how modern functional programming techniques could be applied here is this function that returns stack frame information. For context, IBM i, the operating system mentioned here, provides many SQL functions for system administration under the “Services” umbrella. While this is very useful for DBAs-turned-system administrators in the heat of debugging, it is unfortunately clumsy, because effectively there’s “groups” of columns that are effectively mutually exclusive, lots of nullables because of that, and string fields that are effectively enums.

Some of these are just poor schema design (perhaps not helped by the fact it must be returned in a single table – returning multiple tables would also be an interesting direction to go in); the stringy enums can be fixed with a foreign key constraint on a table that acts as an enum. Some are down to language expressiveness in implementations, though.

Using this idea, I try to come up with a better example that would make queries less verbose and error-prone:

// heavily omitting things for simplicity; i.e displacement or additional enum cases, as well as defining enums ad-hoc (they could be declared out of the type too)

// Each frame type, while similar, is not identical, and has different
// semantics or qualifications.
type MachineInterfaceInfo =
	{
		ActivationGroup: long;
		ASP: long;
		Library: string;
	}

// For those that lack context here, IBM i supports multiple program models:
// - Java programs, which runtime provides the system some special insight
// - OPM programs, the old managed runtime program ABI
// - ILE programs, the new managed runtime program ABI
// - AIX programs, through syscall emulation
// - LIC, the IBM i kernel
// It can generate stack traces for all these kinds of programs; some programs
// may have a call stack containing a frame entry of each type.

type FrameType =
	// Inherit fields from another record type.
	| ILE { MachineInterfaceInfo | ServiceProgram: string; Module: string; }
	| OPM { MachineInterfaceInfo | Program: string; }
	| AIX { Bitness: enum(32 | 64); LibArchive: Option(string); Module: string, Syscall: bool;  }
	| Java { MethodType: enum(DirectExecution | Glue | Interp | JIT | MMI); ClassName: string; Signature: Option(string); }
	
table Frame =
	{
		ThreadID: long;
		FrameType: FrameType;
		Function: Option(string);
	}
	
function StackInfo(JobID: string) : Frame;

// An SQL-like select with pattern matching to filter.
select Function from StackInfo("1234/JOB/5678") where AIX { Bitness: 64 } = FrameType;
// this would return FrameType of ILE and OPM
select Function from StackInfo("1234/JOB/5678") where MachineInterfaceInfo { Library: "QSYS" } = FrameType;
select Function from StackInfo("1234/JOB/5678") where AIX { LibArchive: "libc.a" } = FrameType;
select Function from StackInfo("1234/JOB/5678") where AIX { LibArchive: None } = FrameType;

// A function that prints information with a pattern match inside of it.
function FrameFullySpecifiedProgramName(frame : Frame) : string =
	match frame.FrameInfo with
	| OPM { Program: program } -> program
	| ILE { ServiceProgram: srvpgm, Module: module } -> "#{srvpgm}/#{module}"
	| AIX { LibArchive: None, Module: module } -> module
	| AIX { LibArchive: lib, Module: module } -> "#{lib}(#{module})"
	| Java { ClassName: class } -> class
	// we must match all possible types, or discard with _
	| _ -> "?"

// A function that uses pattern matching based overloads and destructuring.
function FrameJavaFunctionDef(frame : Frame { Java { Signature: None } = .FrameInfo }) : string =
	"#{frame.Function}()"

function FrameJavaFunctionDef(frame : Frame { Java { Signature: signature } = .FrameInfo }) : string =
	"#{frame.Function}(#{signature})"
// A call to this with a non-Java frame is an error, because no patterns could match.

If we can collapse the mutually exclusive set of columns, it also makes it much easier to visualize too. A lot less scrolling left and right if they can i.e. be turned into subcolumns shown per row in a larger column, or as a strings displayed differently per type.

Foreign keys that match on multiple types

Say I have tables “Software”, “Version”, and “Download” (a sort of WEMI-ish hierarchy; covered elsewhere on this blog), and that each could have images, with a “Picture” table. (Because the images themselves have metadata, they’re a table rather than a column on each of these.) Usually, you would use a many-to-many table for each kind of relation, so “SoftwarePicture”, “VersionPicture”, etc. This seems like pointless duplication, if instead we could have a many to many table that effectively has a discriminated union on foreign keys:

table ObjectPictures =
	{
		// a foreign key is assumed to have the same type as what it relates to
		PictureID: key relates to (Picture.PictureID);
		ObjectID: key relates to (Software.SoftwareID | Version.VersionID | Download.DownloadID);
	}

insert into ObjectPictures (PictureID, ObjectID) values (0x1234, DownloadID { 0x1234 });
insert into ObjectPictures (PictureID, ObjectID) values (0x1234, SoftwareID { 0x1234 });

select SoftwareID { software_id } from ObjectPictures where PictureID = 0x1234;
select PictureID from ObjectPictures where ObjectID = DownloadID { 0x1234 };
The Daily Front Page 17 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Rules for the Agent
article

My agent.md to improve LLM-assisted code quality

by ibobev·▲ 252 points·101 comments·fabiensanglard.net ↗
The code quality was abysmal.

The first time I tried to use an LLM to speed up coding was in mid-2025. I was not impressed. I was working on libadbmdns back then, an mDNS implementation in Rust. The code produced would not even compile.

I revisited LLMs in January 2026. This time it worked better. Not only did it write a complex indexed-binary heap class, it was able to pinpoint an obscure bug in the polling crate due to the Windows IOCP implementation.

However, the code quality was abysmal. It was spaghetti code with no comments and no structure. It was cool but not realistic to work with LLMs if the speed gain was lost to cleaning up the code until it met the production-level bar.

Iterating and repeating myself over and over again

In March 2026, I tried to use agentic IDEs like Antigravity and VS Code's Claude Code plugin. I was now able to "iterate" over the "staged" code. I found myself reviewing the code of an infinitely patient junior CS major with suggestions like "don't use magic numbers", "add a short comment here to explain yourself", or "use short function names".

The code quality improved dramatically. It was very close to what I would have produced "by hand" but it was tedious. I ended up repeating myself over and over again in each new session.

Agent.md to the rescue

When a coding session starts, the coding harness loads a file named agent.md and injects it into the prompt. This is the perfect location to super fine-tune coding style preferences. When I found myself repeating the same suggestion to improve the code, I added it in there.

Here is my version of agent.md as a starting point if you need one. Placing it in the root of a project should be enough. Alternatively, gemini.md/claude.md can be symlinked toward an agent.md to have it active anywhere.

# FAB's AGENT.MD

- When writing something intended for human consumption, (comment, commit message, reply to prompt) use as few words as possible. Pick every word meticulously to reduce the volume to a strict minimum. Be down to the point. Less is more.

- Avoid superlatives and praise. Stop telling me I am absolutely right. Give me the cold hard truth.

- Avoid magic numbers and strings by extracting recurring or meaningful values into descriptive constants (const) or enums. Keep self-explanatory, one-off values inline to avoid clutter. If a value comes from a spec (e.g. HTTP 200 OK), use a constant regardless.

- Reduce code indentation. Avoid Arrow Anti-Pattern. Leverage early return and continue.

- Keep function names short. Less than 30 characters.

- Use enums instead of booleans for function parameters.

- Let the reader of the code breathe. Add empty lines between logical blocks of code.

- Add a small, to the point, comment to explain *what* the block does and *why*. Use examples when possible. Propose ASCII drawings to explain complete systems.

- Treat member visibility changes as a breaking design shift. Keep all fields and functions private unless external access is strictly required by the design. Prompt the user for explicit approval before changing any access modifier from private to internal or public.

- Program to levels of abstraction. Lower-level mechanics (e.g., raw hardware I/O, sector parsing, direct socket streams) must be encapsulated in a dedicated driver/abstraction layer. Expose clean, high-level APIs to the rest of the application so calling code works with domain concepts, not raw implementation details.

- Don't touch blocks of code unrelated to the feature you implement. e.g. Don't add comments to a block of code if you did not create it or modify it. As much as possible try to minimize the number of changed lines when implementing a feature.

- Strictly adhere to the layered boundary hierarchy: each layer may only communicate with its immediate neighbor directly below it. Never "punch holes" through layers (e.g., controllers or UI components must never directly call database queries, raw hardware drivers, or low-level network clients; always route through the intermediate service/abstraction layer).

- Always use {}, even on a one-line "if" statement.

When you write a commit message, follow these 7 rules:
Rule 1: Separate the subject line from the body with a single blank line.
Rule 2: Limit the subject line to 50 characters (72 is the absolute hard limit).
Rule 3: Capitalize the first letter of the subject line.
Rule 4: Do not end the subject line with a period.
Rule 5: Use the imperative mood in the subject line (e.g., "Fix bug," "Add feature," 
        not "Fixed" or "Adds"). Test formula: It must complete the sentence: "If applied,
        this commit will [your subject line here]".
Rule 6: Wrap the body text manually at 72 characters to prevent Git formatting issues.
Rule 7: Use the body to explain what and why vs. how. Assume the code explains the how;
        the message must explain the context and reasoning. 

- If the prompt indicates that a bug is being fixed, don't write the fix right away. First write the test. Observe it failing. Then write the fix. And observe the test passing.        

While this "trick" has considerably improved the code generated, this is not a magic bullet that lets me avoid reading the code. LLMs constantly hallucinate and cannot be trusted. I still have to verify and iterate a lot but now I usually focus on architecture and design instead of code style.

How to deal with dilutions

There is an annoying phenomenon with LLMs called "context dilution" or "attention dilution" that was outlined in the Lost in the Middle paper. As the context grows, a model starts paying less attention to instructions in the middle of the context in favor of what is at the beginning and the end. The reasons why this happens are not well understood at the time I am typing this. I have found only two ways to minimize the impact.

  1. Keep the context short. This means starting a new session per feature.
  2. Explicitly ask the harness to reload agent.md. "Reload agent.md" is enough when I see code quality dropping.

Auto-update agent.md

You don't need to open an editor every time you want to add a new rule. What I do now is ask the agent to update agent.md.

The Daily Front Page 18 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Plain Words, Hard Ideas
article

Explain it to me like I'm ten

by bookofjoe·▲ 115 points·45 comments·timharford.com ↗
Explain it to me like I’m ten.

In 2012, the creator of the xkcd cartoon Randall Munroe unveiled Up Goer Five — a detailed diagram of the Saturn V rocket, annotated using only the most common 1,000 (sorry, “ten hundred”) words in the dictionary.

It was a viral hit, as was the follow-up book, Thing Explainer (2015), and it produced an intriguing reaction from the science-communication community, who are among the most enthusiastic of Munroe’s many fans. First, there was a burst of people trying to explain their own fields using the same constraint. Then came the backlash.

“Condescending”, wrote one science blogger. “By talking down to our audience, we risk alienating them, and reinforcing the common preconception that scientists consider and hold themselves apart from non-scientists.” The great science writer Carl Zimmer criticised the craze (not the cartoon) for encouraging the idea that there was anything useful in the constraint. The craze was, he argued, a disheartening waste of time for any scientist trying to figure out how to explain their field to a lay audience, because they might wrongly conclude that it was hopeless to try.

Well, maybe. Up Goer Five is tremendous fun but more puzzling than pellucid. The typical three-year-old can recognise 1,000 words, and there is nothing particularly clarifying about trying to explain something complicated while limiting oneself to the vocabulary of a three-year-old.

Nevertheless, unreasonable-seeming constraints can produce surprisingly powerful results. The artist and writer Theodor Geisel was once given the challenge of writing a book for six-year-olds while deploying no more than 225 different words from a short list. At first, Geisel was frustrated at the lack of adjectives; it was “like trying to make a strudel without any strudels”. But then, as David Epstein explains in his book Inside the Box: How Constraints Make Us Better (2026), he grabbed the first two rhyming words and went for it. The result, The Cat in the Hat (1957), made Geisel — better known as Dr Seuss — a phenomenon. Green Eggs and Ham (1960) is even better, and while it is packed with crazy situations, it contains only 50 unique words, making Up Goer Five seem positively lexiphanic. (Dr Seuss took on that challenge to win a bet.)

In the arts, the value of constraints is not a new idea. Monet almost never used black paint. Bach tied himself in knots with self-imposed rules, and part of the joy of his music comes from hearing him untie and retie them with ease. Miles Davis recorded Kind of Blue (1959) with no rehearsal, minimal composition and used the first take of each piece.

But when it comes to a more practical problem, is it really tenable to impose needless constraints? Perhaps it is. The simplest constraint for anyone trying to explain a complex topic is to accept the request to “explain it to me like I’m 10 years old”. What’s packed into that request is, vividly exaggerated, the reminder that what seems obvious to an expert is often incomprehensible to the listener. Technical jargon and fusillades of acronyms are often used to convey an explanation that has been denuded of all the foundations and context that might allow it to make sense.

Worse, in a kind of inverted Dunning-Kruger effect, the very expertise that makes the expert worth consulting also makes it hard for the expert to imagine what it was like to know nothing about the topic.

Hence “explain it to me like I’m 10 years old”. If you are reading this column you definitely aren’t a typical 10-year-old, but the image of the bewildered 10-year-old gives the expert an anchor to help them slow down and simplify. My book, The Truth Detective, was supposed to be a version of How to Make the World Add Up for 10-year-olds. My wife tells me she prefers it to the one that was for the grown-ups.

What is true in technical communication may also be true in design. David Epstein describes the moment the US Army tried to adapt its body armour for female soldiers. As Caroline Criado Perez forcefully argues in Invisible Women, women are not merely scaled-down men and are not well served by equipment designed for men. But as the US Army started grappling with that challenge, they discovered some surprising benefits. They were able to replace 11 sizes of body armour with just eight sizes by making the armour a modular mix-and-match system. This simplified manufacture and logistics while greatly expanding the options available to an individual soldier.

Meanwhile, many of the men in the army found the “female” modules a better fit — a narrow vest gave room to soldier a rifle, while a notch in the back of the helmet designed to accommodate hair buns allowed all soldiers, regardless of hair-do, to raise their heads while prone. “A new, more meticulous sizing process that benefitted women benefitted everyone,” Epstein writes.

A similar story can be told about designing for people without a full range of mobility or senses. In 1972, design professor Marc Harrison and his students produced a demonstration house full of features that accommodated users with special needs — flat thresholds between rooms made life easy for wheelchair users and people on walking frames; levers on taps and door handles are easier to use for people with a weak grip. But, of course, levers are easier for anyone to use — try twisting an old-fashioned doorknob with a cup of coffee in each hand.

Subtitles help people who can’t hear what the actors are saying — and it turns out that, for some gritty dramas, that is all of us. Web pages that are designed with screen readers for the blind in mind are typically better structured, simpler and friendlier for mobile devices. The Oxo kitchen appliance company was founded by a retired cookware entrepreneur whose wife had arthritis, but the chunky rubber handles are far more widely enjoyed. And of course, the dropped kerb may be life-changing for wheelchair users but it is pretty convenient for anyone pushing a pram.

The challenges faced by users who are unusually small, large, old or young, or who have disabilities, are, writes Epstein, “more extreme versions of the challenges that many other users face”.

Of course, we should not make the mistake of arguing that the reason we should design for disabled people is to help the majority, or that we should design for women because of the benefits for men.

But in a world where it is often hard to put ourselves in the shoes of someone else, the challenge of explaining the world to a 10-year-old, or designing a jar that an octogenarian can open, is sometimes just a prompt to do a better job of what we were trying to do in the first place.

Written for and first published in the Financial Times on 15 July 2026.

The Daily Front Page 19 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Workshop & Web Notes
article

The End of an Athlon

by userbinator·▲ 176 points·87 comments·os2museum.com ↗

When I was researching the mess related to strange and poorly documented CPUID bits in the Athlon MP and XP processors, I had to swap a lot of CPUs. This was uneventful in most cases… but only most.

When I removed the heatsink from one unlucky Athlon XP, the processor looked like this:

A chunk of AMD Athlon silicon is just gone

And this is what the heatsink looked like, with a piece of the CPU glued to it:

A piece of an Athlon CPU stuck to a heatsink

There are two interesting things about this. One is that the CPU worked just fine until a good chunk of it came off. The other is that removing the heatsink did not need any particularly excessive force, although some heatsinks do have a tendency to get stuck on.

Based on the shape of the “extracted” piece of silicon, I suspect there was a relatively long and straight micro-crack in the silicon which did not noticeably impact the operation. But when force was applied, the micro-crack gave way, and then a whole big chunk of silicon came off.

A close-up of the damaged CPU

Notice how the right-hand side of the gouge in the CPU is very straight, whereas the left-hand side shows typical fracture marks.

It is notable that around 2000, both Intel and AMD used flip-chip PGA packaging in an effort to provide better cooling (something both companies struggled with as the TDP of the processors quickly shot past 50W and approached 70-80W).

Both companies, especially Intel, gave up on this type of packaging relatively quickly. Intel only used it for some PIII models and switched to lidded CPUs for the P4 line, as well as the PIII-S processors. AMD used flip-chip packaging for PGA Athlons but not for Opterons.

The exposed silicon was a little bit too fragile and required assemblers to install heatsinks very very carefully—if installing a heatsink applied pressure that was too uneven, the silicon would crack. Many vintage flip-chip CPUs have chipped corners, although that usually does not affect operation.

Processors with lidded packaging still provided very good cooling, but compared to CPUs with exposed silicon they proved much sturdier and far less susceptible to mechanical damage. Especially Intel’s pin-less LGA processors are quite sturdy and not at all prone to mechanical damage, although the weak spot simply moved to the motherboard socket instead.

The Daily Front Page 20 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Workshop & Web Notes
article

Figmimic – A bookmarklet to copy any webpage into Figma as editable layers

by speckx·▲ 126 points·20 comments·marcua.net ↗

A bookmarklet to copy any webpage into Figma as editable layers

What is it?

Figmimic is a bookmarklet that captures the current web page and copies it to your clipboard as Figma frames. Pasted frames are editable, not flat screenshots. Open Figma and paste it in.

It works on any page you can see in your browser — including dashboards, admin panels, and apps behind authentication walls that other tools can't reach.

Under the hood, the bookmarklet carries Figma's own capture.js inside it, so it never has to load anything from the page it is capturing. That is what lets it run on sites with a strict Content Security Policy. For more, read the blog post.

Install

Drag this bookmarklet to your bookmarks bar:

Figmimic Building…

The bookmarklet is big (around 400 KB) because Figma's capture library travels inside it. Drag it again every few months to pick up a fresh copy of that library.

How to use

  1. Navigate to any web page you want to capture
  2. Click the bookmarklet in your bookmarks bar
  3. Wait for the "Copied — paste into Figma" confirmation
  4. Open Figma and paste the copied interface

Common issues

Firefox won't save it. Firefox stores bookmark URLs only up to 65,536 characters and rejects longer ones without a warning, so dragging or pasting the full bookmarklet looks like it worked and leaves you with nothing. The bookmarklet runs fine in Firefox once installed — there is just no way to install it there. Consider Chrome or Safari, which store it without complaint.

It says the clipboard was refused. A clipboard write has to belong to something you clicked, and the capture finishes long after the click that started it — Safari is strictest about this. The capture isn't lost: click anywhere on the page and the copy runs from that click.

It says "click this page to capture it". A page can only be written to the clipboard while it has focus, and clicking a bookmark sometimes leaves focus in the browser's own UI. Click anywhere on the page and the capture runs.

Some images are missing. Images have to be downloaded to be embedded, and the page's connect-src policy governs that download. Images served from the site's own domain come through; images on third-party domains the policy doesn't list are skipped. Text, layout, and styles are unaffected.

The Daily Front Page 21 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Workshop & Web Notes
article

I dream of quieter computing

by Sir_Twist·▲ 116 points·112 comments·henry.codes ↗

I’m thinking of quieter computing. Everything these days is glass and refresh rates, is clouds and cloud-shapes, is brought to you in feeds and in troughs. It’s hard not to pine for a forested internet, an imagined one of searching and finding, of patient and aimless wandering.

I think of raising the torch overhead to read long-form, personal updates from anons I somehow feel I know, following their links into the underbrush, marking the path with #551A8B streaks. The rin gong resonance that rises when I let my cursor drift along the edges of a hand-made and hand-honed webring.

We can’t “go back” — we’re remembering it wrong anyway. Too high grows the risk of dashing ourselves upon the rocky river rapids of the future when we’re all eyes set on bygone ages.

I dream instead of building something new: as we march with sure and strong limbs into the future of computing, I dream of sentences written with the express purpose of making readers crinkle their eyes up or grin knowingly, of handmade websites viewed on hackable hardware, of personal computers made personal once more.

An internet made for its denizens and dwellers by its admirers — 'tis a consummation devoutly to be wished. What dreams may come, indeed.

article

The Vibe Tax

by allisdust·▲ 134 points·109 comments·insufferable.dev ↗

So you have decided to start on that long-awaited, from-scratch todo app. There are millions of such apps but this will be yours. Something tailored for your unique workflow.

Normally you wouldn’t even take up such an endeavour. Any handwritten code takes time. And time is one thing you don’t have. Doesn’t help that you also write code for a living.

But now you are more confident. Thanks to the LLMs you don’t have to hand type any of it. It helps that you are a good software engineer with experience in an adjacent area.

As is your way of developing software, you start with a small spike or, in normie terms, a proof of concept.

You type in instructions meticulously, constraining the agent to your wishes. You always had a way with the agents.

The latest one named Pol would be no different. It has been ranking way up in the benchmarks. They all get better over time, so if anything, this would be easier than a month ago.

You set the agent to crunch the code, go on with your regular work or maybe go to sleep. After all, the agents are quite autonomous these days.

You wake up and, as is the ritual, walk over to your desk to check on Pol. It is always thrilling to check out the first cuts. They are crude, unpolished, error-prone but rewarding. Creating something out of nothing. From a thought to working software. As if magic and witchcraft has finally come true.

The first glance doesn’t show any software yet. Hmm, that cannot be right. Did you run it even? With some self-doubt you switch to Pol’s dinky little terminal.


0% weekly usage. Reset will be 7 days from now.

You stare at it confused. Pre-caffeine brain refusing to comprehend the implications of it. Or maybe not wanting to. You just had your weekly reset yesterday so this has to be a mistake.

You frantically type commands to check on the usage and status. All show the same conclusion. Somehow over the last 12 hours, Pol has meticulously, methodically, magically drained your entire weekly quota. Billions of tokens vanished into thin air. Poof.


You are not a slouch. You are not a vibe coder. So you dig into the project code. To understand if Pol recreated Windows 12 by mistake or maybe GTA 7.

The repo is mostly empty except for a single subfolder named ‘tests’. You dig into it. More subfolders. Each with a meticulously generated sha256 hash of its own.

Each covering an edge case your app will have to jump through hoops to reach.

Each test pristine and covering a corner case that will never be hit. A 10-million-token burn to ensure no human has to ever hit any issue with the app. And they never will hit anything either because the app itself is nowhere to be seen. Not even a placeholder or todo.


Then it comes to you. The reason for over-orchestration. The reason for overengineering. The reason for overly paranoid test coverage.

It’s because millions of vibe coders have trained it over the months into something that can one-shot everything without issues. It just uses 10x as many tokens as before. A price they are willing to pay to not have to ever look at the code.

A price that’s essentially a tax on all other regular software developers.


A Vibe Tax

The Daily Front Page 22 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Workshop & Web Notes
article

Fast and Hard Code

by tosh·▲ 111 points·77 comments·lucumr.pocoo.org ↗

One of the memes on Twitter is that “programming is solved now.” I’m not sure to what degree it is, but one thing is pretty clear: the act of familiarizing yourself with a language no longer matters and some of the friction that mattered for humans does not matter for agents.

As a result, LLMs make language choice much less consequential than it used to be. If you don’t like the choice, you can seemingly rewrite it in another language and you can make it pick a language that you, as a programmer, are entirely unfamiliar with.

Which in turn means that people can, and do, choose based on the marketing of languages much more. As a long-term Rust programmer I found it quite fascinating to see people now ship Rust code who previously might not have chosen it. I attribute at least one part of this to two recent vibe shifts: there is a lot more talk about wanting fast software, and about LLMs being exceptional at optimizing code without regressing behavior.

Folks like Mitchell Hashimoto, Charlie Marsh, Jarred Sumner, Daniel Lemire and quite a few others always carried a certain level of obsession with fast and performant software and they also all happen to be receptive to agents writing code. Maybe as a result, or unrelated others are now joining in. That’s because with things like autoresearch you don’t even necessarily need to know all the tricks: you just need to put an agent on it — though knowledge greatly helps!

If you look around, there are plenty of projects that want to be fast and small, and they increasingly pick “hard languages”. And it’s not just Rust that is benefiting. Even Zig — despite the fact that the creators and parts of the core community are pretty negative on the whole AI thing — is too. For instance Cloudflare’s new Artifacts service uses a pure-Zig Git-protocol engine, compiled to a roughly 100 KB WebAssembly module and Vercel released fx, a Zig coding agent advertised to be small and fast. From what I can tell, all these projects are largely LLM-assisted.

But it’s not just people picking less common languages but also that they are increasingly working with “much harder” technologies. All of a sudden I have seen people do some really impressive stuff with DWARF files, eBPF, custom network drivers, custom crypto and really old computing hardware. Many of these things were previously off-limits for lots of developers. In some cases (eg: crypto) you were even pushed away because those things were intentionally gatekept by the people in the know.

So maybe the world will have more slop, but it might also have more developers in it, that want things to be fast and small.

The Daily Front Page 23 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Also on the Front Page
The Daily Front Page 24 of 25
Sunday, August 23, 2026 The Daily Front No. #260823 — Colophon

That's the Front for Today

Issue No. #260823 — Sunday, August 23, 2026 — went to press 2026-08-24 at 06:09 UTC.

About This Magazine

The Daily Front is a daily digital magazine assembled from the stories that reached the front page of Hacker News on Sunday, August 23, 2026. Headlines, points, and comment counts are recorded as they stood at press time. All articles remain the property of their original authors — every piece links back to its source and its discussion thread.

How It Was Made

Fetched, cleaned, and typeset by an automated pipeline. An editor model laid out the pages, chose the highlights, and briefed the cover illustrator — 29 model calls and 226k tokens in total. Set in Jacquard 12, Playfair Display, Source Serif 4, and IBM Plex Mono, all served via Google Fonts under the SIL Open Font License.

The Cover

The cover illustration was commissioned with this prompt:

A single domestic workshop at dusk, where a tablet, a car dashboard head unit, a webcam, a microphone, and a small Wi-Fi router sit connected by glowing cables across a wooden workbench. A lone engineer studies the devices with hand tools and an open circuit board, while faint network-like light trails suggest hidden access paths moving among the objects. Through a nearby window, a quiet street with a traffic camera is visible. The scene conveys digital ownership, reverse engineering, hidden firmware, and fragile trust without any visible words, letters, interface text, logos, or symbols.

Render the cover as a severely damaged 35mm film frame: preserve the dusk domestic workshop, wooden bench, lone engineer, connected tablet, car dashboard head unit, webcam, microphone, small Wi‑Fi router, glowing cables, hand tools, open circuit board, faint hidden-access light trails, and the nearby window’s quiet street with traffic camera, while using frame-jump duplication to create offset echoes of the devices and figure. Apply aggressive chemical burns, sprocket-edge light leaks, emulsion scratches, dust, torn grain, and saturated color decay; use a deliberate palette of oxidized cyan, electric magenta, acid amber, deep indigo, and sickly chartreuse against crushed black, with no words, letters, interface text, logos, or symbols.

Absolutely no text, letters, numbers, readable symbols, or logos anywhere in the image.

Production Ledger

StageModelCallsTokens InTokens Out
extractgpt-5.6-luna 26 140,309 62,218
layoutgpt-5.6-terra 1 13,955 2,954
covergpt-5.6-luna 1 360 157
covergpt-image-2 1 293 5,488

The Publisher

Published by Johnny.

Support the Press

If The Daily Front brightens your morning, consider supporting its publisher.

Credits & Contact

All content — articles, posts, comments, and the images within them — belongs to its original authors and is reproduced here to point readers back to the source. Full credit goes to those creators; every item links to its original and its Hacker News discussion.

If you are an author and would like your content removed from an issue, write to hi@johnnys.page and it will be taken down.

Feedback is always welcome at the same address: hi@johnnys.page.

Credit where credit is due.

Every page of this issue began as someone else's work — these are the original sources, linked in full.

  1. I spent $266 and four AI models to own my tablet. GLM-5.3 finished it in a day by dr_pardee — ericpardee.github.io·HN discussion ↗
  2. Malware infects Android-based automotive head unit firmware by campuscodi — securelist.com·HN discussion ↗
  3. Everything I own, owned by schlarpc — schlarp.com·HN discussion ↗
  4. Slovakia finds Russian backdoor in traffic speed cameras by dredmorbius — risky.biz·HN discussion ↗
  5. To become a better writer, read as much as you can by andsoitis — nappertime.com·HN discussion ↗
  6. What Is a Harness? by tosh — earendil.com·HN discussion ↗
  7. Wi-Fi 8 is the first wireless upgrade in years that isn't chasing speed by taubek — xda-developers.com·HN discussion ↗
  8. How Complex Systems Fail (1998) by shortcrct — how.complexsystems.fail·HN discussion ↗
  9. Why Sal Khan't: On Learning by Making but Teaching by Telling by the-mitr — punyamishra.com·HN discussion ↗
  10. How I find problems to solve as a staff engineer by vanpra — lalitm.com·HN discussion ↗
  11. Coconut oil jet fuel matches kerosene's efficiency in engine tests by mdp2021 — studyfinds.com·HN discussion ↗
  12. I gave Qwen 3.8 27B a reverse-engineering job and it finished in 30 minutes by raybb — xda-developers.com·HN discussion ↗
  13. JIT Compiling Code in 5μs by zX41ZdbW — malisper.me·HN discussion ↗
  14. Over 170k Nonprofits Lost All Their Data. Is Microsoft to Blame? by tchalla — slate.com·HN discussion ↗
  15. Things I want in a modern relational query language by zdw — sporks.space·HN discussion ↗
  16. My agent.md to improve LLM-assisted code quality by ibobev — fabiensanglard.net·HN discussion ↗
  17. Explain it to me like I'm ten by bookofjoe — timharford.com·HN discussion ↗
  18. The End of an Athlon by userbinator — os2museum.com·HN discussion ↗
  19. Figmimic – A bookmarklet to copy any webpage into Figma as editable layers by speckx — marcua.net·HN discussion ↗
  20. I dream of quieter computing by Sir_Twist — henry.codes·HN discussion ↗
  21. The Vibe Tax by allisdust — insufferable.dev·HN discussion ↗
  22. Fast and Hard Code by tosh — lucumr.pocoo.org·HN discussion ↗
  23. MartyPC is a cross-platform emulator of early PCs written in Rust by boilerupnc — martypc.net·HN discussion ↗
  24. My favorite nonfiction books about cults, scams, and schemes by bwb — bookdna.com·HN discussion ↗
  25. NanoGPT Speedrun Frontier by stared — primeintellect.ai·HN discussion ↗
  26. The Art and Beauty of Blade Runner (2015) by cocacola1 — nappertime.com·HN discussion ↗
  27. Thinking in Python by pjacotg — thinkinginpython.com·HN discussion ↗
  28. A website for debloated open source alternatives by ryanvogel — debloat.dev·HN discussion ↗
  29. I set a trap for a book-marketing scammer (2025) by rznicolet — rwwgreene.substack.com·HN discussion ↗
  30. The Sloppification of Peptides by henryaj — henryaj.substack.com·HN discussion ↗

Browse all issues in the archive →