diff --git a/.claude/skills/adding-a-thought/SKILL.md b/.claude/skills/adding-a-thought/SKILL.md index d03af4d..0f8045f 100644 --- a/.claude/skills/adding-a-thought/SKILL.md +++ b/.claude/skills/adding-a-thought/SKILL.md @@ -38,6 +38,15 @@ The voice is DESIGN.md "Wording": first person, short sentences, plain words, no - Figures carry the ideas that are easier to see than to read. Use `figure.anim` (DESIGN.md "Animated diagram"): a drawing that plays once on screen, a two-state switch, parts to tap, a running token. Draw a narrow version (`.dg-n`) for phones. Use only the `.dg` classes, no colours, no `style` attributes. - End with what Tim takes from it: a rule, a draft, a file, or open questions. +Write for a technical reader who does not know every concept. Tim's feedback on encrypted-patches (12 Nov 2026): the TUF and drand parts were too short and had too many new words, and the games and patents sections felt meaningless. + +- Explain each new term where it first appears, in one plain sentence: what it is, then why it matters here. "A bug that is already fixed and public is called an n-day." A name alone (TUF, Uptane, drand, tlock) is not an explanation. +- Give a mechanism the room it needs. If the argument rests on it, explain how it works in a few short paragraphs, with an everyday comparison where one fits. Do not compress it into a list of terms. +- Every section must carry the argument. End a detour or an example with what it teaches for the idea ("So the lesson from games is four rules"). If it teaches nothing, cut it or fold it into the section it serves. Background such as patents gets one short paragraph with the practical consequence. +- Use few numbers in a row. After a dense list, say in one sentence what the numbers show. +- Check every new explanation against a primary source, like any other claim. +- If the thought will be read aloud, use the skill `narrating-a-thought` too. Text that reads well aloud also reads well on the page. + ## 5. The page Copy `thoughts/humans-md/index.html` and keep its structure: diff --git a/.claude/skills/narrating-a-thought/SKILL.md b/.claude/skills/narrating-a-thought/SKILL.md new file mode 100644 index 0000000..34f0cfa --- /dev/null +++ b/.claude/skills/narrating-a-thought/SKILL.md @@ -0,0 +1,79 @@ +--- +name: narrating-a-thought +description: Use when Tim wants a thought on t7d.dev read aloud, narrated, turned into audio or a podcast, given read-along highlighting, or explained by a voice. Also use when the narration script, the voice, the ElevenLabs audio, narration.json or assets/narration.js must change, or when a narrated page feels restless, hides its diagram on a phone, or loses the listener. +--- + +# Narrating a thought + +A narrated thought works two ways from one recording: Tim reads and listens at the same time, or he listens on the go with the screen off. The voice tells more than the page: it explains every figure and bridges the sections. The page follows the voice calmly and never hides the figure that the voice explains. + +The design was tested with Tim on 12 Nov 2026, first in a prototype, then on `thoughts/encrypted-patches/`, the reference page. Do not reopen these decisions unless Tim asks. The research behind them is in `attention-research.md`. + +## Audio costs credits: generate only when Tim says so + +- Generate ElevenLabs audio only when Tim says that the text of the thought is final and must be narrated. Approval of a cost estimate is not that instruction. +- Do not make voice samples. The voice is chosen (see the table). +- Until then, the page runs on simulated timing (about 160 words a minute). Tim reads along and judges the text, the spoken parts and the figures without audio. +- Do not read, print or commit the key. It is in `~/.config/wortzauber/elevenlabs.key`. Send it only as the `xi-api-key` header. +- Before a generation, tell Tim the character count. After it, tell him what it used. + +## How it is built + +| Part | Where | +| --- | --- | +| Player, marker, cues, scrolling | `assets/narration.js` (no inline script, the CSP stays strict). The page loads it with ` + @@ -48,7 +49,7 @@

Encrypted patches, unlocked on patch day

Status
Draft
Started
-
Last revised
+
Last revised
@@ -57,70 +58,90 @@

Encrypted patches, unlocked on patch day

