Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Security

Trust model

siggy is a thin TUI layer over signal-cli. It does not implement any cryptographic protocols, manage credentials, or contact Signal servers directly. All security-critical operations are delegated to signal-cli, which implements the full Signal Protocol.

This means siggy inherits signal-cli’s security posture:

  • What signal-cli handles: key generation, key exchange, message encryption/decryption, identity verification, contact and group management, attachment encryption, and all network communication with Signal servers.
  • What siggy handles: rendering messages in a terminal, storing a local cache of conversations in SQLite, and forwarding user actions to signal-cli via JSON-RPC.

siggy never sees plaintext cryptographic keys or raw network traffic.

Credential storage

Signal credentials (identity keys, session keys, pre-keys) are stored by signal-cli in its own data directory (~/.local/share/signal-cli/ on Linux). siggy does not read, write, or manage these files. If credential storage security is a concern, it should be addressed at the signal-cli level or via OS-level protections (encrypted home directory, restrictive file permissions).

Encryption

In transit

All messages are end-to-end encrypted using the Signal Protocol, handled entirely by signal-cli. siggy communicates with signal-cli over a local stdin/stdout pipe using JSON-RPC – no network sockets are involved.

At rest

Messages are stored unencrypted in a local SQLite database (siggy.db). This is the same approach used by Signal Desktop and most other messaging clients. The rationale is that local storage protection is best handled at the OS level (full-disk encryption, screen lock, file permissions) rather than by individual applications.

The database uses PRAGMA secure_delete = ON, which zeroes out deleted content in the database file rather than leaving it recoverable in free pages.

Files on disk

FileContentsLocation
siggy.dbMessage history, contacts, groupsPlatform config directory
siggy.db-walRecent uncommitted writesSame directory
config.tomlPhone number, settingsPlatform config directory
debug.logDebug output (opt-in, PII redacted by default)~/.cache/siggy/
Download directoryReceived attachments~/signal-downloads/ or configured path

Platform config directories:

  • Linux / macOS: ~/.config/siggy/
  • Windows: %APPDATA%\siggy\

File permissions

On Unix (Linux / macOS), siggy creates its sensitive files and directories with restrictive permissions: the lock hash, debug log, and their parent directories are set to owner-only (0600 for files, 0700 for directories).

On Windows there is no portable equivalent of chmod, so siggy does not set an explicit DACL. Instead it relies on the default per-user ACLs that Windows applies to the profile directories these files live in (%APPDATA%, %USERPROFILE%, %LOCALAPPDATA%). Under those defaults other standard user accounts cannot read your siggy files, but local administrators still can. If that is part of your threat model, enable BitLocker (full-volume encryption) or store your profile on an encrypted volume. This is a deliberate choice over manipulating Win32 security descriptors, which could lock you out of your own files if it went wrong.

Privacy features

Incognito mode

siggy --incognito

Uses an in-memory database instead of on-disk SQLite. No messages, conversations, or read markers are written to disk. When you exit, everything is gone.

Notification previews

Desktop notification content is configurable via the notification_preview setting in /settings:

LevelTitleBody
full (default)Sender nameMessage content
senderSender name“New message”
minimal“New message”(empty)

Debug logging

Debug logging is opt-in only and disabled by default.

  • --debug – enables logging with PII redaction: phone numbers are masked (e.g. +4***...567), message bodies are replaced with [msg: 42 chars], and contact/group lists show only counts.
  • --debug-full – enables logging with full unredacted output. Only use this when you need actual message content for troubleshooting, and delete the log file afterwards.

Debug logs are written to ~/.cache/siggy/debug.log with 10 MB rotation. On Unix systems, the log file and directory are created with restrictive permissions (0600 / 0700). See File permissions for how this differs on Windows.

Chat exports (/export) and the unredacted --debug-full log have terminal control characters stripped on write (newlines and tabs are kept), so opening either with cat/type cannot execute escape sequences embedded in a message body. Desktop notification titles and previews are likewise stripped of control characters before being handed to the OS notifier.

Clipboard

Copied message content is automatically cleared from the system clipboard after 30 seconds (configurable via clipboard_clear_seconds in config).

Session lock

Ctrl-L (or /lock) blanks the chat behind a passphrase prompt for the “someone walked up to my terminal” case. Set lock_timeout = N (minutes) in the config to also auto-lock after N minutes without a keypress (0, the default, disables it; mouse movement does not count as activity). The passphrase is stored as an argon2 PHC hash at {config_dir}/lock_hash, never as plaintext. While locked:

  • Keyboard input is intercepted; nothing reaches the composer
  • Terminal bell and OS desktop notifications are suppressed
  • Window title is clamped to bare siggy so the unread count does not leak

Threat model. Session lock is a deterrent against casual on-screen snooping, not a defence against an attacker with shell access. Anyone who can read your home directory can also delete lock_hash and bypass the prompt, which is the same escape hatch the maintainer uses to recover from a forgotten passphrase (siggy --reset-lock). If you need stronger at-rest protection for the message DB, rely on full-disk encryption.

Recommendations

  • Enable full-disk encryption on your device (BitLocker, LUKS, FileVault). This is the single most effective protection for data at rest.
  • Use --incognito mode for sensitive sessions where you don’t want any messages persisted to disk.
  • Set notification_preview = "sender" or "minimal" if you’re concerned about notification content being visible on lock screens or in screen recordings.
  • Use a screen lock to prevent physical access to your terminal session.
  • On shared Unix systems, restrict file permissions on the config directory (chmod 700 ~/.config/siggy).
  • On Windows, the config and cache directories inherit your user profile’s default ACLs (other standard users cannot read them; local administrators can). Enable BitLocker if you need protection beyond that. See File permissions.

Reporting vulnerabilities

If you discover a security issue, please report it responsibly via GitHub Issues or contact the maintainer directly. We take security seriously and will respond promptly.