This document describes how PostPilot handles your data, what leaves your machine, and what security practices are in place. It is intended for users who want to review the app before using it with sensitive credentials.
PostPilot is a local-first desktop application built with Tauri (Rust backend) and a Nuxt frontend. There is no PostPilot cloud backend involved in your API calls, database queries, or data inspection work. All core operations run entirely on your machine.
Database passwords are stored in your OS-native secure storage and are never written to disk in plaintext:
| Platform | Storage |
|---|---|
| macOS | Keychain Access |
| Windows | Credential Manager |
| Linux | Secret Service (GNOME Keyring / KWallet) |
Workspace connection files contain only { "password": { "keychain": true } }. The actual password lives only in the OS keychain, retrieved at query time.
Environment variables — including API keys, tokens, and any secret stored as {{variableName}} — are saved as plain JSON files inside your workspace folder under the environments/ directory. They are not encrypted at rest.
Recommendation: If you version-control your workspace with Git, add
environments/to your.gitignoreto avoid accidentally committing secrets.
PostPilot makes outbound network requests in two situations only:
HTTP requests you execute in PostPilot go directly from your machine to the target URL using the system network stack (Rust reqwest library). No content is routed through PostPilot servers. No request or response data is written to disk or app logs.
On every app launch, PostPilot contacts https://license.postpilot.dev/api to verify your license. See Section 7 — License Service for the full breakdown of what is sent.
Editing kits, running API requests, executing database queries, and inspecting data all work offline. License verification requires an internet connection on app startup. If the network is unavailable, the app will inform you.
Workspace data is stored as human-readable JSON files in the folder you select when creating a workspace:
my-workspace/
├── workspace.json
├── environments/ ← Variable values stored here in plaintext
│ └── <env-name>/
│ └── environment-variables.json
├── collections/ ← HTTP and DB kit definitions (no secrets)
│ └── <collection>/
│ └── *.http.json
└── database-connections/ ← Connection metadata (no passwords)
└── *.connection.json
| Data | Where | Encrypted? |
|---|---|---|
| Database passwords | OS Keychain | Yes (OS-managed) |
| Environment variables | Workspace JSON file | No — plaintext |
| HTTP kit content | Workspace JSON file | No |
| License key | App data directory | No (not a sensitive secret) |
| Device key (for license) | OS secure storage | Yes (OS-managed) |
All license operations contact: https://license.postpilot.dev/api
The app makes three types of requests to this endpoint:
POST /licenses/trialSent once when starting a free trial.
{
"device": {
"id": "<32-char device ID, derived from public key hash>",
"publicKey": "<ECDSA P-256 public key, base64 DER encoded>",
"keyOrigin": "OS_SECURE",
"keyType": "ECDSA_P256"
}
}
POST /licenses/activateSent once when activating a purchased license on a device.
{
"licenseKey": "XXXX-XXXX-XXXX-XXXX",
"device": {
"id": "<device ID>",
"publicKey": "<ECDSA P-256 public key, base64 DER encoded>",
"keyOrigin": "OS_SECURE",
"keyType": "ECDSA_P256"
},
"appVersion": "1.x.x"
}
POST /licenses/verifySent on every app launch to confirm the license is still active.
{
"licenseKey": "XXXX-XXXX-XXXX-XXXX",
"deviceId": "<device ID>",
"appVersion": "1.x.x"
}
This request is signed with your device's private key (stored in OS secure storage). The private key itself is never transmitted — only the cryptographic signature is sent, allowing the server to verify your device without ever seeing the key.
| Data | Stored? | Purpose |
|---|---|---|
| License key + status | Yes | Track whether license is active, expired, or suspended |
| Device ID (public key hash) | Yes | Bind license to your device |
| Device public key | Yes | Verify cryptographic signatures on future requests |
| App version at activation | Yes | Version enforcement |
| Request/response payloads | No | — |
| API keys or environment variables | No | — |
| Hardware identifiers | No | — |
| IP address logs | No | — |
| Usage analytics | No | — |
Your device ID is derived as hex(sha256(publicKey)[0..16]) — a 32-character opaque identifier computed from your device's cryptographic public key. It does not directly expose any hardware identifiers.
The desktop app does not auto-update. There is no background update process. Updates are published to the website and must be downloaded and installed manually by the user.
The browser-based version of PostPilot has a different security profile from the desktop app:
| Aspect | Desktop | Web |
|---|---|---|
| Data storage | Filesystem (workspace folder) | Browser localStorage |
| Credential storage | OS Keychain for DB passwords | No keychain — all localStorage |
| Database clients | Supported | Not supported |
| HTTP transport | Rust reqwest (direct) | Browser Axios (CORS applies) |
| Analytics | None | Vercel anonymous page visits |
| Updates | Manual download | Always latest deployed version |
Recommendation: For work involving production credentials, database connections, or sensitive API keys, use the desktop app. The web version does not have access to OS-level secure storage.