On this page

  1. The problem
  2. -
  3. What games do
  4. +
  5. The idea
  6. A design
  7. Without a key server
  8. Air-gapped sites
  9. Open source in private
  10. What it does not fix
  11. -
  12. Prior art and patents
  13. +
  14. Prior art
  15. +
  16. What I take from it
  17. Sources
  18. Revisions
  19. Feedback
-
+
+

SpokenEncrypted patches, unlocked on patch day. A thought by Tim Conrad, read aloud. It takes about twenty minutes, in ten short chapters. Three words carry the idea. Patch day, the moment a fix becomes public, written as T. The encrypted bundle, which arrives early. And the key, which arrives at T. When a figure comes up, the narration describes it, so you can listen without the screen.

The problem

-

A security fix tells an attacker where the bug was. That was always true. What changed in the last year is the price of turning a fix into an exploit.

-

Keycloak is a good example. Between November 2025 and November 2026 the project tagged 47 releases, about one every eight days, across four supported lines, and fixed at least 50 CVEs [1]. In August 2026 one of them, CVE-2026-18963, let an unauthenticated attacker take over accounts through the password-reset flow [2]. The fixed builds carry tag dates a week before the CVE was published [1], and the public fix is a small change of 57 added lines [3]. A public proof of concept credits Claude for "research and PoC development assistance" and ships "the annotated patch diff" [4]. A team that runs Keycloak has to patch every week, and every patch is a map for someone else.

-

The numbers behind that feeling are from 2026:

+

A security fix tells an attacker where the bug was. That was always true: compare the old and the new version, a step called patch diffing, and the change points at the bug. What changed in the last year is the price of turning a fix into an exploit.

+

Keycloak is a good example. Between November 2025 and November 2026 the project tagged 47 releases, about one every eight days, across four supported lines, and fixed at least 50 CVEs [1]. In August 2026 one of them, CVE-2026-18963, let an unauthenticated attacker take over accounts through the password-reset flow [2]. The fixed builds carry tag dates a week before the CVE was published [1], and the public fix is a small change of 57 added lines [3]. A public proof of concept credits Claude for "research and PoC development assistance" and ships "the annotated patch diff" [4]. A team that runs Keycloak has to patch every week, and every patch is a map for someone else.

+

A bug that is already fixed and public is called an n-day. One that nobody has fixed yet is a zero-day. The numbers for n-days are from 2026:

+

SpokenThree numbers to keep from that list: an exploit from a patch in under an hour, for about two thousand dollars, and attacks that begin within days of the fix.

Finding a new bug with AI works, but it is a search, and search costs. XBOW spent about $40,000 on API calls for a six-day campaign that produced a full Chrome exploit chain [10]. Anthropic's OpenBSD campaign took about 1,000 runs for under $20,000, and the FFmpeg one about $10,000 [11]. A patch removes the search: it says where to look.

- + What it costs: finding new bugs against exploiting patched ones Log scale. Finding new bugs, per campaign: XBOW Chrome full chain about 40,000 dollars; Anthropic OpenBSD about 1,000 runs under 20,000 dollars; Anthropic FFmpeg about 10,000 dollars. Exploiting a patched bug, per exploit: Windows kernel exploit about 2,000 dollars; Linux kernel n-day under 1,000 dollars; Windows crash proof of concept about 120 dollars. $100$1k$10k$100k - Find new bugs · per campaign - Exploit a patched bug · per exploit + + Find new bugs · per campaign XBOW · Chrome full chain, 6 days~$40k Anthropic · OpenBSD, ~1,000 runs<$20k - Anthropic · FFmpeg, some 100 runs~$10k - Windows kernel exploit, from patch~$2k - Linux kernel n-day exploit<$1k - Windows crash PoC, from patch~$120 - + Anthropic · FFmpeg, some 100 runs~$10k + Exploit a patched bug · per exploit + Windows kernel exploit, from patch~$2k + Linux kernel n-day exploit<$1k + Windows crash PoC, from patch~$120 + + What it costs: finding new bugs against exploiting patched ones + $100$1k$10k$100k + Find new bugs · per campaign + XBOW · Chrome chain~$40k + Anthropic · OpenBSD<$20k + Anthropic · FFmpeg~$10k + Exploit a patched bug · per exploit + Windows kernel, from patch~$2k + Linux kernel n-day<$1k + Windows crash PoC~$120 + +

