Skip to content

pit: serve a Moshpit name at /n/<name> - #145

Merged
ralyodio merged 1 commit into
mainfrom
feat/gateway-n-route
Jul 31, 2026
Merged

pit: serve a Moshpit name at /n/<name>#145
ralyodio merged 1 commit into
mainfrom
feat/gateway-n-route

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Every resolver and the TronBrowser extension already pointed here. Nothing answeredgatewayUrlFor sent tabs to pit.moshcode.sh/n/<name> and got the app's 404 page, so a resolved name still went nowhere. This is the hole in the middle of the stack.

  • A name with a target is fetched and returned.
  • A name without one gets a directory rather than a dead end: live sites under that ending, what else is claimed there, and which other endings are worth a look.

A parked name is the commonest thing anyone lands on, so it's the page that has to earn its keep.

"Related" without inventing a taxonomy: an alias is an operator explicitly saying two endings belong together; shared ownership is the next best signal. Everything after that is just the rest of the namespace.

The security problem

The target is typed in by whoever holds the name, and this server fetches it from inside its own network. Pointed at 169.254.169.254 that's cloud credentials; pointed at 10.x it's every internal service the box can reach, returned to whoever asked.

  • Reserved ranges refused — loopback, private, link-local, CGNAT, multicast, benchmarking, documentation, and IPv4-mapped IPv6, which would otherwise skip every v4 rule
  • A hostname is judged on what it resolves to, not how it looks — and one public A record doesn't make the others safe
  • Cookies and authorization are never forwarded. The visitor's session on app.moshcode.sh has nothing to do with the origin; passing it would hand a name's owner their visitors' credentials
  • Set-Cookie doesn't come back, or a name's owner could set cookies on the domain where accounts live
  • Responses sandboxed by CSP, bounded at 5MB / 10s

Tests

11, every one an SSRF case — including the 172.16/12 boundary, the classic off-by-one in a hand-written deny list.

Exercised live against a seeded DB:

parked.eggs  200  directory: "Sites on .eggs", "Also claimed", "Related endings"
evil.eggs    502  "link-local — cloud metadata lives here"   ← not the metadata
nope.eggs    404
bad          400

274/274 pwa suite.

Not in this PR

Buy Now buttons and the ads network — next.

🤖 Generated with Claude Code

Every resolver and the TronBrowser extension already pointed here. Nothing
answered — gatewayUrlFor sent tabs to pit.moshcode.sh/n/<name> and got the
app's 404 page, so a resolved name still went nowhere.

A name with a target is fetched and returned. A name without one gets a
directory rather than a dead end: the live sites under that ending, what else
is claimed there, and which other endings are worth a look. A parked name is
the commonest thing anyone lands on, so it is the page that has to earn its
keep.

"Related" without inventing a taxonomy: an alias is an operator explicitly
saying two endings belong together, and shared ownership is the next best
signal. Everything after that is just the rest of the namespace.

The security problem here is the target, which whoever holds the name typed in
and which this server then fetches from inside its own network. Pointed at
169.254.169.254 that is cloud credentials; pointed at 10.x it is every internal
service the box can reach, returned to the person who asked. So:

  - reserved ranges are refused — loopback, private, link-local, CGNAT,
    multicast, benchmarking, documentation, and IPv4-mapped IPv6, which would
    otherwise skip every v4 rule
  - a hostname is judged on what it RESOLVES to, not how it looks, and one
    public A record does not make the others safe
  - cookies and authorization are never forwarded; the visitor's session on
    app.moshcode.sh has nothing to do with the origin, and passing it would
    hand a name's owner their visitors' credentials
  - Set-Cookie does not come back, or a name's owner could set cookies on the
    domain where accounts live
  - responses are sandboxed by CSP, bounded at 5MB and 10s

11 tests, every one of them an SSRF case including the /12 boundary that is the
classic off-by-one in a hand-written deny list. Exercised live: a parked name
renders the directory, a bad target returns "link-local — cloud metadata lives
here" rather than the metadata.

274 across the pwa suite.

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 a10539f into main Jul 31, 2026
3 checks passed
@ralyodio
ralyodio deleted the feat/gateway-n-route branch July 31, 2026 11:24
@ralyodio ralyodio mentioned this pull request Jul 31, 2026
ralyodio added a commit that referenced this pull request Jul 31, 2026
* chore(release): v0.13.3

install.sh resolves releases/latest, so everything merged since v0.13.2 has
been sitting on main unreachable — `moshcode dns enable` exists in the source
and not in anyone's binary.

The headline is the DNS bridge (#141). Moshpit names now resolve for every
program on the machine, not just inside TronBrowser: each OS gets the mechanism
that routes ONE SUFFIX rather than the one that replaces the resolver —
/etc/resolver on macOS, systemd-resolved routing-only domains or dnsmasq on
Linux, an NRPT rule per namespace on Windows.

  moshcode dns enable / disable / status
  moshcode uninstall <engine|tool>          (#150, completion in #151)

The pit gained most of a namespace registry in between: key pins per name
(#137), pasted bulk claiming with per-line price and target (#138, #142, #143,
#146), all-numeric endings (#147), /n/<name> serving a name or a directory
(#145, #149), and Buy Now on an unclaimed name (#148).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* chore: restore the em-dash the version bump escaped

The bump rewrote package.json through a JSON serialiser that defaults to ASCII,
turning the em-dash in `description` into —. Valid JSON and the same string
once parsed, but a gratuitous diff in a commit that should touch one line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to 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