Security

Security at Ghostli

What we actually store, in what form, for how long, and how to report a problem if you find one - written for the people who check before they trust.

This page is our own internal security overview, published by us, not a certification from an independent auditor. We'd rather be specific about what is actually true today than hand you a badge that means nothing. If a claim below turns out to be wrong, we want to hear about it - see the bug bounty section below.

The short version: your token is never stored in a reversible form, your conversations are never stored on our servers at all, and any email we collect is only kept in a form that can be decrypted for as long as it takes to actually deliver something to you.

01 The desktop app

Most of what matters happens on your machine before it ever reaches us. The app decides what you see, what gets attached to a request, and what stays local.

Area How it works
Local app data Conversation history, workspace metadata, and session state are stored in a local database, encrypted at rest with a key derived from a passphrase you set on first launch. We hold no cloud copy.
Key derivation Argon2id where available, with a PBKDF2 compatibility path, for the authentication material; AES-GCM for the encrypted local package.
Workspace boundary Only the folder you select is in scope. Nothing outside it is read. Live Workspace and Repository Context scan locally, skip heavy folders like node_modules and .git, and build a capped map, not a full upload.
Session storage The desktop auth session is kept through the operating system's secure storage where available, not a plain settings file.
Your token Treated like an API key. It authenticates the app, it is not your identity, and it should never be pasted into a prompt.
What this means in practice Losing your local passphrase means losing your local data. There is no server-side recovery, because there is no server-side copy to recover from.

How the local password and encryption actually work

When you set your local passphrase on first launch, nothing is sent anywhere. A random salt is generated, and it is used to derive two separate keys from your passphrase: one that verifies the passphrase is correct, and one that encrypts your data. They are derived with different purpose labels so the same material can never be reused for both jobs.

The app's default derivation is Argon2id, a memory-hard function chosen specifically because it is expensive to attack with GPUs, tuned with a time cost of 3, roughly 64 MB of memory cost, and a single-lane parallelism setting. Older local records that predate this upgrade are still readable through a PBKDF2-SHA256 compatibility path (300,000 iterations), and are transparently upgraded to Argon2id the next time you unlock successfully.

Verification never compares your password directly. It derives a hash and compares it to the stored one byte-by-byte in constant time, so the comparison itself can't leak timing information about how close a guess was. Repeated failed attempts are throttled with an increasing lockout, up to 15 minutes, so local brute-forcing a passphrase is not a fast option even for someone with the encrypted file in hand. Once unlocked, your data is decrypted with AES-GCM, which also authenticates the metadata alongside the ciphertext, so a tampered payload fails to decrypt instead of silently returning garbage.

Verify it yourself We publish the actual AuthManager logic behind this, near 1:1 with what ships in the app: Argon2id derivation, the PBKDF2 compatibility path, the automatic upgrade between them, constant-time verification, the lockout, and authenticated AES-GCM encryption. What's cut is the Electron/UI plumbing around it, replaced with a plain pluggable storage interface so it runs anywhere. The README explains exactly what was kept and what was cut, and why. Source: github.com/GhostliAI/ghostli-local-encryption.

02 The API

This is the part that actually handles your requests: authentication, plan limits, and routing to a model. Here's what it does and does not keep.

Area What we do
Token storage bcrypt hash only. Requests are matched against the hash; the raw token is never stored server-side.
Conversation content Not stored. Your client sends conversation history with each request; the API does not write prompts or replies to a database.
Server logs Redacted before anything is written: message, content, prompt, token, password, secret, key, history, and file fields never land in plaintext logs.
Device and session limits Enforced per device, with heartbeat checks and active-device tracking, so plan limits apply to real usage, not a shared static key.
Requests to AI providers Minimized identity: the API acts as a privacy-preserving layer between you and the upstream model, and avoids forwarding your raw token, payment email, or raw IP as part of an ordinary model request.
Rate limiting Applied across authentication, chat, and heartbeat endpoints to blunt abuse and brute-force attempts.
Checkout / free-plan email Kept only briefly: readable only for as long as it takes to deliver a token or confirmation, then cleared to a one-way hash used purely for anti-abuse lookups.

None of this makes us unbreakable, and we're not going to pretend otherwise. It means the things that would actually hurt you in a worst-case breach - your raw token, your stored email, your conversations - are either not stored, not reversible, or not there for long.

03 Reporting a vulnerability

If you find a real security issue, we want to know before anyone else does. Report it through our Discord or via the contact listed in /.well-known/security.txt. Include what you found, how to reproduce it, and what you think the impact is.

A few ground rules that keep this useful for everyone: don't access, modify, or exfiltrate data that isn't yours, don't run anything destructive against production, and give us a reasonable window to fix the issue before talking about it publicly. Automated scanner noise without a real finding isn't a report, it's just traffic.

04 Bug bounty

If you responsibly report a genuine, previously unknown vulnerability, we will thank you and, at our discretion, send something back - typically account credit or a plan upgrade sized to how serious the finding actually is. There's no fixed public payout table, and we're not going to pretend there's an unlimited budget behind this. What we can promise is that a real finding, reported responsibly, gets a real reply and a real reward, not silence.

That's also just the more useful path for you: a private report gets you an actual thank-you and something in your account. A public callout gets you a scramble to patch and, most likely, nothing else.

ยท

Found something, or want more detail on any of this before you rely on it? The Discord is the fastest way to reach us.

Don't take our word for the encryption claims - read the source: github.com/GhostliAI/ghostli-local-encryption.