SpokenFigure one compares costs on a log scale: each grid line to the right means ten times more money. The top group is finding new bugs, one whole campaign per bar. About forty thousand dollars for a Chrome exploit chain, under twenty thousand for OpenBSD, about ten thousand for FFmpeg.

SpokenThe bottom group is exploiting a bug that a patch already gave away, one exploit per bar. About two thousand dollars for Windows, under one thousand for Linux, and about a hundred and twenty for a crash proof of concept. The costs in the bottom group are ten to a hundred times lower. That difference is what a patch gives away.

Fig. 1 · Cost per result on a log scale, from [5], [10] and [11]. Discovery is a whole campaign, the n-day rows are one exploit each. Some discovery is cheaper: depthfirst reports 21 FFmpeg bugs for about $1,000 [12].
-

The idea of this post: ship the fix days early, but encrypted. Teams download it, plan the change and stage it. At patch day T, only the key is published, and everyone applies the fix at the same moment. Nobody could diff it before T. The goal is not to win the race against the attackers, but to stop it from being a race.

+

SpokenPause here for a moment. How many days does your team need from a published fix to production?

+ +

The idea

+

The idea of this post: ship the fix days early, but encrypted. Teams download it, plan the change and stage it. At patch day T, only the key is published, and everyone applies the fix at the same moment. Nobody could diff it before T. The goal is not to win the race against the attackers, but to stop it from being a race.

- + Timeline: today and with an encrypted pre-load Today the attacker can diff the patch as soon as the first host downloads it at T, while installs spread over weeks. With a pre-load, the encrypted bundle arrives in the week before T, the key arrives at T, and automatic updates install within minutes, while the attacker also only starts at T. T · patch day - Today + Today installs spread over weeks - + diff → exploit from the first download - nothing on the hosts yet + nothing on the hosts yet - Pre-load + Pre-load encrypted bundle on every host - + installed within minutes - + diff → exploit - same start line + same start line 32-byte key published @@ -128,13 +149,35 @@

The problem

T +7 days + + Timeline: today and with an encrypted pre-load + + T · patch day + Today + nothing on hosts + installs: weeks + diff → exploit + from first download + + Pre-load + bundle on hosts + in minutes + diff → exploit + same start line + + 32-byte key published + + −7 days + T + +7 days + +

SpokenFigure two shows two timelines around patch day T, the vertical line in the middle. The top row is today. Nothing is on the hosts before T. At T the patch goes out, installs spread over weeks, and an attacker can diff it from the first download.

SpokenThe bottom row is the pre-load. The encrypted bundle sits on every host during the week before T. At T only the thirty-two byte key is published. Hosts that update by themselves install within minutes, and the attacker starts at the same moment as everyone else.

Fig. 2 · With a pre-load, the attacker and the defenders start at the same moment, and hosts that update by themselves are done within minutes.
- -

What games do

-

Games have done this for years. A pre-load puts the game on your disk before launch, and it opens only at release. Steam, as SteamDB describes it, encrypts each depot with AES-256 and one key that is the same for every user, so mirrors and caches can serve the same bytes, and only owners can ask for the key [13].

-

GTA Online shows the other side. Rockstar ships the content of later updates early inside earlier ones and switches it on from its servers. The files are encrypted, but the keys are in the game, so dataminers read upcoming cars and missions long before they go live. A server switch decides when something is available. It does not keep it secret while the key sits on the device.

-

For patches, four rules follow:

+

SpokenHas anyone shipped something locked before? Games do it all the time.

+

Games already ship this way, and at a scale that no patch reaches. A pre-load puts a new game on your disk days before launch, and it opens only at release. Steam, as SteamDB describes it, encrypts each depot with AES-256 and one key that is the same for every user, so mirrors and caches can serve the same bytes, and only owners can ask for the key [13]. That is the half I want: millions of copies in place before the moment, and one small key at the moment.

+

GTA Online shows what goes wrong. Rockstar ships the content of later updates early inside earlier ones and switches it on from its servers. The files are encrypted, but the keys are in the game, so dataminers read upcoming cars and missions long before they go live. For a patch, that would undo everything: with the key on the device, anyone can diff the fix before T.

