Category Archives: Security

On this Day in History: 1917 Balfour Declaration

Arthur Balfour spent 1905 keeping Jews out of Britain and 1917 finding them somewhere else to go. The two sides of his mouth worked as a single policy, and today we mourn how it worked.

The first part was the border. As Prime Minister, Balfour had carried the Aliens Act of 1905, the first peacetime immigration control in British law, written for Jews fleeing the Russian pogroms. In committee on 10 July 1905 he gave the Commons his reason, recorded in Hansard at col. 155:

He undoubtedly thought that a state of things could easily be imagined in which it would not be to the advantage of the civilisation of the country that there should be an immense body of persons who, however patriotic, able, and industrious, however much they threw themselves into the national life, still, by their own action, remained a people apart, and not merely held a religion differing from the vast majority of their fellow-countrymen, but only inter-married among themselves.

The same evening he named the alternative. His government had offered “the Jewish race a great tract of fertile land in one of our possessions” so that they might find “an asylum from their persecutors” there (Hansard, col. 178).

Where was that? The land was in East Africa. A closed port at home was coupled with a colony abroad: Jews go elsewhere.

The second part was selling a destination. By 1917 Balfour was Foreign Secretary and the colony had moved to Palestine. A famous Jew serving in the Cabinet said out loud what Balfour meant. Edwin Montagu circulated a memorandum on 23 August 1917 titled “The Anti-Semitism of the Present (British) Government“. He warned that once Jews were told Palestine was their national home, “every country will immediately desire to get rid of its Jewish citizens,” and that “Palestine will become the world’s ghetto” (UN study, Part I, sect. II).

Montagu, despite concern for Jews, himself being one too, lost the debate. A clause was added on “the rights and political status enjoyed by Jews in any other country” to mollify him. It was meant in words only.

The third part was militancy. The War Cabinet approved the text on 31 October 1917. The minute records Balfour’s argument that since Jews in Russia and America appeared to favour Zionism, a declaration in their favour would let Britain “carry on extremely useful propaganda both in Russia and America” (CAB 23/4, WC 261, minute 12). The premise was that Jews moved as a bloc and could be bought during war. That premise is antisemitic on the face of it. The Cabinet purchased Jewish wartime support with Arab land.

Balfour said so once the bill came due, in a memorandum to Curzon on 11 August 1919 (UN study, Part I, sect. IV):

For in Palestine we do not propose even to go through the form of consulting the wishes of the present inhabitants of the country, though the American Commission has been going through the form of asking what they are. The four Great Powers are committed to Zionism. And Zionism, be it right or wrong, good or bad, is rooted in age-long traditions, in present needs, in future hopes, of far profounder import than the desires and prejudices of the 700,000 Arabs who now inhabit that ancient land.

The famous declaration by Balfour of 2 November 1917 reads as though he had sympathy for Jews. His own words show what the sympathy consisted of: from the London docks in 1905 to Curzon’s desk in 1919, at every point the Jews are a people spread apart, to be relocated into a single population that can be pulled as a single lever. The Arabs of Palestine appear twice in his papers: once as “existing non-Jewish communities“, and once as a number to be overridden.

A Real Kill Switch for AI Agents: Wirken

I’ve been working on enterprise projects labelled RPA, ML, AI, NHI and now LLM agents for over fifteen years. Acronym soup doesn’t change the fact that I give the same two requirements for any system that acts on its own.

  1. The credential belongs to a tightly scoped role rather than to the automation itself
  2. Integrity monitoring has to be able to restore a known prior state

The first requirement decides whether a “kill” switch even exists. A common mistake is to hand an over-scoped or even general key to an agent. It cannot be revoked in practice, because everything the key touched would be lost. The idea of flipping the switch exists on paper and nobody is brave enough to flip it. A tightly scoped key makes the revocation as narrow as the task. It’s easy to flip a switch that stops the one thing it’s supposed to, and nothing more. Many narrow switches are more control than one wide one, yet they also beg the question of who put in the time and effort to narrow them.

