Security and privacy
You're handing us your commit history. Here's what we do with it.
Every claim on this page matches what the code does today, not what a policy says it should. Where something isn't in place yet, it says so.
Data flow
What crosses each boundary
What we store
- Your account: email, display name, avatar
- Per-day summaries and their highlights
- Commit counts and an hour-of-day histogram, for charts
- Non-commit work you log by hand or push in through the API
- Settings, schedule, repository rules, task links
What we never store
- File contents or diffs
- Your full commit history
- Audio from dictation — recognition runs in the browser
- Your AI provider key in plaintext — it is encrypted on the way in and never returned
Six things the code actually enforces.
Encrypted at rest
GitHub, GitLab and Google tokens, AI provider keys, tracker and calendar credentials, and any database password are encrypted with AES-256-GCM before they reach Postgres.
The key lives outside the database, so a dump, a restored snapshot or a leaked service-role key does not hand over credentials. Ciphertext is tamper-evident: a modified value fails rather than decrypting to something else.
Separated at the database
Every workspace table carries row-level security. One company's data is unreachable from another's by policy, not by a filter in application code.
A test suite creates two workspaces with two throwaway accounts and attempts every cross-workspace read and write with a signed-in user's credentials — the same ones a browser holds — so the database is what has to stop it.
Drafts until you submit
Summaries you generate by hand are shown before they are saved; nightly runs land as drafts you review and submit. Reports and dictated entries are drafts too. Hours carry their provenance; an estimate is labelled as one.
A task key the model invents is discarded. Write-back to Jira or Linear is off by default and only fires for a link a commit named, never one the model inferred — a comment on a real issue is a claim about someone's work in front of their colleagues.
Keys are hashed, prices are server-side
API keys are shown once and only a SHA-256 hash is stored. Checkout takes a pack id and reads the price from the database; the browser never grants credits.
Payment fulfilment happens only on the signed server-to-server webhook, and a replayed webhook cannot grant twice. Operator-only database functions are revoked from every public role and re-check the caller inside their own body.
Minimal scopes
GitHub sign-in asks for the repo scope — GitHub has no read-only scope for private repositories — and your email. Google sign-in asks for Sheets and Drive-file access, limited to files Devlog creates, so the Sheets destination works without a second consent screen.
Calendar and tracker connectors take a token you create with the scope you choose, and each one is isolated: an expired Jira token costs you Jira, not your GitHub summary.
Delete means delete
Settings → Delete account removes your account and everything keyed to it. Public profiles are off until you publish one and show aggregates only.
Entries already written into a workspace report are retained by that workspace as its business record of work performed — which is what the Terms say, and what a manager would reasonably expect.
What we don't claim
- No third-party audit or SOC 2 report yet. The controls above are real; the paperwork isn't.
- An AI provider key you paste in never comes back to the browser — the settings screen shows its last four characters. If you lose it, replace it.
- Self-hosted deployments are only as encrypted as the key you set. Without SECRETS_ENCRYPTION_KEY, tokens are stored as-is.
- Outbound webhooks to Slack, Discord, Teams or a custom endpoint carry the log text. Choose the channel accordingly.
Found something?
Email security@devlog.app with what you found and how to reproduce it. A human reads it, you get a reply, and we won't pursue anyone who reports in good faith. The same address is published at /.well-known/security.txt.
The full data inventory is in the privacy policy; self-hosting details are in the docs.