+

So the lesson from games is four rules for patches:

+

SpokenThose four rules are easy to write down. The next question is how to build them on update systems that already exist.

A design

-

The update frameworks TUF and Uptane already solve most of this: an offline root key, roles with narrow rights, thresholds of signatures, and protection against rollback and freeze attacks [14][15]. Uptane even names patch diffing as an attacker goal and can carry wrapped keys for encrypted images. What they lack is a key that is published later. The design adds one role for that.

+

A signature on the patch alone is not enough. If the one signing key leaks, the thief can sign malware. A mirror can also cheat without any key. It can serve an older version with a known bug, a rollback attack. Or it can keep serving yesterday's list of updates, so the client never learns that a fix exists, a freeze attack.

+

The Update Framework, TUF, was designed against exactly these attacks [14]. It splits trust into roles, and each role has its own keys:

+ +

A role can also require a threshold: k of its n keys must sign, so one stolen key is not enough. Uptane is TUF adapted for cars [15]. It adds a second repository, the director, which tells each vehicle which images to install, and the director can encrypt images for each control unit. The Uptane standard even names patch diffing as an attacker goal.

+

What neither has is a key that is published later. The design adds one role for that, the release role, next to targets:

  1. Pre-load. Days before T, the vendor publishes the encrypted bundle as an ordinary target. The manifest with its hash, size and release time is signed by the targets role under the organisation's root key. Clients download it and check the hash.
  2. -
  3. Release. At T a separate release role signs a short statement: patch id, hash of the ciphertext, the 32-byte content key. A threshold, say two of three officers, keeps one person from releasing early.
  4. -
  5. Log. Every statement goes into an append-only transparency log, so a release before T, or a different key for some customers, can be seen [16].
  6. +
  7. Release. At T the release role signs a short statement: patch id, hash of the ciphertext, the 32-byte content key. A threshold keeps one person from releasing early: say three officers each hold a key, and any two of them must sign.
  8. +
  9. Log. Every statement goes into a transparency log. That is a public list that only grows: entries can be added but not changed or removed, and anyone can check that an entry is in it. Certificate Transparency uses such logs for TLS certificates [16]. Anyone who watches the log sees a release before T, or a different key for some customers.
  10. Install. The client checks the statement and the log entry, decrypts with the key and installs.
-
- +
+ Who signs what An offline organisation root key delegates to a targets role and a release role. Days before T the targets role signs a manifest with the hash of the encrypted bundle, and mirrors carry both. At T a release role, two of three officers, signs a key-release statement that is written to a transparency log. The client verifies the manifest, the bundle hash, the statement signature and the log entry, then decrypts and installs. Organisation @@ -197,15 +250,36 @@

A design

5 decrypt, install AES-GCM, key from 4 -
-
    -
  1. The organisation’s root key stays offline. It gives two roles their rights: one signs the manifest, the other releases keys.
  2. -
  3. Days before T the targets role signs the manifest, and mirrors carry it together with the encrypted bundle.
  4. -
  5. Every client checks the manifest against the organisation key and the bundle against the manifest. Then it waits; its clock opens nothing.
  6. -
  7. At T two of three release officers sign the key-release statement, and it goes into the public log.
  8. -
  9. The client checks the statement and its log entry, decrypts the bundle with the key and installs.
  10. + + Who signs what + Organisation + org root keyoffline · delegates roles + + targets rolesigns the manifest + release role2 of 3 officers + −7 days + manifest + bundlehash, size, id, T + + at T + key releaseid, hash, key · 104 B + transparency logappend only, public + + Client + + 1 check manifestagainst org key + 2 check bundlehash from manifest + 3 wait for Tthe key opens, not the clock + 4 check statementsignature, log proof + 5 decrypt, installAES-GCM, key from 4 + +

    SpokenFigure three shows who signs what, in three parts: the organisation, the mirrors and the log, and the client. It builds up in five steps, one for each line below the drawing.

    +
      +
    1. The organisation’s root key stays offline. It gives two roles their rights: one signs the manifest, the other releases keys.
    2. +
    3. Days before T the targets role signs the manifest, and mirrors carry it together with the encrypted bundle.
    4. +
    5. Every client checks the manifest against the organisation key and the bundle against the manifest. Then it waits; its clock opens nothing.
    6. +
    7. At T two of three release officers sign the key-release statement, and it goes into the public log.
    8. +
    9. The client checks the statement and its log entry, decrypts the bundle with the key and installs.
    -