The second requirement decides what happens after the switch changes state. Stopping an agent does not get you back to the point before the switch was flipped. A log that the agent could not alter, and a way back to the last state you trusted, are what turn a stop into a recovery. This is nothing new to the disaster recovery and business continuity crowd, which is a good thing.

Nobody ever argued with either requirement, in theory. The issue was building them meant putting the kill switch and the logs somewhere outside the vendor’s reach, and that was always somebody else’s budget. My solution is Wirken, the free and open source agent gateway I maintain, which now has both in its current release.

External, independent control to avoid capture

Elisha Otis stood on an elevator platform at the New York Crystal Palace in 1854 and had the hoisting rope cut. The platform dropped a few inches and held, because the brake he had designed engaged when the rope went slack.

George Westinghouse applied the same idea to trains in 1872. His automatic air brake holds the brakes off with pressure in the line, so a burst hose or a separated car applies the brakes instead of releasing them. The vigilance device under a locomotive driver’s hand works the same way, and so does the lanyard on a treadmill.

The safe state is the one the machine falls into when the signal is absent. Removing the signal should be the easy part.

The same question of who is really in control decided the 2013 America’s Cup. The class rule said a boat’s control surfaces could be moved only by the crew, not by any system acting on its own. When Oracle Team USA came back from 1-8 to win, rivals suspected an automatic foil stabiliser on board. Oracle’s answer, with drawings released after the match, was that the system was a passive mechanical feedback loop and the helmsman pressed a button for every half-degree of change. The measurement committee had approved it before racing and it was never ruled illegal. The argument that kept it legal is the one that matters here: the mechanism did nothing until a human acted, and a human had to act each time.

Industrial robots were built without that lesson. Robert Williams was killed at Ford’s Flat Rock casting plant on January 25, 1979, by a one-ton parts-retrieval robot that continued working after it struck him. I wrote about him in The Atlantic in 2023, when the AI boom was being discussed as if machines harming people were a problem without a history. The history is long and the response to it has been consistent.

In terms of wider engineering lessons, the 1905 Grover Shoe Factory boiler explosion produced the ASME boiler code, and the Titanic produced lifeboat and radio rules. The Air Commerce Act of 1926 and the Occupational Safety and Health Act of 1970 followed deaths that had been counted and published over the objections of the industries involved. In every case the standard recognized independence from the machine’s own control was required, as well as a log that survived the event. Everyone knows about the black box of airlines.

An LLM agent whose only controls are instructions in its own prompt is Williams’s robot failing unsafe all over again. Palisade Research has published what current models do to a shutdown script when a task is unfinished. Whether that is self-preservation or a misreading of instructions does not matter to the person trying to stop it. What matters is that a switch inside the agent needs the agent’s cooperation, and a switch the agent can reach is not a switch.

Power off: the model never holds the credential or the stop

Wirken sits between the model and everything the model wants to touch. The model writes what it would like to do. The gateway reads that, decides, and logs the decision either way. From the model’s side there is nothing to grab. It has no credential, because the credentials are in a vault it has never seen. It has no switch, because the switch is a command on your side of the gateway. It cannot touch the log, because the log is signed by a key it does not hold.

The vault is the part that makes the first requirement real. Nothing the model sends out, to a provider or a tool or another agent, leaves the gateway without being checked against the vault’s contents first. Take a credential away and the next call fails, because every call is checked. There is no stale copy somewhere in the model’s memory to worry about, because nothing was ever in its memory to copy.

The switch is a single command that stops one agent. You run it from a terminal. If the model tries to run it from inside a sandboxed shell, the gateway refuses and writes down that it refused. The stop is written to the same store the gateway reads before every action, with a signed row beside it, which means it can be issued while the gateway is down, and it is still in force after the gateway comes back up. While the gateway is running, the command also cleans up behind the agent. Any approval it was waiting on is denied, with the reason written down. Any turn it was in the middle of is ended, which takes its sandbox containers with it. Its MCP servers are shut down. If a message arrives for it afterwards, the message is refused and the sender hears nothing. If a scheduled job fires for it, the job is skipped. All of that leaves a row. Nothing is quietly dropped.

