Security

What's protected: your relay login's token, on this machine. How the relay issues, checks and stores tokens is the relay's: Tunnels: accounts and tokens.

  • Where the token is. In the Keychain on a Mac (Keychain), else in ~/.config/lnk/config.toml, mode 600, written atomically. A file named with LNK_CONFIG keeps its own token. lnk has to send the token, so it keeps the token itself, not a hash.
  • Who reads it. Only the accounts plugin reads the file. Other plugins ask lnk auth, which prints to the plugin that ran it, never to a terminal:
    • lnk auth relay --json gives the login token itself, to lnk tunnel, which connects to the relay with it. It is a child process of the same user, who could read the file anyway. Run in a terminal, it refuses and prints no token.
    • lnk auth token --json gives a token for the relay's share API that expires in minutes, to lnk bucket share. The login token never leaves the accounts plugin that way. The relay's GET /_link/whoami takes it too, saying whose it is (your username and GitHub account's id), so a service you hand it to can tell who you are, for those minutes, and do nothing else as you.
    • lnk auth whoami --json gives who you are, never a token, to lnk box and lnk bucket.
    • lnk auth ticket --json gives a confirmation ahead (below), never a token, to lnk box start.
  • Which relay gets it. Only the relay you logged in to, whatever --relay or LNK_RELAY names. A token saved without its relay, in a hand-edited or very old file, goes only to https://local.link.
  • Logging out revokes the token. lnk auth logout asks the relay to remove the token first, then clears it here. When the relay can't be reached or refuses (one too old to revoke, or a token from its operator's list), it still logs out here and warns that the token may still be valid: anyone holding a copy of it can use it until the relay's operator removes it.
  • Against a hostile relay, lnk auth login opens only https:// login URLs, writes control and bidi characters in relay-supplied text as escapes (such as \u{1b}) or drops them, in its output, its errors and the username it saves, reads at most 512 bytes of an error, and waits at most an hour for a login, polling every 1 to 60 seconds, whatever the relay asks.
  • A busy relay. When the relay is out of room for requests from people not yet logged in, it answers 503; lnk auth login asks again every 2 seconds, for a minute to start a login and until the code expires while waiting for it.
  • A new login is confirmed here. Once your account has a machine signed in, a new lnk auth login elsewhere waits, after you approve it in the browser, for one of your machines to confirm it with lnk auth approve, which shows the device, the address and the code, and warns when it came from another network. Phishing the browser's approval alone gets nothing. lnk auth ticket --json, for lnk box start, gives the box's login a confirmation ahead, once, for 10 minutes. The rules: Tunnels: confirming a login.
  • Command-line flags are visible to other local users, so prefer LNK_TOKEN to --token.

Gaps

An account's first login, before it has a machine to confirm it, can be phished. See Known limitations.