Skip to content

Security: pdz1804/threadglass

Security

SECURITY.md

Security

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.

Threat model

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.1 by 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 in localStorage

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

Exposing it beyond localhost

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_ORIGIN remains same-origin unless you deliberately widen it

Reporting a vulnerability

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.

Things already considered

  • 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+xml and rendered in <img>, which does not execute scripts. They are not inlined into the page.

There aren't any published security advisories