Security
Last updated . Packs hold credentials, so this page says how ShellTasks protects them, what our server can and cannot see, and what is not built yet. It describes the design the apps are built to. When a part of it ships or changes, this page changes with it.
Where things stand. The ShellTasks apps and tsk are not released yet. End-to-end encryption ships with sync in Phase 2, the first beta. Today you can use the playground: it keeps everything in your browser's localStorage, sends nothing to a server and encrypts nothing. Don't paste real secrets into it.
The short version
- Secret fields are encrypted on your device before they sync. Our server stores only ciphertext.
- Without an account, nothing leaves your device.
- Secrets stay masked on screen, and the clipboard is cleared 30 seconds after you copy one.
tskprints secrets only to standard output and never writes them to a temporary file.- If you lose both your passphrase and your recovery key, nobody can get your secrets back, including us.
Secrets are encrypted on your device
Any field typed as a secret (db_password:secret in the pack editor) is encrypted on your device with libsodium's crypto_secretbox before it is written to the sync payload. The server stores the ciphertext and its nonce. It never has the key, so it cannot read the value, and neither can anyone who gets into the server or its backups.
Each account has a keypair. Its private key is wrapped by a key derived from your passphrase with Argon2id, so the server only ever holds it wrapped. Shared team packs, which come later, get a pack key wrapped once for each member's public key, so adding someone to a pack does not mean re-encrypting it.
When you sign up you get a printable recovery key. Keep it somewhere safe. If you lose your passphrase and the recovery key, your secrets are gone, and the app says so before you rely on it.
What our server can and cannot see
Can see
- Your account email and your paired devices
- Task text, due dates, priority and project
- Pack names, field keys and field types
- Values of text, URL, command and date fields
- When each record changed
Cannot see
- Values of secret fields
- Your passphrase
- Your private key and your recovery key
Keys and non-secret values stay readable so search and the web app work without extra crypto. That means a key name like db_password is visible to the server even though its value is not. If a value is sensitive, type it as a secret, and keep secrets out of task text.
Local first
The desktop app and tsk work offline on a local database. You can use them without an account, and then nothing leaves your device. Sync is the only thing that sends packs to our server, and it needs an account. Usage pings (install, first pack, weekly active) will be opt-in and anonymous.
On your device, the app keeps its key in the OS keychain and locks after a period of idle time, behind your OS password or biometrics.
Masking and the clipboard
Secret values are masked wherever the app shows them, and typed into a password field in the pack editor. Quick lookup copies a value without showing it: type #acme-prod.db_password in the input bar and press Enter. After you copy a secret, ShellTasks clears the clipboard 30 seconds later, unless you copied something else from ShellTasks in the meantime. A clipboard history tool on your computer can still keep its own copy, so turn it off or exclude ShellTasks if you use one.
The playground already masks secrets and clears the clipboard this way.
Secrets in the terminal
tsk getandtsk envprint secrets to standard output only, never to standard error or a log, so$(tsk get acme-prod.db_password)works and nothing else records the value.tsk exec acme-prod -- php artisan migratesets the values in that command's environment. It writes no temporary file.tsk set acme-prod.db_password:secretwith no value asks for it at a hidden prompt, so the secret stays out of your shell history.tsk env acme-prod > .envwrites plain text to a file you chose. Keep that file out of Git, or usetsk execinstead.- Synced packs are decrypted on your machine. Our server never sends a secret in plain text, because it has none.
What ShellTasks is not
ShellTasks keeps the context for your own work and your small team's: the staging password, a client's API key, the server you deploy to. It is not a production secrets manager. For secrets your servers and CI read at runtime, keep using Vault, Doppler, Infisical or your cloud's secret store. Later, a field will be able to point to a 1Password or Bitwarden item instead of holding the value, for teams whose policy rules out a new secret store.
Not built yet
Everything above is the design. This is what does not exist today:
- Accounts, sync and encryption. They ship together in Phase 2. No ShellTasks server holds packs today.
- The published encryption design and its test vectors (below).
- The recovery key, keychain storage and the idle lock. They ship with the desktop app.
- Two-factor sign-in and a written incident process. Both come before we sell to teams.
- Shared team packs and an audit log of who revealed a secret and when. They come with the Team plan.
- An external penetration test, once revenue allows.
The encryption design
The full design will be written up as ADR 0002 before any encryption code exists: the formats, the key derivation parameters, and test vectors that the app and tsk must both pass. It is not published yet; it will be linked here when it is.
We also plan to open-source tsk, so you can read the code that decrypts your secrets.
Reporting a problem
If you find a security issue in shelltasks.com or the playground, email [email protected] with "Security" in the subject. Please give us a chance to fix it before you publish it. How we handle your own data on this site is on the privacy page.