Fig. 3 · Two roles under one offline root. The release role can only publish keys for ciphertext that is already pinned, so a stolen release key cannot push code.

The statement is small and public, so any mirror, CDN or even DNS can carry it. That makes the release hard to block.

@@ -219,10 +293,12 @@

A design

Without a key server

The key server is the weak spot. It can go down at the wrong moment, someone can force it to wait, or someone can leak the key early. There is a way to release a key on time without any server of the vendor.

-

A public service called drand publishes a new signed number every three seconds, and each number has a sequence position. A group of independent organisations runs it together, the League of Entropy. No single member can make the number for a position alone: it takes enough of them together, and they make it only when that moment has come [17].

-

The trick: you can lock data to a number that does not exist yet. The vendor picks the position that falls on patch day T and locks the patch key to it. Until T nobody, the vendor included, can open the lock. At T drand publishes the number, and that number opens it. The free tool tlock does exactly this [17].

-
- +

drand is a public randomness beacon [17]. Every three seconds it publishes a new round: a round number and a value. The value is a signature over the round number, made with a key that nobody holds as a whole. When the network was set up, its members, a group of independent organisations called the League of Entropy, split that key into shares, and each member keeps one share.

+

For each round, every member signs the round number with its share when that round's time has come. Enough of these partial signatures together give the full signature, and anyone can check it against one public key that never changes. Cryptographers call this a threshold signature. So nobody can compute the value of a future round, not even a member alone. It takes enough members, and honest members sign a round only at its time.

+

The second part is a kind of encryption where the key can be a name. In identity-based encryption, anyone can encrypt to a name, an email address for example, with one public master key. The private key for that name is made later, by whoever holds the master secret. In drand, the name is a round number, the master key is drand's public key, and the signature for a round is the private key for it [17]. The master secret is the split key of the League, so the private key for a round appears only when the members sign that round.

+

So the vendor picks the round that falls on patch day T and encrypts the patch key to that round. Until T nobody, the vendor included, can decrypt it. At T drand publishes the signature for that round, and the signature opens it. The free tool tlock, from the drand team, does exactly this [17].

+
+ How a drand number opens a patch key at patch day Independent organisations make a new numbered value every three seconds; the value for a position exists only when enough of them have taken part, at that moment. Days before patch day the vendor locks the patch key to the value at position T, which does not exist yet. At T the organisations make that value, it is published, and anyone can use it to open the lock and install the patch. League of Entropy @@ -253,14 +329,26 @@

Without a key server

patch key → install -
-
    -
  1. drand makes a new value every three seconds. Values for later moments do not exist yet.
  2. -
  3. Days before T the vendor locks the patch key to the value at T. Nobody can open it now, the vendor included.
  4. -
  5. At T enough of the organisations together make the value for T. Not every one is needed.
  6. -
  7. The value is public. It opens the lock, and everyone installs the patch.
  8. + + How a drand number opens a patch key at patch day + League of Entropyorg Aorg Borg Corg Dorg E + T + drand valuesone every 3 seconds + publishednot made yet + Vendor · before T + key, locked + to the value at T + Everyone · at T + T opens it + key → install + +

    SpokenFigure four has three layers. At the top, the organisations of the League of Entropy. In the middle, the row of drand values, one every three seconds, with the value for T marked. At the bottom, the vendor on the left and everyone else on the right. It builds up in four steps.

    +
      +
    1. drand makes a new value every three seconds. Values for later moments do not exist yet.
    2. +
    3. Days before T the vendor locks the patch key to the value at T. Nobody can open it now, the vendor included.
    4. +
    5. At T enough of the organisations together make the value for T. Not every one is needed.
    6. +
    7. The value is public. It opens the lock, and everyone installs the patch.
    -
Fig. 4 · The lock points at a value that does not exist yet. Only the organisations together can make it, and only at T.

The vendor can use both ways at once: its own key server and the drand lock. Then the patch opens at T even if the vendor's server is down. Two limits remain:

@@ -273,7 +361,7 @@

Without a key server

Air-gapped sites

Offline networks already carry updates in on removable media. With a pre-load, the large part crosses days before T and can be checked against the organisation's key. At T only the key has to cross: the signed statement, or the 48-byte drand number for T, which the site checks against drand's public key, stored there in advance [17]. Either fits in one QR code, which holds up to 2,953 bytes [18], or can be typed in as hex.

- + Updates for an air-gapped site Days before T, the encrypted bundle and its signed manifest cross the air gap on removable media, gigabytes in size. At T only a key-release statement of about 104 bytes, or a 48-byte drand number, crosses, small enough for one QR code. The offline site checks both against pinned keys, then decrypts and installs. @@ -308,15 +396,30 @@

Air-gapped sites

48 B drand no. + + Updates for an air-gapped site + Connected + vendor mirrorbundle, manifest, key release + + days before TUSB or discbundle · gigabytes + at T + + QR code104 B statementor 48 B drand no. + air gap + + Offline site + stored early: org key, drand public keyat T: verify offline, decrypt, install + +

SpokenFigure five has three zones: the connected network, the air gap, and the offline site. Days before T, the encrypted bundle crosses on a USB stick or a disc, gigabytes in size. At T only a QR code crosses: a signed statement of about a hundred bytes, or the forty-eight byte drand value. The site checks it against keys that it stored earlier, then decrypts and installs.

Fig. 5 · The gigabytes cross early. At T only a few bytes cross, and they are public, so the channel needs to reach the site, not to be secret.

A checked drand number also proves that its moment has passed. A site without a reliable clock learns that it is at least that late.

Open source in private

For an open-source project the hard part comes earlier: the fix has to be written and tested without showing it. Today it often shows. In the Keycloak case the fixed builds were tagged a week before the CVE, the port to the main branch was a public pull request whose title does not mention security, and the proof of concept was written from that diff [3][4].

-

The tools for private work are thin. On GitHub, maintainers can open a temporary private fork from a security advisory. Only invited collaborators see it, but no CI runs there, branch protection does not apply, and merging and publishing are manual steps [19]. On GitLab a merge request in a public project is public; private work needs a separate private fork [20]. Distributions coordinate by mail: the linux-distros list allows an embargo of at most 14 days [21], and the kernel security team holds a fix back for at most 7 days, 14 in exceptional cases [22]. The Git project comes closest to the idea of this post: it prepares signed tags in a private repository, sends a bundle to the distributions less than a week ahead, and pushes in public on release day [23]. That bundle is plaintext and goes to a few.

+

The tools for private work are thin. On GitHub, maintainers can open a temporary private fork from a security advisory. Only invited collaborators see it, but no CI runs there, branch protection does not apply, and merging and publishing are manual steps [19]. On GitLab a merge request in a public project is public; private work needs a separate private fork [20]. Distributions coordinate by mail, under an embargo: a fixed time in which everyone who knows about the bug keeps quiet. The linux-distros list allows an embargo of at most 14 days [21], and the kernel security team holds a fix back for at most 7 days, 14 in exceptional cases [22]. The Git project comes closest to the idea of this post: it prepares signed tags in a private repository, sends a bundle to the distributions less than a week ahead, and pushes in public on release day [23]. That bundle is plaintext and goes to a few.

- + A security fix in an open-source project, from private work to release The maintainers write and test the fix on a private branch with private CI. Days before T the project publishes the encrypted, signed build. The embargo list of distributions gets the key early to test. Everyone else stages the ciphertext. At T the key is published, everyone applies the fix, and the public repository gets the merge and the advisory. @@ -342,7 +445,24 @@

Open source in private

T +6 days -
Fig. 6 · Work in private, publish the ciphertext early, open it for everyone at T. The embargo list keeps what it has today: early access to test.
+ + A security fix in an open-source project, from private work to release + T · release + Maintainersprivate work, CI + + Releaseencrypted, signed + key published + Embargo listearly key + Everyonestaged + apply at T + Public repomerge + advisory + + −10 days + T + +6 days + +

