Security model
What each part of Houseguest™ can do, what it cannot, and what it keeps. The same model is on houseguest.dev/security.
Who can do what
Section titled “Who can do what”| Party | Can | Cannot |
|---|---|---|
| A viewer | Use the preview’s hostnames until it ends or they are revoked | Use a forwarded link without the invited inbox; reach names outside the preview |
| The agent | Reach the hostnames on its own allow-list | Accept a name its host did not allow |
| The edge | See requests and responses of an open preview, to check each one | Reach any name outside the agent’s allow-list; sign in to your app without a user’s credentials |
| A compromised edge | Send requests to allowed names and TCP services at any time | Reach the rest of your network; widen the allow-list |
| You, on the self-hosted edition (Enterprise) | Everything, on servers you run | No preview traffic or workspace data reaches Houseguest. The hosts that serve releases and the agent image (GitHub’s container registry) see the server’s IP address when it downloads them |
The agent
Section titled “The agent”- It opens one connection out to the edge on port 443. Nothing connects in, so no firewall rule changes.
- It joins once with a token that works one time within an hour, and registers its own Ed25519 key. Each later connection is signed with that key over the edge’s name, the time and a one-time value, so a captured connection cannot be replayed.
- Its allow-list,
HG_ALLOW, is set on its own host. It may be exact names, or one level under a domain such as*.lab.example.com. The console can turn names on within that ceiling and never past it, and the agent can be told to ignore the console entirely. - It connects to the app with TLS, sends the real hostname and checks the app’s certificate, as a browser on your network would: against public roots, plus your internal CA if you name one. It removes Houseguest’s own cookie before forwarding.
- It runs as an unprivileged user: in a container of about 10 MB with no shell, or, without Docker, as a locked-down systemd service.
- On the hosted service, a name is served on its own hostname only under a domain your account has verified with a DNS TXT record. Another account’s agent cannot claim it.
Viewers
Section titled “Viewers”- Invites work once. Opening the link shows a confirmation page, so link previewers in chat and mail cannot use it up.
- Email codes confirm every sign-in with standing access, and every invite unless the sharer turns them off. They work for 10 minutes and allow 5 wrong tries. A new code can be sent after 30 seconds, up to 5 an hour.
- Standing access sign-in pages answer every address the same way, so the page reveals nothing about who is on the list. Code emails are capped per address and per network.
- Sessions use a cookie marked Secure and HttpOnly, scoped to the preview’s own domain, lasting until the preview ends or a set number of days. Revoking a person or ending a preview stops web access at the next request. TCP and terminal connections already open run until they close.
Requests without a session
Section titled “Requests without a session”Some apps make requests without cookies: site icons, health checks, or API calls with a bearer token. The gate cannot tie those to a person, so it refuses them by default. Three narrow exceptions, each visible in the request log:
- Paths you list as open, such as a health check.
- Site icons, from the network address a signed-in viewer used in the last 15 minutes.
- Optionally, per preview, other cookie-less requests from that same address, rate-limited. People behind one office network share an address, so this stays off unless an app needs it.
Houseguest addresses
Section titled “Houseguest addresses”On the hosted service, a preview can use addresses such as app.acme.houseguest.page instead of the app’s own
hostnames.
- The app’s internal names never appear in public DNS or certificate logs. Each account has one wildcard
certificate for its addresses (
*.acme.houseguest.page), so certificate logs show the account’s short name, not its addresses. - The edge sends each request to the agent under the internal name, and rewrites the address in
Origin,Referer,Location, CORS, Content-Security-Policy and cookie-domain headers. It never rewrites page content. - Each account’s addresses sit under its own name, and one sign-in covers them. Until houseguest.page is on the Public Suffix List, a page under another account’s address could set a cookie for all of houseguest.page. Houseguest’s sign-in ignores such cookies; the app’s own cookies do not get that protection until the listing.
SSH and other TCP services
Section titled “SSH and other TCP services”- The agent’s host lists each service by exact name and port. The console cannot add to that list.
- With the
houseguestcommand line, the edge relays bytes without interpreting them. Encrypted protocols such as SSH stay encrypted end to end; a protocol without encryption, such as plain HTTP or an unencrypted database connection, is readable at the edge. - The browser terminal runs the SSH session on the edge, which sees it in the clear, as it sees web previews. The server’s host key is remembered on first use, and a changed key stops the terminal.
- Connections are checked when they start. Revoking a person or ending a preview stops new connections; open ones run until they close.
The console
Section titled “The console”- People who share previews sign in with an emailed code, a passkey alone, or Sign in with Microsoft. There are no Houseguest passwords to leak or reuse.
- A second sign-in step (a passkey or an authenticator app) can be required for Owners and Admins, or for everyone. It is required for Owners and Admins by default on the hosted service.
- Members can also sign in through the workspace’s own identity provider with single sign-on (OIDC or SAML), which the workspace can require. It is part of the Business plan and included in Early access.
- Roles decide who can do what. Owners and Admins manage agents and people; Members open previews and run their own. Nobody can grant more than they hold.
- Every change is checked for a per-session token and the page’s origin, and the console refuses to be framed by other sites. Every change, including refused ones, is recorded in the activity log with the person, the time and the IP address.
What is kept
Section titled “What is kept”- Invite links, codes, session tokens and command-line tokens are stored only as hashes.
- The request log keeps the time, the person, the method, the hostname, the path, the result, the browser family and OS, the device type and the country, for 90 days. Never query strings, never request or response bodies.
- The edge’s web-server log for previewed hostnames records the client IP address, the request line without its query string, and request headers such as the user agent. It rotates by size.
- The activity log keeps every console change with the person, the time and the IP address, for one year.
- On the hosted service, email goes out through Amazon SES, with Resend as the fallback. Mail to Microsoft consumer mailboxes (Outlook.com, Hotmail, Live and MSN) goes through Resend first. Open and click tracking are off on both, so links in Houseguest’s email go straight to your app’s address. A self-hosted edge sends through your own mail provider.
Hosted or self-hosted
Section titled “Hosted or self-hosted”To check each request, the edge has to read it, so it terminates TLS. On the hosted service that edge is Houseguest’s. If no third party may see your traffic, the self-hosted edition, on the Enterprise plan, runs the edge on a Linux server you control: the same software, and no preview traffic or workspace data reaches Houseguest. The hosts that serve releases and the agent image see the server’s IP address when it downloads them. Contact hello@houseguest.dev for the Enterprise plan, and see Self-hosting the edge.
Reporting a security issue
Section titled “Reporting a security issue”Write to security@houseguest.dev.
© 2026 Houseguest Technologies LLC. Houseguest™ is its trademark.7723 Tylers Place Blvd., Box #119, West Chester, OH 45069