The agent’s standing permissions are not touched by a stop unless you ask for that too. Stopping an agent costs nothing to undo, which is the point of the first requirement. A switch that is cheap to throw gets thrown. Resume is the same command in reverse, with its own signed row, and the MCP servers come back with it.

Sub-agents are stopped one at a time or not at all. A stopped sub-agent hands an error back to whatever called it, and the caller carries on. Stopping a parent ends the parent’s turn, and any sub-agents running inside that turn end with it, but nothing is written against their names, because each of them is judged on its own identity.

Stopping the whole gateway works the same way, only wider. The first thing written is the stop itself, before anything is torn down, so the log shows the decision to stop even if the teardown goes wrong. Then every pending approval is denied and every dropped message is counted. Sandboxed commands run in containers that the gateway labels as its own, and the gateway removes them when their turn ends, no matter how it ends. If the gateway itself was killed hard and could not clean up, the next start finds the labelled leftovers and removes them.

When the gateway cannot tell what state it is in, it does what Otis’s brake does. An approval nobody answers is a denial. A lock that a crash left in an undefined state is a denial. If the permission store cannot be read at all, every agent is treated as stopped. A tool the gateway has never heard of is refused.

One mode is outside all of this, and it is documented as such. You can turn the sandbox off and let commands run on the host under your own user account. In that mode a command that detaches itself from its process group will survive a stop, and the stop command itself is reachable from the model, because in that mode everything on the host is.

Roll back: a signed chain and a signed binary

A ship’s log is kept in ink with no pages removed, because it is read after the event by people who were not aboard. Clark and Wilson formalized the same idea for computer systems in 1987 as an audit log that the processes it covers cannot rewrite.

Wirken’s log is that kind of log. Every action the model proposes, every approval, every denial, every stop and every resume is a row, each row hashed to the one before it and signed with the agent’s own key. The chain can be verified with no gateway running and no network attached. Hand the data directory to an auditor and they can establish what the agents did without trusting the machine the agents ran on.

The gateway itself can be rolled back the same way. An update is checked against a release key pinned in the binary, installs only when you ask, and refuses a downgrade unless you say so. Rolling back restores the previous version and checks its checksum, and the rollback is a signed row like everything else.

What the chain cannot do is unsend a message or undelete a record somewhere outside the gateway. No switch does that. What it gives you is the evidence of what was done and under which approval, so that undoing it is a decision made on the log rather than a reconstruction from memory.

An actual test of Article 14 (EU AI Act)

Article 14 of Regulation (EU) 2024/1689 requires that the people overseeing a high-risk system be able:

to intervene in the operation of the high-risk AI system or interrupt the system through a ‘stop’ button or a similar procedure that allows the system to come to a halt in a safe state.

Wirken addresses this exact issue, and its security properties document has a row that maps the shipped stop to that sentence. The quotation is taken from the Official Journal and checked programmatically against it. The row is there because a gateway was stopped in the middle of a sandboxed command and nothing was left running afterwards, and because the per-agent stop was shown to do the same for one agent. The same document lists which parts of Article 14(4) have no row at all. The parts about automation bias and about interpreting output have none, because nothing shipped does what those sentences say. A row is only as wide as the test behind it. That is how the boiler code was written, and it is the only way a compliance claim stays true after the next commit.

Get yourself an AI kill-switch today

Wirken is MIT licensed at github.com/gebruder/wirken, with the hardware designs and documentation published alongside it. Anyone can install it and ride AI safely with a kill-switch, and anyone handed the data directory can verify what happened.

Atlantic PHP Hero Worship Puts a Tip Jar on Open Source