SpokenFigure six is a timeline with five rows, from ten days before T to six days after. The maintainers work on a private branch with private CI. Then the encrypted, signed build is published. The embargo list gets the key early to test, and everyone else stages the ciphertext. At T the key is published, everyone applies the fix, and the public repository gets the merge and the advisory.

+
Fig. 6 ·Work in private, publish the ciphertext early, open it for everyone at T. The embargo list keeps what it has today: early access to test.

To make this normal, a forge such as GitHub or GitLab would need (Fig. 7):

    @@ -351,8 +471,8 @@

    Open source in private

  • Release artefacts that are published encrypted and signed, with the key held by the forge.
  • One action that, at T, publishes the key, merges the branch and publishes the advisory.
-
- +
+ What a forge would need for a private fix in a public repository Inside the public repository a private branch holds the fix; only maintainers and a security role see it. Private CI with closed logs tests it. Days before T the forge publishes the encrypted, signed release, and the embargo list gets the key early. At T one action publishes the key and the advisory and merges the branch, and everyone applies the fix. @@ -368,18 +488,34 @@

Open source in private

encrypted release, signedembargo listearly key: test mergekey + advisoryeveryoneapplies at T -
-
    -
  1. The fix is written on a private branch inside the public repository. Only the maintainers and a security role can see it.
  2. -
  3. Private CI builds and tests the branch. Its logs stay closed.
  4. -
  5. Days before T the forge publishes the encrypted, signed release. The embargo list gets the key early and tests.
  6. -
  7. At T one action publishes the key and the advisory and merges the branch. Everyone applies the fix.
  8. + + What a forge would need for a private fix in a public repository + Public repository + T + main · public + + private branchmaintainers + security role + + CI, closed logs + releases + encrypted release + embargo listearly key: test + merge + key + advisory + everyoneapplies at T + +

    SpokenFigure seven shows what this looks like inside one public repository, in four steps.

    +
      +
    1. The fix is written on a private branch inside the public repository. Only the maintainers and a security role can see it.
    2. +
    3. Private CI builds and tests the branch. Its logs stay closed.
    4. +
    5. Days before T the forge publishes the encrypted, signed release. The embargo list gets the key early and tests.
    6. +
    7. At T one action publishes the key and the advisory and merges the branch. Everyone applies the fix.
    -
Fig. 7 · What a forge would need for a private fix in a public repository.

The embargo lists fit into this as they are: their members get the key early and test, everyone else gets the ciphertext early. Each early key is a chance to leak, so the list stays short and the embargo stays short.

+

SpokenThat is the design. Here is what it does not solve.

What it does not fix

  • Diffing after T. At T the patch is public. The scheme moves the start line; it does not stop the race. It helps the hosts that install at once.
  • @@ -389,16 +525,14 @@

    What it does not fix

  • Insiders. The key exists before T. Create it late, keep it in an HSM, split it between people.
  • Testing. Companies test patches before they roll them out. Most can stage before T but test only after it. Early keys for a few, as embargo lists do today, bring back the risk of leaks.
+

SpokenWhich of these limits matters most for your systems?

-

Prior art and patents

-

The idea is not new, and the patents below show it. I found no vendor that does it for security patches today.

-

Microsoft has patents on it. They are old, but they matter now. This is my reading, not legal advice, and I could not open the claims or the fee records:

-
    -
  • US 7,876,902, "Distribution of encrypted software update to reduce attack window", priority date 31 August 2006, granted 2011 [24]. A US patent runs 20 years from filing, so it ends around 31 August 2026, later only if the patent office added term for its own delays, and earlier if a maintenance fee was not paid. Its description releases the key once enough machines have the update or after testing, not at a fixed time.
  • -
  • US 8,171,560, "Secure content pre-distribution to designated systems", granted 2012 [25]. It is closer to this post: content goes out encrypted and the key follows at a set moment. Filed around 2008, it may run to about 2028.
  • -
-

So the design can be built from public parts, and a fixed release time, a transparency log and a public beacon in place of a vendor key server differ from the first patent's description. Whether that is enough depends on the claims. Anyone who wants to ship this as a product in the US before about 2028 should have a patent attorney read both patents first.

