This issue records evidence and asks for a decision. It does not propose cutting a release — that is the maintainer's call.
v0.4.2 is the only release, it has downloadable assets, and two client-side security fixes have landed on master since it was tagged. One of them the project classified in its own commit message as a passive decryption break. (An earlier draft of this line said "at least three" and was refuted by this issue's own correction section below; the number is the whole point of the issue, so it should not have been left contradicting itself.)
Evidence
v0.4.2 was tagged 2026-08-23T11:58:03Z.
1. All-zero X25519 shared secret is not rejected (#153)
Fix is commit 47ab00c, "tls: abort on an all-zero X25519 shared secret (#153)".
$ git tag --contains 47ab00c
# empty — in no tag
The commit landed after v0.4.2 was tagged, so no cherry-pick could have carried it. Its own message describes the impact: a server, or an attacker who rewrites one ServerHello in passing, can send a low-order key_share and force every handshake and traffic key to be a function of the two plaintext hello messages. Any passive observer who recorded the session can then derive the traffic keys, without staying on the path.
Also unreleased: tools/test_ecdh_zero_check.py, the suite that covers it.
2. Handshake-message sequence is not enforced (#152, PR #160)
Fix is commit d0c9ed3, "tls: enforce the handshake message sequence (#152)" — TLS_HS_SEQ_CHECK / src/tls_hs_seq.inc, the shared DF_ERR_SEQ rejection in both dispatchers.
$ git tag --contains d0c9ed3
# empty
This one changes shipped 6502 code in src/tls_deframe.s and src/tls13.s, so released images genuinely lack the check. Also unreleased: tools/test_hs_sequence.py.
A correction to how this was originally scoped
#163 was suggested to me as a third unreleased security fix. It is not one, and I am recording that rather than repeating it. f3b39d9 is "rigs: fail closed offline when the PRG cannot pass the SAN check (#141)" — a change to test-rig preconditions, not to any shipped 6502 code. It does not affect what a released PRG does, and folding it into a security-release argument would overstate the case. Two client-side fixes are unreleased, not three.
A documentation artifact worth recording separately
README on master credited the all-zero check to "Since v0.4.3". There is no v0.4.3, locally or on the remote — the tag list ends at v0.4.2. The false reference was written by the fix's own author in that same commit, forward-looking to a release that never happened, and it survived until now. Anyone reading the README would have concluded the fix was shipped. Corrected in #192.
The v0.4.2 images also carry a registrable third-party hostname
Independent of the above, and relevant to how a released image behaves if someone runs it unmodified.
The packaging scripts never set HTTPS_HOST, so released images carry the Makefile default. At the v0.4.2 tree that default is www.foo.bar:
$ git show v0.4.2:Makefile | grep 'HTTPS_HOST ?='
HTTPS_HOST ?= www.foo.bar
.bar is a delegated gTLD with live nameservers, so www.foo.bar is a name a third party can register. The rename to www.foo.invalid — RFC 2606 / RFC 6761 reserved, never delegated, cannot resolve — is commit cdf02b4 (PR #164, 2026-08-30) and is in no tag:
$ git tag --contains cdf02b4
# empty
Currently NXDOMAIN, so this is latent rather than live. But it combines badly with items 1 and 2: an image with no certificate chain validation, no server-name validation on the ip65 product, and no all-zero-shared-secret check would dial an attacker-controlled host on its first GET if that domain were ever registered.
Footnote — a third unreleased fix that is NOT a crypto break
Deliberately kept out of the list above so it cannot be miscounted as a third client-side security fix, but recorded because it bears on the release decision.
8c4b389, "uci: start CIA1's TOD, so the bounded waits are actually bounded (#145)". Untagged, and it touches shipped 6502 code (src/net/uci/net.s, src/net/uci/uci_cmd.s):
$ git tag --contains 8c4b389
# empty
Before it, CIA1's TOD was never started — it is halted out of reset and nothing in the KERNAL starts it — so every UCI spin-wait that believed itself wall-clock bounded was in fact unbounded on hardware. That is a fail-unsafe hang, not a confidentiality or authentication break, which is why it is a footnote rather than item 3. It is also UCI-only, so it affects the two UCI products and not ip65-onchip.
Worth knowing that VICE cannot catch a regression here (it runs the TOD from reset), so the guard is tools/uci/boot_check.py and it needs real hardware.
The decision being asked for
Any of these is a reasonable answer; the point is that it is recorded:
- Cut a release from master.
- Annotate the v0.4.2 release page with what it lacks.
- Do neither, and note here why (e.g. this is explicitly a demonstration project that already says "not cryptographically secure" at the top of its README).
Until it is decided, #192 states in the README that the all-zero check is master-only and links here.
Method note
Every claim above is checkable offline from this repo with git tag --contains and git show <tag>:<path>. The general trap it came out of: a fix being on master says nothing about it being in a release, and a README written at merge time will describe the world the author expected rather than the world that shipped.
This issue records evidence and asks for a decision. It does not propose cutting a release — that is the maintainer's call.
v0.4.2 is the only release, it has downloadable assets, and two client-side security fixes have landed on master since it was tagged. One of them the project classified in its own commit message as a passive decryption break. (An earlier draft of this line said "at least three" and was refuted by this issue's own correction section below; the number is the whole point of the issue, so it should not have been left contradicting itself.)
Evidence
v0.4.2was tagged 2026-08-23T11:58:03Z.1. All-zero X25519 shared secret is not rejected (#153)
Fix is commit
47ab00c, "tls: abort on an all-zero X25519 shared secret (#153)".The commit landed after v0.4.2 was tagged, so no cherry-pick could have carried it. Its own message describes the impact: a server, or an attacker who rewrites one ServerHello in passing, can send a low-order
key_shareand force every handshake and traffic key to be a function of the two plaintext hello messages. Any passive observer who recorded the session can then derive the traffic keys, without staying on the path.Also unreleased:
tools/test_ecdh_zero_check.py, the suite that covers it.2. Handshake-message sequence is not enforced (#152, PR #160)
Fix is commit
d0c9ed3, "tls: enforce the handshake message sequence (#152)" —TLS_HS_SEQ_CHECK/src/tls_hs_seq.inc, the sharedDF_ERR_SEQrejection in both dispatchers.This one changes shipped 6502 code in
src/tls_deframe.sandsrc/tls13.s, so released images genuinely lack the check. Also unreleased:tools/test_hs_sequence.py.A correction to how this was originally scoped
#163 was suggested to me as a third unreleased security fix. It is not one, and I am recording that rather than repeating it.
f3b39d9is "rigs: fail closed offline when the PRG cannot pass the SAN check (#141)" — a change to test-rig preconditions, not to any shipped 6502 code. It does not affect what a released PRG does, and folding it into a security-release argument would overstate the case. Two client-side fixes are unreleased, not three.A documentation artifact worth recording separately
README on master credited the all-zero check to "Since v0.4.3". There is no v0.4.3, locally or on the remote — the tag list ends at v0.4.2. The false reference was written by the fix's own author in that same commit, forward-looking to a release that never happened, and it survived until now. Anyone reading the README would have concluded the fix was shipped. Corrected in #192.
The v0.4.2 images also carry a registrable third-party hostname
Independent of the above, and relevant to how a released image behaves if someone runs it unmodified.
The packaging scripts never set
HTTPS_HOST, so released images carry the Makefile default. At the v0.4.2 tree that default iswww.foo.bar:.baris a delegated gTLD with live nameservers, sowww.foo.baris a name a third party can register. The rename towww.foo.invalid— RFC 2606 / RFC 6761 reserved, never delegated, cannot resolve — is commitcdf02b4(PR #164, 2026-08-30) and is in no tag:Currently NXDOMAIN, so this is latent rather than live. But it combines badly with items 1 and 2: an image with no certificate chain validation, no server-name validation on the ip65 product, and no all-zero-shared-secret check would dial an attacker-controlled host on its first GET if that domain were ever registered.
Footnote — a third unreleased fix that is NOT a crypto break
Deliberately kept out of the list above so it cannot be miscounted as a third client-side security fix, but recorded because it bears on the release decision.
8c4b389, "uci: start CIA1's TOD, so the bounded waits are actually bounded (#145)". Untagged, and it touches shipped 6502 code (src/net/uci/net.s,src/net/uci/uci_cmd.s):Before it, CIA1's TOD was never started — it is halted out of reset and nothing in the KERNAL starts it — so every UCI spin-wait that believed itself wall-clock bounded was in fact unbounded on hardware. That is a fail-unsafe hang, not a confidentiality or authentication break, which is why it is a footnote rather than item 3. It is also UCI-only, so it affects the two UCI products and not
ip65-onchip.Worth knowing that VICE cannot catch a regression here (it runs the TOD from reset), so the guard is
tools/uci/boot_check.pyand it needs real hardware.The decision being asked for
Any of these is a reasonable answer; the point is that it is recorded:
Until it is decided, #192 states in the README that the all-zero check is master-only and links here.
Method note
Every claim above is checkable offline from this repo with
git tag --containsandgit show <tag>:<path>. The general trap it came out of: a fix being on master says nothing about it being in a release, and a README written at merge time will describe the world the author expected rather than the world that shipped.