Threadglass reads a folder of private messages and serves it over HTTP on your own machine. That makes a small number of things worth stating plainly.
Threadglass is a local, single-user, read-only viewer. It assumes the person who can reach the port is the person whose messages these are.
What it does:
- reads the archive directory and holds it in memory; it never writes to that directory
- binds to
127.0.0.1by default - serves the API and attachments only to same-origin requests by default
- stores nothing except a settings file (
~/.threadglass/settings.json) holding the chosen archive path and a short recents list, and a theme preference inlocalStorage
What it does not do:
- no authentication — there are no accounts and no login
- no telemetry, analytics, error reporting, update check, or any other outbound request
- no encryption at rest; the archive stays exactly as the export left it
Don't, unless you mean to. Setting HOST=0.0.0.0 — including via the Docker
instructions in the README — makes every message in the archive readable by anyone who
can reach that address, with no credentials. If you need remote access, put it behind a
reverse proxy that handles authentication and TLS.
Two behaviours change when the bind address is not loopback:
- the directory browser (
GET /api/archive/browse) is refused with 403, because it discloses folder names outside the archive THREADGLASS_CORS_ORIGINremains same-origin unless you deliberately widen it
Please open a private security advisory through GitHub: https://github.com/pdz1804/threadglass/security/advisories/new
Do not open a public issue for anything that could expose message data, and please do not attach real message content to a report — a redacted example or a description of the shape is enough.
Expect an acknowledgement within a week. As an unfunded personal project there is no formal SLA, but anything that lets one archive read another, escapes the archive directory, or leaks data off the machine will be treated as urgent.
- Path traversal on
/media/*— request paths are resolved and then checked for containment within the current archive root; anything that escapes is refused. Covered by tests. - Switching archives — a failed load leaves the previous archive in place, and derived caches are cleared on a successful switch so data from one archive cannot leak into another's analytics.
- Rendering message text — messages are rendered as React nodes, never as HTML. The server returns highlight segments rather than markup, so a message containing HTML or a script tag is displayed as text.
- SVG attachments are served with
image/svg+xmland rendered in<img>, which does not execute scripts. They are not inlined into the page.