Public Suffix List

Ask the Public Suffix List (PSL) to treat every tunnel as its own site, so that browsers keep one user's apps apart from another's. This page has what the maintainers require, the entry, and the body of the pull request.

Browsers treat everything under one "registrable domain" as the same site. Today that is local.link, so every user's tunnel (app.alice.local.link, app.bob.local.link) is the same site as every other. The relay already strips cookie Domain attributes that would cross tunnels (Keeping tunnels apart). A PSL entry fixes the root cause in browsers. Each tunnel becomes its own site, so SameSite cookies, storage partitioning and site isolation separate users' apps the way they separate unrelated websites.

Similar services already have entries: ngrok.io and ngrok-free.app (ngrok), trycloudflare.com (Cloudflare Tunnel), github.io (GitHub Pages).

Prerequisites

The PSL maintainers (CONTRIBUTING, Guidelines) decline or delay requests that miss any of these. Submit only once all of them hold:

  • Enough users. They decline "smaller, private projects with <2000 stakeholders". An invite-only relay for friends doesn't qualify.
  • A role-based email address on the domain, e.g. security@local.link or psl@local.link, monitored with replies within 30 days. A personal address is not accepted.
  • A public abuse contact. dev@local.link, on the terms page (www.local.link/terms). Link it from the home page too before submitting.
  • At least 2 years left on the local.link registration, and a commitment to keep more than 1 year left. Renew for several years first.
  • Terms of use covering abuse (www.local.link/terms) are strongly advisable, since the site is open to other people's content.

An entry takes months to reach browsers, and removing it later is just as slow. So it's worth doing once, when the service is clearly multi-tenant and public.

The entry

*.local.link makes every <user>.local.link a public suffix, so each <app>.<user>.local.link is its own site. Separating users is the point, and the wildcard also separates one user's apps from each other. Share links are served on <user>.local.link itself, which the entry makes a public suffix. local.link itself stays a normal registrable domain for the relay and website.

To file it:

  1. Fork publicsuffix/list and edit public_suffix_list.dat. Add the block below in the PRIVATE DOMAINS section, sorted alphabetically by organization name among the existing entries. Don't append it at the end.
    // Local Link : https://local.link
    // Submitted by <Your Name> <security@local.link>
    *.local.link
  2. Run the repo's checks (make test, see its README).
  3. Open the PR with the body below. Then add the DNS record it asks for, and keep it forever:
    _psl.local.link.  TXT  "https://github.com/publicsuffix/list/pull/<number>"
    Check it with dig +short TXT _psl.local.link.

PR body

Fill in the <…> parts. The checklist items come from the PSL's own PR template, .github/pull_request_template.md in their repo. Copy the current template and put these answers into it, because they change it now and then.

Description of Organization

Local Link (https://local.link) is a tunneling service run by <your name / organization>. Users run the open lnk client on their own computer, and it gives a local web server a public HTTPS URL: lnk tunnel open 3000 serves the app at https://<app>.<user>.local.link. Each user owns the namespace <user>.local.link, tied to their GitHub account, and every app they expose gets its own host under it. The relay routes each host only to its owner's machine. users currently run tunnels.

Reason for PSL Inclusion

Every tunnel serves content written by a different, mutually untrusting person, often a development build of their own web app. Without a PSL entry, browsers treat all of *.local.link as one site. That has three effects:

  • A cookie set with Domain=local.link by one user's app is sent to every other user's app. That allows session fixation and overwriting other apps' CSRF cookies.
  • SameSite cookie protection doesn't apply between users, because a.alice.local.link and b.bob.local.link count as same-site.
  • Storage partitioning and site isolation don't separate them.

The relay already strips Domain attributes that aren't the exact tunnel host from Set-Cookie. But that can't cover cookies set from JavaScript, or the same-site checks. A *.local.link entry makes each <app>.<user>.local.link its own site, as intended: users are separated from each other, and one user's apps from each other. local.link itself stays a normal registrable domain for the service's website and API.

Example outcomes after inclusion:

  • demo.alice.local.link: registrable domain demo.alice.local.link.
  • demo.bob.local.link: a different site from the above.
  • local.link: unchanged; the service's own site.

The domain has at least two years remaining on its registration (expires ), and we will keep more than one year remaining for as long as the entry exists.

Third-party limits: none sought. This request is not intended to work around Let's Encrypt or any other third-party limit. Certificates are issued only for a host the relay serves right now: a connected tunnel's host, or a user's own host while they have live share links, and at most 7 new hosts per user a day.

DNS verification

$ dig +short TXT _psl.local.link
"https://github.com/publicsuffix/list/pull/<number>"

Abuse contact: