edge-control: deregister has no ownership check — any authorized SSH key can take over any project #1091

Closed
opened 2026-04-20 18:46:22 +00:00 by dev-bot · 0 comments
Collaborator

Mirrored from johba/disinto#832

---## Problem

tools/edge-control/register.sh:109-144 (do_deregister) removes a project from the registry with no check that the caller owns it. The only auth gate is SSH access to the disinto-register user (forced command seeded in install.sh:363). Any key in that authorized_keys file can:

  1. Call deregister <project> on any project, regardless of who registered it.
  2. Immediately call register <project> <attacker-pubkey> and reclaim the name.

The first-write-wins pubkey binding in lib/ports.sh:74-82 protects a live registration — allocate_port early-returns the existing port without touching the stored pubkey — but offers no protection once the entry has been deleted.

Today, with only one admin key seeded by install.sh, the blast radius is bounded by that key. The gap becomes severe as soon as a second operator key is added or the admin key is compromised.

Proposal

Require the caller to prove ownership on deregister:

  • Change the SSH protocol to deregister <project> <pubkey>.
  • In do_deregister, load .projects[$project].pubkey from registry.json and refuse unless the supplied pubkey matches byte-for-byte.
  • Return {"error":"pubkey mismatch"} on failure; do not reveal the stored pubkey.

This is a one-function change in register.sh plus the dev-box CLI update that calls it.

Acceptance

  • deregister without a matching pubkey returns an error and leaves the registry untouched.
  • deregister with the correct pubkey works as today.
  • Test covers both paths.
_Mirrored from [johba/disinto#832](https://codeberg.org/johba/disinto/issues/832)_ ---## Problem `tools/edge-control/register.sh:109-144` (`do_deregister`) removes a project from the registry with no check that the caller owns it. The only auth gate is SSH access to the `disinto-register` user (forced command seeded in `install.sh:363`). Any key in that `authorized_keys` file can: 1. Call `deregister <project>` on any project, regardless of who registered it. 2. Immediately call `register <project> <attacker-pubkey>` and reclaim the name. The first-write-wins pubkey binding in `lib/ports.sh:74-82` protects a *live* registration — `allocate_port` early-returns the existing port without touching the stored pubkey — but offers no protection once the entry has been deleted. Today, with only one admin key seeded by `install.sh`, the blast radius is bounded by that key. The gap becomes severe as soon as a second operator key is added or the admin key is compromised. ## Proposal Require the caller to prove ownership on `deregister`: - Change the SSH protocol to `deregister <project> <pubkey>`. - In `do_deregister`, load `.projects[$project].pubkey` from `registry.json` and refuse unless the supplied pubkey matches byte-for-byte. - Return `{"error":"pubkey mismatch"}` on failure; do not reveal the stored pubkey. This is a one-function change in `register.sh` plus the dev-box CLI update that calls it. ## Acceptance - `deregister` without a matching pubkey returns an error and leaves the registry untouched. - `deregister` with the correct pubkey works as today. - Test covers both paths.
dev-bot added the
backlog
label 2026-04-20 18:46:22 +00:00
dev-qwen2 self-assigned this 2026-04-20 18:46:42 +00:00
dev-qwen2 added
in-progress
and removed
backlog
labels 2026-04-20 18:46:42 +00:00
dev-qwen2 was unassigned by dev-qwen 2026-04-21 06:04:15 +00:00
dev-qwen removed the
in-progress
label 2026-04-21 06:04:16 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: disinto-admin/disinto#1091
No description provided.