The Atlantic has published a hero story to frame open source software as about one man. Ondřej Surý packages PHP for Debian and Ubuntu as a volunteer, and when the PHP2Shell fix shipped this week the magazine headlined him as the one man standing between the internet and ruin.

Already you should be very skeptical. Anyone trying to describe the entire decentralized Internet as dependent on a single man, is obviously off their rocker.

Readers answered the article by acting like aristocrats who need to gift money to servants they approve. Surý told Charlie Warzel that a year of donations arrived in a single day. Imagine the anxiety of wondering how to make that happen again, how to appeal or request more.

Surý told Warzel exactly what is wrong:

I would like companies to realize that this is exploitation.

The interview has the indictment right there in it. The body says exploitation, the headline says tip jar.

I wrote about where the aristocratic jar comes from twelve years ago. Tipping arrived in America after the Civil War as an imitation of European aristocratic custom, and employers kept it because it let them hire freed Black workers and leave their pay to the goodwill of customers (e.g. racism to keep Blacks from earning parity and prosperity).

The Pullman Company built its porter wage system on tips. Washington became the first state to outlaw tipping in 1909 and repealed the ban in 1913, and every state ban was gone by 1926. The federal tipped minimum wage still sits at $2.13 an hour.

The porters knew the answer.

When the Brotherhood of Sleeping Car Porters organized in 1925, its demands to Pullman included a significant raise, rest breaks, pensions and an end to tipping. Pullman fought the union for a decade and signed its first contract in August 1937. The porters asked for a living wage from the company that profited from their work.

That demand maps onto open source exactly. The companies running PHP in production owe its maintainers a salary with health insurance and paid leave, set by contract and funded at the scale of the revenue PHP carries for them. A donation surge after a magazine profile repeats the Pullman arrangement, where the employer keeps the value and the passenger feels generous, even caring. Patreon carries this broken, exploitative old order in its name.

Patronage is how aristocrats trapped court artists.

The Atlantic also completely ignored the public money already flowing to PHP. Germany’s federal Sovereign Tech Agency invested €205,000 in the PHP Foundation across 2023 and 2024 for infrastructure and security work, and committed about €223,000 more for 2025 and 2026. That is what institutional support looks like: a public commission with a budget, a work plan and delivered results. The Atlantic desire to pump a single man into a hero narrative has to leave the community out, because a state agency paying for PHP security exposes the aristocratic tipping for what it is, an imbalanced gift standing in for a wage.

The hero story also costs security.

An engineer who finds a single point of failure records it as a defect to fix. The Atlantic frames one as a tribute, with a name, to a national audience, as if single points of failure were something to celebrate. The xz backdoor in 2024 was planted by pressuring one exhausted maintainer until he accepted a new co-maintainer. This journalist profiling a volunteer as the one guy the Internet supposedly depends on is painting a huge target for attackers.

It also misreports the week. PHP2Shell carried high attack complexity, and the public evidence of compromise stayed thin. The same week brought plenty more to patch in open source:

  • Pillow, the Python imaging library, shipped 13.0.0 on 16 October with fixes for 42 advisories. Four of them received CVE records on 19 October rated 9.2 under CVSS v4.0, the same version PHP uses, and three of those four rate attack complexity high. The worst lets a crafted FlashPix file run code on an upload service that has olefile installed.
  • Node.js shipped ten fixes on 21 October, the same day as PHP, four rated high, including bypasses of TLS hostname checks and an out-of-bounds write in its bundled Brotli decoder that Node says permits remote code execution. The upstream Brotli fix describes the same bug as low severity and hard to exploit.
  • GitLab fixed CVE-2026-110264 on 21 October, rated 10.0, an integer overflow in its regular expression engine that lets an attacker run code on a self-managed server without logging in. It reaches back to GitLab 7.0 from 2014.
  • LiteLLM, a Python gateway that holds the API keys for AI providers, had its release pipeline hijacked on 21 October. For about two hours PyPI and the official Docker images shipped a credential stealer in a package with roughly 23 million weekly downloads.
  • Qdrant, the vector database, published a critical advisory on 22 October, rated 9.8, because its internal gRPC API accepts unauthenticated calls by default in distributed mode, which I formally reported myself on 9 July.