-

My conclusion: the tool is cheap for an update system that already signs its metadata. It does not stop patch diffing, and with LLMs diffing is now cheap. It lets every team have the fix ready when it becomes public, and that turns patch day from a race into a date.

+

Prior art

+

The idea is not new. Microsoft patented an encrypted update with a key that follows later, first in 2006 [24] and in a version with a set release moment around 2008 [25]. I found no vendor that does it for security patches today. By my reading, which is not legal advice, the first patent ends around August 2026 and the second may run to about 2028. Anyone who wants to ship this as a product in the US before then should have a patent attorney read both.

+ +

What I take from it

+

The tool is cheap for an update system that already signs its metadata. It does not stop patch diffing, and with LLMs diffing is now cheap. It lets every team have the fix ready when it becomes public, and that turns patch day from a race into a date.

+

SpokenTo sum up. Patches are now cheap to turn into exploits. Ship the fix early but encrypted, publish only the key at T, and every team gets the same start line. The parts exist: TUF or Uptane for the signatures, a transparency log for the release, and drand with tlock for a release without a key server. The sources are on the page.

Sources

    @@ -418,7 +552,7 @@

    Sources

  1. The Update Framework specification.
  2. Uptane Standard.
  3. RFC 9162: Certificate Transparency 2.0; Sigstore Rekor.
  4. -
  5. drand: tlock.
  6. +
  7. drand: tlock; quicknet is live, Oct 2023 (a round every 3 seconds); Gailly, Melissaris and Romailler: tlock: Practical Timelock Encryption from Threshold BLS, IACR ePrint 2023/189.
  8. ISO/IEC 18004 capacity table, summarised by Keyence.
  9. GitHub Docs: Collaborating in a temporary private fork.
  10. GitLab Docs: Confidential merge requests.
  11. @@ -431,6 +565,7 @@

    Sources

    Revisions

      +
    • Rewrote it to be read aloud and for readers who do not know every term: explained patch diffing, n-days, TUF, Uptane, transparency logs, drand and timelock encryption; folded the games section into "The idea" and cut the patents to one paragraph; added a narration with spoken parts.
    • First version, as a blog post.
    diff --git a/thoughts/encrypted-patches/narration.json b/thoughts/encrypted-patches/narration.json new file mode 100644 index 0000000..ed1a734 --- /dev/null +++ b/thoughts/encrypted-patches/narration.json @@ -0,0 +1,30 @@ +{ + "title": "Encrypted patches, unlocked on patch day", + "voice": "Jonathan Livingston", + "audio": null, + "timing": null, + "chapters": [ + ["say-intro", "Introduction"], + ["problem", "The problem"], + ["idea", "The idea"], + ["say-design", "A design"], + ["beacon", "Without a key server"], + ["airgap", "Air-gapped sites"], + ["oss", "Open source in private"], + ["say-limits", "What it does not fix"], + ["prior", "Prior art"], + ["take", "What I take from it"] + ], + "spoken": {}, + "cues": [ + {"in": "say-fig1", "p": "log scale", "until": "The top group", "sel": ".cue-scale", "cls": "hot"}, + {"in": "say-fig1", "p": "The top group", "until": "The bottom group", "sel": ".cue-find", "cls": "hot"}, + {"in": "say-fig1", "p": "The bottom group", "until": "That difference", "sel": ".cue-exploit", "cls": "hot"}, + {"in": "say-fig1", "p": "The costs in the bottom group", "sel": ".cue-exploit [data-c]"}, + {"in": "say-fig2", "p": "The top row is today", "until": "The bottom row", "sel": ".cue-today", "cls": "hot"}, + {"in": "say-fig2", "p": "an attacker can diff", "sel": ".cue-today [data-c]"}, + {"in": "say-fig2", "p": "The bottom row", "until": "Has anyone shipped", "sel": ".cue-preload", "cls": "hot"}, + {"in": "say-fig2", "p": "install within minutes", "sel": ".cue-preload [data-c=green]"}, + {"in": "say-fig2", "p": "the attacker starts", "sel": ".cue-preload [data-c=red]"} + ] +}