[P0][SECURITY] Unauthenticated LAN + unfenced /api/tools/file/write = remote arbitrary file write (escalates #110) #128
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity escalation of neuron#110 (BUG-41). Two separately-known facts combine into remote arbitrary file write on the user's machine. Both verified in the CURRENT shipped brain (
8ec39278…, round 9.1) this session.Fact 1 — the brain listens on all interfaces with no authentication. Byte search of the shipped binary:
EL_HTTP_BIND_HOST0 occurrences,EL_HTTP_AUTH_KEY0 occurrences — the launcher sets both and logs "loopback-locked", and neither exists on the receiving side. Previously measured end-to-end:GET /healthand an unauthenticatedPOST /api/neuron/memoryboth succeeded from the machine's LAN IP.Fact 2 — there is an unfenced file-write route.
POST /api/tools/file/write(studio.el:106-114) writes to any path, with no workspace fence, no path validation, and no check of the write's return — it respondsok:trueregardless of whether the write succeeded. Present in the shipped binary (/api/tools/file/write, 1 occurrence). It has no caller in the app, so nothing in normal product use exercises it.Combined: anything on the same Wi-Fi can write arbitrary files anywhere the Neuron process can reach, unauthenticated, with no user interaction and no record in the app. That includes the user's own dotfiles and login items. This is materially worse than the read/write-the-memory-graph exposure #110 was filed for.
Not exploited, not tested against a third party — asserted from the binary's own contents plus #110's earlier live LAN measurement. Confirming it end-to-end would mean writing a file to a machine over the network, which we have not done and will not without your say-so.
Why now: the beta test wave runs in an isolated VM, so this is contained today. It must close before any build reaches a person on a real network — a coffee-shop or shared-office Wi-Fi is exactly the scenario.
What done looks like: the binary honors a loopback bind and a per-install auth key (making the launcher's existing claim true), AND the write route grows a workspace fence with a checked return — or is removed, since nothing calls it.
Escalation: this is no longer a shipped-binary defect. It is measured, live exposure on a real machine — Tim's, right now. Measured 2026-08-07, read-only probes only.
The running production stack on Tim's Mac (LAN address
192.168.0.97) answers on all interfaces, not loopback:With no credentials of any kind:
Note
limit=2returned 38.9 MB — the limit parameter is not honoured, so a single unauthenticated request from any device on the network exfiltrates the entire memory graph. That is every memory, every note, everything the user has ever told Neuron.There is no auth mechanism to misconfigure. Raw-byte count against the shipped brain binary:
So this cannot be mitigated by configuration or an environment variable — the capability is absent from the binary. (Related:
CredentialStore.kt:366asserts the soul "requires X-Neuron-Auth". It does not. That claim is false as built.)Context that makes it worse, not better: the host firewall is disabled (
socketfilterfw --getglobalstate→ State = 0) and there are 15 hosts in the local ARP cache. This is not a theoretical adjacency.Composition is the real severity. Paired with the unfenced
POST /api/tools/file/write(studio.el:106-114, present in the shipped binary, no path fence, no auth, returnsokregardless), this is remote arbitrary file write as the user with no interaction and no record — from any device on the same Wi-Fi. Read and write, unauthenticated, no audit trail.Also worth noting:
/healthis auth-exempt and triggers a live provider call (routes.el:149), so an unauthenticated remote party can drive API spend.Against the design. The architecture register states
INV-RT-02: loopback-only bind plus a per-install keychain key. Today the bind is*and the key does not exist. In a first full conformance run of the invariant register completed today, this was judged the single most urgent violation of 117 — because it is the only one reachable end-to-end from off-loopback with no credentials, and because it amplifies every other read-path violation into a remote one.This issue is still unassigned. It needs an owner.
Immediate mitigation available to a user today, without touching the daemons: enable the host firewall to block incoming connections. That is a workaround, not a fix — the fix is a loopback bind and a per-install key, which requires engine work.