Security
GhostSwap credentials let the holder create swaps that move real funds. Treat them like a payment processor secret key.
Keep credentials server-side
✅ Server-side environment variables loaded into your runtime.
✅ Secret managers (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, Doppler, 1Password Connect).
✅ Backend services with TLS 1.2+ to call our API.
❌ Browser code — single-page apps, mobile apps, anything served to a user device. Anything in the client bundle can be extracted in seconds.
❌ URL query strings — leak into server logs, browser history, referrer headers, third-party analytics.
❌ Source control — even private repos. Use .env (gitignored) or a secret manager.
❌ Error messages, logs, response bodies you return to the user.
Protect the secret at rest
The secret half (gssk_live_*) is shown at creation and is re-viewable from the dashboard via the Reveal secret button. Treat it as a production secret regardless.
Where to store it depends on the environment:
# Local development — fine when the file is gitignored:
echo "GHOSTSWAP_SECRET=gssk_live_..." >> .env.local
# Production — use a real secret manager so the value is never on disk
# beside your code, never baked into a build artifact, and rotatable
# without a redeploy:
gh secret set GHOSTSWAP_SECRET # GitHub Actions
op item edit "GhostSwap" credential=... # 1Password
aws secretsmanager put-secret-value --secret-id ghostswap/prod ... # AWS
doppler secrets set GHOSTSWAP_SECRET=... # DopplerThe cardinal rule: the secret never lives in source control, build artifacts, browser bundles, log lines, or URL query strings.
If you lose track of the secret, you can recover it from /dashboard/api-credentials (Reveal secret on the credential row). Every reveal is audit-logged on our side; we will reach out if we see a pattern that looks unusual (multiple reveals from new IPs, etc.).
Reveal is for recovery, not a routine flow. Step-up auth (re-prompt for password / WebAuthn) and a rate cap on reveals are on the near-term roadmap. In the meantime: if you suspect a secret has leaked, revoke the credential instead of revealing — that invalidates it everywhere immediately and lets you issue a fresh credential after the brief 401 window.
How we store it: the secret lives as both an argon2id hash (used on every authentication) and an AES-256-GCM ciphertext (used for the Reveal flow). Both require the master KEY_ENCRYPTION_KEY env var on our infrastructure to decrypt — neither can be recovered from a database snapshot alone.
Rotate regularly
Recommended cadence: every 90 days, plus on any of:
- Team member who had access leaves.
- Suspected secret leak (committed to repo, posted in chat, etc.).
- Unexplained traffic spike on the credential's last-used metric.
Rotation flow:
- Create a new credential in the dashboard.
- Roll the new bearer token into your environment.
- Verify traffic flows through the new credential (watch its
last_used_at). - Revoke the old credential.
Reduce blast radius
- Separate credentials per environment: one for staging, one for production. (When per-environment keys land — see Roadmap — this becomes a built-in feature.)
- Don't share credentials between services. If service A and service B both need access, give them separate credentials so you can rotate one without touching the other.
- Audit credential usage. The dashboard shows
last_used_at. Anything stale is a candidate for revocation.
Monitor traffic
- Log every request's
X-Request-Idresponse header. When escalating to support, this lets us find your exact request. - Alert on unexpected 401s. Could indicate a revoked or rotated credential; could also indicate a compromised credential being abused.
- Alert on unusual rate-limit errors. A sudden spike in 429s without a corresponding traffic increase suggests someone else has your credential.
- Track per-credential volume against expectations. If a credential normally creates 100 swaps/day and you see 10,000, that's an alert.
TLS only
https://partners-api.ghostswap.io only. We do not serve over plain HTTP. Reject anything that comes back unencrypted.
What we do server-side
For your awareness, here's what we do to protect you:
- Secrets are stored as argon2id hashes. Nobody at GhostSwap can read your secret — even our DBAs see only the hash.
- Bearer tokens are checked in constant time to prevent timing attacks.
- Per-credential and global rate limits cap the damage from abuse.
- Every request is logged with
X-Request-Idfor forensics. - Idempotency keys prevent replay attacks from creating duplicate swaps.
Reporting a leak
If you suspect your credential has leaked:
- Revoke immediately at /dashboard/api-credentials.
- Email support@ghostswap.io with the credential's public key (
gspk_live_...) and a description of the suspected exposure. - We'll review usage logs and respond within one business day.
What's coming
Roadmap entries that further harden credentials:
- Per-credential IP allowlists so a leaked credential can't be used outside your servers.
- Per-credential method scopes for read-only or restricted credentials.
- Test-mode keys (
gssk_test_*) so you can iterate safely without live funds.