Assets
What is worth protecting, in rough order of severity if lost:Adversaries
We design against four, and state our limits against each.Meradomo itself is in this list on purpose. A privacy claim that depends on our good behaviour
is a policy, not a guarantee. The architecture is built so that the strongest claim — that we cannot
read your traffic — does not require you to trust us.
1. Meradomo, or anyone who compromises our shared infrastructure
The shared address service forwards sealed bytes. It reads the requested hostname out of the TLS handshake without terminating TLS, then splices the raw connection through to the user’s computer. It holds no key for a connected user’s address, so it cannot decrypt the traffic — not by policy, but because the key material does not exist on that machine. This is the load-bearing property of the product. An operator with full access to our servers, or an attacker who takes them over, still cannot read request contents.2. A network attacker between the visitor and the user’s computer
Traffic is TLS-encrypted end to end, terminating on the user’s computer. A network observer sees the same thing our own infrastructure sees, and no more: a hostname, byte counts, and timing.3. Other Meradomo customers (co-tenants)
Tenancy is a data row, not a server. Every customer shares the same front door, so isolation is enforced at the point of admission rather than by separation of machines:- A computer proves a per-device credential on connect, and that credential is re-verified on every heartbeat, not just at login.
- A customer may only claim hostnames inside their own namespace —
<name>.meradomo.comand labels beneath it. An attempt to register a hostname belonging to another customer is refused at registration time, which is what prevents address squatting.
4. A lost or stolen device
The user removes the device from their account. Because the credential is re-checked on every heartbeat, the removed computer is disconnected within seconds rather than at the next login. The same mechanism suspends an inactive account.Trust boundaries
There are three, and identity is re-established at each:- Visitor → shared address service. Untrusted. The service does not decrypt; it only routes.
- Shared address service → the user’s computer. Sealed bytes. TLS terminates here, on the user’s machine, with the user’s own key.
- The agent → your local app. A loopback connection that is not reachable from the network. This is the only boundary at which identity headers are trusted, and the agent is the only thing that can write them.
What the shared address service can and cannot see
This is the part most worth being precise about, because a vague answer here is indistinguishable from a dishonest one. It can see:- The hostname requested in the TLS handshake. Because published apps live at
<app>.<name>.meradomo.com, the hostname reveals which user, and which app a visitor is reaching. We do not consider this hidden and you should not assume it is. - The visitor’s network address. It is a direct connection to our front door. (Notably, we do not pass this on — the agent never learns the visitor’s address, so your app cannot log it either.)
- Byte counts and timing of each connection, and therefore rough traffic volume and shape.
- Whether the user’s computer is currently online, which is how the asleep page is triggered.
- The request method, path, or query string.
- Any header, cookie, or authorization credential.
- Request or response bodies — your app’s actual data.
- Which person is signed in. Identity is established on the user’s computer, after decryption, and is never visible to the shared infrastructure.
Where the keys live
The agent generates its own private key on the user’s computer, writes it to disk readable only by that user, and never transmits it. Certificate issuance uses a signing request — the key itself never crosses the network, including to us. This is why we do not, and will not, terminate TLS centrally for connected users. A central service holding a wildcard key would be able to decrypt every customer’s traffic. That design would be more convenient and is deliberately not the one we built.What the control plane stores
The control plane knows who has an account and what they may connect. It never sees traffic. It stores: account email and display name; the claimed name (hostname); device records, where the device credential is kept only as a SHA-256 hash — the credential itself is not recoverable from our database; subscription and billing status; and, for developer integrations, granted app authorizations. It does not store: request or response content, request paths, browsing or usage history, or any private key belonging to a user. The access log — who reached which app and when — is written on the user’s own computer, not here. The shared infrastructure is architecturally incapable of producing that log, which is why it lives where it does.Why identity headers cannot be forged
Your app trustsX-Meradomo-* headers. That trust rests on two facts:
- Inbound headers are deleted, not merged. Before the agent forwards a request to your app, it
strips every inbound
X-Meradomo-*andX-Forwarded-*header, and only then injects its own values from its verified session state. A visitor who sendsX-Meradomo-Email: owner@example.comhas that header removed — there is no path by which a supplied value survives. - The loopback hop is not routable. The agent talks to your app over
127.0.0.1. Nothing on the network can reach that connection to inject a header directly.
Revocation
Removing an app’s access, removing a device, or suspending an account all take effect within seconds, because the check is continuous rather than at-login:- Apps: the agent keeps a current list of authorized apps and refreshes it on a short poll. A revoked app’s requests stop being served on the next refresh.
- Devices and accounts: verified on every heartbeat; a rejection disconnects the computer.
The one exception: the asleep page
There is exactly one case where the shared service terminates TLS: when the user’s computer is offline. It then obtains a short-lived certificate for that hostname and serves a static “this computer is asleep” page. Three properties bound this exception, and all three are structural:- It happens only when no computer is connected — there is by definition no traffic to intercept, because the other end does not exist.
- The key is held in memory only, for a short lifetime, and is never written to disk.
- The page is a fixed, pre-built response. That code path can serve that one static page and nothing else — it has no ability to forward a request anywhere. It is not a proxy that happens to be serving a page; it cannot proxy.
What this model does not protect against
Stating these plainly is part of the model.- A compromised user computer. Everything decrypts there. If that machine is compromised, the data is compromised. Meradomo protects the path, not the endpoint.
- A compromised visitor device. Same reasoning at the other end.
- Traffic analysis. Hostname, timing, and volume are visible to us and to a network observer. Someone watching can tell that you used a given app, and roughly how much — just not what you did in it.
- A malicious local app. An app the user runs receives the identity headers and whatever data the user gives it. Meradomo verifies who is asking; it does not sandbox what your app then does.
- A user who authorizes the wrong person. Access granted is access granted. Revocation is fast, but it is after the fact.
- Our own availability. We can take the front door down — refuse to route, or suspend an account. We cannot read the traffic, but we are in the path. That is the trade of a shared address.
-
An adversarial Meradomo, on a
meradomo.comaddress. This one deserves a straight answer. Our deployed code cannot decrypt your traffic — that is the whole design. But we operate themeradomo.comzone, and whoever controls a zone can obtain a certificate for names beneath it. So “we cannot decrypt” is a true statement about the system we run; it is not a statement about our position. A future us, or someone who compromises us badly enough, could issue a certificate for your address and terminate traffic there. Two things constrain that, and we would rather point at them than pretend the gap does not exist:- It is detectable. Public certificates are logged in Certificate Transparency. A certificate issued for your address that your own computer did not request is a public, permanent record.
- A custom domain removes it. Bring your own hostname and you control the zone — issuance is yours to authorize, and this residual risk goes away. If you want the guarantee to rest on architecture rather than on our conduct, use a custom domain.