Security Model¶
What this protects against, and what it does not.
The command parser is the attack surface¶
Reachable by any stranger on nine networks. Deliberately tiny: twelve commands, none privileged, everything else silently dropped.
Notes are flattened (control characters stripped, whitespace collapsed, truncated at 200 characters) before they can reach an outbound message, so a note cannot inject extra lines into a broadcast. Endpoint addresses reject control characters.
Administration is not on the network¶
There is no admin command, no socket, no API.
partylinepagerctl requires host access. Host access is the
admin credential.
Full image exception
The full image exposes an admin terminal via ttyd, reachable
over the LAN. This is gated by HTTP basic auth
(TTYD_CREDENTIAL) and optionally a self-signed cert, not
by host access. The compose deployment is unaffected and
keeps the original guarantee.
The Docker socket is root¶
The party line hooks drive docker compose, and the compose
file hands the daemon /var/run/docker.sock. Anyone who
compromises the bot owns the box.
There is no escape from this: the docker group is root, a sudo rule is root, a privileged helper is root.
Mitigation: point [provider.tor] at a script that reaches a
separate host over SSH. The hook contract doesn't care how.
A web-only instance needs no Docker socket: leave
compose/docker-compose.docker-socket.yml and the provider overlays
out of your list. See
Compose Files.
Web room security¶
A web room has no second factor. The URL is the credential.
- Default: 160 bits of OS CSPRNG (won't be guessed)
static_slug: trades that guarantee for a stable link. Treat it as public to anyone who has ever seen it.- The room is hosted by whoever runs
base_url. The default public MiroTalk instance sees who connects. Self-host if that matters. - The partyline pager cannot evict anyone: the TTL frees the instance to open the next room, it doesn't end the call.
Credentials are inline by default¶
The broadcast carries the onion address and secret (or room URL) in the message body. Every subscriber's chat provider sees them.
If your threat model doesn't survive that:
- Use
creds_delivery = "link"for one-time Yopass links - Run with
signups = "closed"and a Matrix-only roster (E2EE) - Prefer Matrix for carrying secrets
Secrets¶
256 bits from the OS CSPRNG, rendered as base32 (no case
ambiguity, no 0/O confusion). Generated by the partyline
pager, not by each hook, so secret quality is decided in one
audited place.
- Passed to hooks on stdin
- Written by the shipped hook with
umask 077 - Deleted at teardown along with the onion key
Metadata¶
The roster is a social graph in a flat file on a host reachable from nine chat networks. Consider what that file looks like after a breach.
Quiet-hour drops are deliberately not recorded, so the daemon never accumulates a list of who was asleep at 03:00.
Not Arti¶
The Tor Project does not recommend Arti's onion services for production use or anything requiring privacy. The hook drives the C Tor daemon.