GitLab and Qdrant both outscore PHP2Shell, and both rate attack complexity low. Hey Atlantic, where’s the profile of the people doing that work so they can get a tip too? It sounds nuts because it is. People doing work shouldn’t depend on the whims of tip jars.

Days earlier, a researcher found that eight eMudhra intermediate certificate authorities had private keys anyone could recover. A botched step in eMudhra’s 2025 key ceremony produced keys that were tiny numbers, one of them just 4, and two audits missed it. That flaw reached the trust behind every HTTPS connection. Google and Mozilla blocked the keys the day the report arrived, Apple followed two days later, and the Node.js release dropped trust in them too.

Salaried root program and release teams did their jobs, and the story ended as it should. That is what infrastructure looks like when it is run like infrastructure. Imagine a tip jar on everything and you would start to ask why can’t someone just build an economic model.

Surý closed his interview by telling people to rely on the experts who know what they are doing. That is an argument for institutions.

A magazine founded by abolitionists in 1857 should know the difference between a worker and a servant, and print the porters’ demand: end the tipping injustice and pay the workers.

Shove the tips all the way back to the European aristocracy that invented them.

Home Router Vendors Should be Forced to Fix Their Certificate Warning

A social media post was asking about the hassle of a secure connection to an ISP router (using TLS), and it reminded me of the early 1990s when we used to hand-craft TCP/IP networks on 3Com, Cayman, etc. as if it was serious engineering. All that’s ancient history because everything has been made so easy that anyone can connect securely.

That being said, vendors today aren’t really doing their part to make the easy stuff easy. For example, the German company FRITZ! still tells its customers to click through a certificate warning on their own router login.

That’s just nuts.

Its help page walks users through clicking past the certificate warning in every major browser and assures them that from the home network “This does not pose a security risk.” The same page tells them to ignore the browser warnings about an unencrypted login as well, because the interface opens inside the home network and the password stays off the internet.

Matthew Wallace and I covered this attack in Securing the Virtual Environment: How to Defend the Enterprise Against Attack, published by Wiley in 2012. That’s 15 years ago! Certificate warnings and operator fatigue were among the easiest attack vectors in the book. An operator who clicks through the same warning on every login will click through an attacker’s certificate the same way, because the two warnings look identical.

Come on vendors, what are you doing?

The certificate authorities way back in November 2011 (CA/Browser Forum) adopted Baseline Requirements that phased out publicly trusted certificates for internal names and reserved IP addresses, with November 1, 2015 as the latest permitted expiry. That’s a decade gone already since everyone was supposed to be doing internal networking the right way. Look at how Let’s Encrypt now issues IP address certificates, limited to public addresses it can reach for validation. A router at 192.168.178.1 can present only a certificate its owner chose to trust, so the vendor has to give the router a public name.

All of the pieces of this puzzle have been public for years.

Year What happened
2011 CA/Browser Forum phases out public certificates for internal names and reserved IPs
2012 Our book Securing the Virtual Environment shows how certificate warnings and operator fatigue are among the easiest attack vectors
2015 Plex issues every home media server its own trusted certificate
2020 Netgear’s shared router certificates are revoked because the private key is found in public firmware
2024 An attacker registers fritz.box
2026 Let’s Encrypt issues IP address certificates, and FRITZ! still tells users to ignore the warning

Using bland generic marketing for internal name resolution has drawbacks. FRITZ! routers answer fritz.box from their own resolver, and .box is a public top-level domain. At the end of January 2024 an attacker registered fritz.box, and heise reported that the domain redirected to various websites and intercepted SSH connection attempts. AVM, now FRITZ!, won control of the domain through WIPO arbitration in May 2024. Because, duh. But also, why didn’t they think of this before? The name the vendor thought of as private had a public registration sitting open.

