Report it privately through GitHub: Security → Report a vulnerability. That opens a private advisory only you and the maintainer can read.
Please don't open a public issue for a security problem — the issue tracker is world-readable, and a working report there is a working exploit for everyone else too.
Include what you did, what happened, and the version (Settings → Help, or
lich --version). A proof of concept helps; a patch is welcome but never
expected.
The latest release only. lich updates in place on Windows and macOS and through the AUR on Arch, so a fix ships as a new version rather than as a backport.
A release that fixes a vulnerability can mark its update as required. A lich behind it then shows an update prompt that cannot be put off and opens no new agent session until the update is installed; sessions already running keep working, and a shell still opens so the update can be run. lich learns this from GitHub's release list, so a lich that cannot reach GitHub is not told, and versions from before this mechanism only offer the update.
lich runs entirely on your machine. There is no server, no account and no telemetry, so the interesting boundaries are local ones:
- The loopback listener. One port (47821 by default) carries the HTTP RPC and the WebSockets for terminal I/O and app events. It binds to loopback and every request is authenticated by a per-run token. Anything that reaches it without that token, or from off-host, is a vulnerability.
- The session token. It is never written to the log. Finding it in a log, a crash report or a process's command line is a vulnerability.
- The sandbox's token. A session running in the sandbox is handed a token
of its own, not the launch token, and that token answers only to an allowlist
of calls (
internal/scope) and to the hook endpoints for its own session. The launch token's record, lich's database and the other sessions' checkouts are hidden from the sandbox. A confined session reaching a denied call, the launch token, or another session's state is a vulnerability, and so is a confined session putting text at the prompt of a session that is not confined, by any method: the receiving agent would carry it out on the machine. What it may still do by design is listed indocs/ceilings.mdunder Sandbox: message confined sessions, reply to anyone. - The workspace. Projects, sessions and settings live in SQLite under your config directory.
GH_TOKEN. A project can name the GitHub accountghruns as, which puts that account's token in the environment of theghcalls lich makes. A path that leaks it, or hands it to the wrong project, is a vulnerability.- Session hooks. The scripts ship from lich-plugin and post to the same authenticated listener. A payload that escapes its contract belongs here too; a bug in the scripts themselves belongs in that repository.
- An agent running commands. lich spawns your agent in a real PTY, and that agent runs whatever it decides to run. That is the product, not a flaw — the trust boundary is the agent you chose and pointed lich at.
- A dropped file resolving to a copy. When a drop matches nothing in the searched trees, lich copies it to a temporary directory and hands over that path. Documented, deliberate.
- Two checkouts sharing a
LICH_WORKTREE_PORT. lich reserves the number and proves it free at the time it is handed out, but nothing holds it until your dev server binds it.