Skip to content

feat(parking): host-parked Moshpit names go to the Pit too - #88

Merged
ralyodio merged 1 commit into
masterfrom
feat/host-parking-to-pit
Aug 1, 2026
Merged

feat(parking): host-parked Moshpit names go to the Pit too#88
ralyodio merged 1 commit into
masterfrom
feat/host-parking-to-pit

Conversation

@ralyodio

Copy link
Copy Markdown
Collaborator

#87 moved /parking?name= to the Pit — but that isn't how a parked name actually arrives. The DNS resolver points an unpointed name at this app (DEFAULT_PARKING_HOST = moshcoding.com), so curl scrambled.eggs lands here as a Host header and still rendered the "IS COMING" tenant card.

Change

A name resolved from the Host now redirects to <pit>/n/<name>. An ordinary parked clearnet domain renders exactly as before.

Measured locally against the live registry:

Hostresult
scrambled.eggs307https://pit.moshcode.sh/n/scrambled.eggs
hawaiian.chicken307https://pit.moshcode.sh/n/hawaiian.chicken
moshcode.sh200<title>Moshcode IS COMING</title> (tenant page, untouched)
app host200 — the landing page

Three decisions worth flagging

Asked per name, not by pulling the ending list./api/moshpit/tlds is capped at 200 and .eggs already falls outside it — matching against that list would quietly answer "no" for real names. resolve's registered flag has no such ceiling and means exactly "an ending the pit holds".

307, not 308. The owner can point the name at a real target at any moment; a permanent redirect cached in a browser would keep sending visitors here long after this app stopped being the answer. /parking keeps its 308, because that URL will always mean "go to the pit".

Fails closed. An unreachable Pit answers "not ours", so a registry outage leaves every parked domain rendering as it does today rather than bouncing the whole internet at /n/. Answers are memoised per name behind a 5-minute TTL, in a bounded map — Host is attacker-controlled, so the memo can't be allowed to grow without end.

Verification

  • bun test tests/157 pass, 0 fail (9 new), covering ours/not-ours, shape rejection without a request, memoisation, case normalisation, fail-closed on outage and non-200, and warm-cache survival
  • bun run build clean
  • Served locally and checked real status codes and Location headers with real Host headers — the table above is measured

🤖 Generated with Claude Code

#87 moved /parking?name= to the Pit, but that is not how a parked name
actually arrives. The DNS resolver points an unpointed name at this app
(DEFAULT_PARKING_HOST), so `curl scrambled.eggs` lands here as a Host
header and still rendered the "IS COMING" tenant card.
A name resolved from the Host now redirects to <pit>/n/<name>, while an
ordinary parked clearnet domain renders exactly as before.
Which is which is asked of the Pit per name, not by pulling its ending
list: that list is capped at 200 and `.eggs` already falls outside it, so
matching against it would quietly answer "no" for real names. resolve's
`registered` flag has no such ceiling.
307, not 308. The owner can point the name at a real target at any moment;
a permanent redirect cached in a browser would keep sending them here long
after this app stopped being the answer. /parking keeps its 308 — that URL
will always mean "go to the pit".
Fails closed: an unreachable Pit answers "not ours", so a registry outage
leaves every parked domain rendering as it does today rather than bouncing
the whole internet at /n/. Answers are memoised per name behind a 5-minute
TTL, with a bounded map because Host is attacker-controlled.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit 195a5d2 into masterAug 1, 2026
2 checks passed
@ralyodio
ralyodio deleted the feat/host-parking-to-pit branch August 1, 2026 04:44
ralyodio added a commit that referenced this pull request Aug 17, 2026
…114)
`moshcode.sh` was 307-redirecting to `pit.moshcode.sh/n/moshcode.sh` — the
Pit's page for a name it says nobody holds — instead of serving its own tenant
page. Any two-label domain parked here is affected: `.io`, `.dev`, `.app`,
`.ai`, `.sh` and `.co` are all claimed endings today, out of 17,848.
`isMoshpitName()` read `registered` from the Pit's resolve endpoint and treated
it as "this host is a Moshpit name". It is not: `registered` means "the pit
holds this ending", and the Pit already ships the rule for what to do about it
in `prefer` —
clearnet nothing registered here
fallback use the pit only where the legacy root has no answer (default)
moshpit use the pit even where the legacy root answers (opt-in)
Reading `registered` alone collapses "fallback" into "moshpit" and hands the
pit every domain whose ending someone claimed. So honour `prefer`, and settle
"fallback" the way the extension does: ask a public resolver whether the legacy
root answers for the name. Only a definitive NXDOMAIN sends a visitor to the
Pit — a timeout or a SERVFAIL must never be why a working domain starts
offering itself to strangers.
The opt-out is the variable the resolvers already use, `MOSHPIT_RESOLVE_MODE`,
so one vocabulary covers the extension, the DNS bridge and this app.
docs/moshpit-dns.md already stated this policy; the web app was the one place
not applying it.
Names under an ending the legacy root has never heard of are unchanged — the
root NXDOMAINs `scrambled.eggs`, so it still goes to the Pit (#88).
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@ralyodio