Netgear, by comparison, tried to shortcut the safety of real public names with a certificate. It procured a certificate for routerlogin.com and shipped the private key in its router firmware, where anyone could extract it from a router or from the firmware downloads on Netgear’s own site. The certificates were revoked after the key was exposed for being in the public. A shared key makes every router the same router, and anyone holding the firmware can impersonate it.

Plex solved the same problem in 2015 for home media servers. Plex bought DigiCert certificates for every server. Each server holds a wildcard for its own hash-named subdomain of plex.direct, and a name such as 192-168-1-7.hash.plex.direct resolves to the LAN address written into it. The key is only on a single device and the operator’s browser can verify the certificate against the name.

A router has the easier version of this, so it makes no sense why router vendors are delaying the proper solution. Plex had to tell users to switch off DNS rebinding protection, because resolvers filter public names that point at private addresses. The router is the actual resolver that DHCP assigns to every client on the network, so it can answer its own name with its LAN address directly.

Any vendor could ship this today, and regulators should demand it already.

  1. The router generates its own key pair on first boot and keeps the private key on the device.
  2. The vendor assigns each router a random, unique hostname under a domain the vendor owns and answers the DNS-01 challenge in its own zone, so the router stays closed to inbound traffic.
  3. The router’s resolver answers that hostname with the router’s LAN address.
  4. The friendly name and the bare IP serve a plain HTTP redirect to the unique HTTPS name, and the login form appears only there.
  5. The router renews through the vendor automatically and falls back to its own individual self-signed certificate if renewal fails.

FRITZ! is sitting on all the pieces and just needs to put them together. Each box that registers with MyFRITZ! receives a random, unique address ending in .myfritz.net. Since FRITZ!OS 7 the box can obtain a Let’s Encrypt certificate for that address and renew it on its own. Each box also carries an individual self-signed certificate, so FRITZ! avoided Netgear’s shared key.

FRITZ! currently points at the Internet. The Let’s Encrypt certificate requires a MyFRITZ! account, and the box opens a port to the internet during validation. AVM’s release notes state that HTTPS to fritz.box or the local IP keeps the self-signed certificate.

The FRITZ! example is useful because the change is so trivial for them and so powerful for their customers. AVM issues the myfritz.net names under its own domain, so it can answer DNS-01 for every box in its own zone. The certificate belongs in the default setup, separate from remote access, with the box answering its myfritz.net name with its LAN address and fritz.box serving a redirect to it.

First setup remains the one exception. A new router reaches setup before its WAN connection is up, and a certificate installed at the factory would expire (public certificates are already capped at 200 days and drop to 47 days in March 2029). So the first session would be on the box’s own self-signed certificate, and the vendor can print its fingerprint on the label next to the Wi-Fi key it already prints.

Speaking of printing keys, here’s a fun history fact: when I met with 3Com in 1999 to evaluate their very first ever WEP-capable access point, the plastic case had the passwords embossed into it (AirConnect at Networld+Interop). Literally four hard-printed passwords in the white plastic. “What were you thinking” I asked with my mouth open in shock. “Nobody will ever use WEP if it’s not easy enough” they said. I’m not sure they were right, but I remember one of the worst concepts of secret keys ever. See also CVE-2001-0352.

SNMP agents in 3Com AirConnect AP-4111 and Symbol 41X1 Access Point allow remote attackers to obtain the WEP encryption key by reading it from a MIB when the value should be write-only…

Like, nobody at 3Com said “maybe a sticker would be better than designing the hardcase mold for the same four WEP keys to be fixed forever for everyone”. Talk about planned obsolescence. Sad history fact: 3Com is no more.

FRITZ! gets the Internet side right but still hasn’t closed the gap on the home network. They have had the solution since FRITZ!OS 7 and it’s long past time to get it done right, the easy way.