RunoSO - Business OS for Solo Operators LogoRunoSO
FeaturesPricingTemplatesBlogAbout
Sign inStart free
RunoSO LogoRunoSO

Run your solo business. From one place.

Built in India 🇮🇳

Product

FeaturesPricingBlogChangelogRoadmap

Legal

Terms & ConditionsPrivacy PolicyRefund PolicyCookie PolicyData Deletion

Connect

Twitter/XLinkedInInstagramhello@runoso.in
Made by RunoSO
© 2026 RunoSO. All rights reserved.
Back to Blog

Featured Articles

Build in Public

Why I Ditched Notion & Sheets to Build RunoSO

7 min read
Technical Deep-Dive

How I Built a Zero-Knowledge Vault with AES-256

10 min read
Productivity

Best Freelance Tools in 2026 — Honest Stack Review

11 min read
View all posts
  1. Home
  2. Blog
  3. Client Credential Rotation: The Security Workflow Agencies Ignore
Technical Deep-Dive

Client Credential Rotation: The Security Workflow Agencies Ignore

By Gautam Parmar28 September 20268 min read
Client Credential Rotation: The Security Workflow Agencies Ignore — featured image

You finished Acme E-commerce 18 months ago. The SSH root@203.0.113.45 + Stripe live key sk_live_... + WordPress admin / ... still sit in Sheets Acme Credentials shared with edit access to two ex-contractors. No rotation log, no updatedAt, no vault — just plaintext cells last touched 2024-09-02. If one contractor's drive leaks, Acme's production is yours to explain.

Agencies rotate logos. They don't rotate secrets. One breach averages $4.45M IBM reports — freelancers won't pay that, but they lose the client, the referral, and reputation. Rotation is not paranoid — it's professional.

Why Freelancers Never Rotate

No trigger. Sheet cell sk_live... lacks updatedAt src/lib/db/schema.ts:137 + category src/lib/db/schema.ts:123 — you never see 180-day stale. No impact link. Stripe Acme in 1Password without clientId/projectId src/lib/db/schema.ts:133 → you can't filter Beta's 8 secrets, so you rotate none. No asset binding. assetsHosting vaultItemId src/lib/db/schema.ts:198 should tie IP+credential; Sheets keeps tabs separate → rotate hunt fails. Leak handover. Email passwords.txt without portalTokens revokedAt src/lib/db/schema-public.ts:175 leaves ex-contractor copy alive.

The Rotation-Ready Vault: Encryption + Linkage + Alerts

RunoSO's vault was built for rotation, not just storage. Three layers:

Layer 1: AES-256-GCM Encryption

encryptGCM src/lib/vault/crypto.ts:22 → deriveKey SHA-256 src/lib/vault/crypto.ts:18 → 12-byte iv → AES-256-GCM → tag getAuthTag → gcm:iv:tag:enc base64 src/lib/vault/crypto.ts:28. decryptGCM verifies tag setAuthTag src/lib/vault/crypto.ts:40 — tamper returns null. All vaultItems usernameEncrypted fields src/lib/db/schema.ts:129 use this; VAULT_MASTER_KEY src/lib/vault/crypto.ts:5 per-tenant — dump is ciphertext.

Layer 2: Linked to Client/Project/Asset

ts
vaultItems {
  category password|server|api-key|other src/lib/db/schema.ts:123
  name vault name
  usernameEncrypted, passwordEncrypted, notesEncrypted src/lib/db/schema.ts:129
  url text src/lib/db/schema.ts:131
  clientId fk → clients.id src/lib/db/schema.ts:133 // who
  projectId fk → projects.id src/lib/db/schema.ts:134 // which scope
  metadataEncrypted encrypted JSON src/lib/db/schema.ts:135 // rotation history, provider hints
  createdAt, updatedAt timestamp src/lib/db/schema.ts:136 // staleness signal
}
assetsHosting.vaultItemId → vaultItems.id src/lib/db/schema.ts:198
assetsSocial.vaultItemId → vaultItems.id src/lib/db/schema.ts:213
assetsSubscriptions.vaultItemId → vaultItems.id src/lib/db/schema.ts:229

Rotate SSH root? Query vaultItems where clientId=Acme + category=server → 3 items sorted by updatedAt. Oldest shows updatedAt 2024-09-02 — 180+ days stale. No 1Password collection gives you that.

Layer 3: Expiry and Handover Signals

assetsDomains expiryDate + assetsHosting renewalDate + assetsSubscriptions renewalDate are already on cron DOMAIN_MILESTONES [14,7,3,1,0] src/app/api/cron/daily/route.ts:16 (daily src/app/api/cron/daily/route.ts:275) → notifications. Six-asset API ALLOWED_CATEGORIES ["domains","cloudflare","github","hosting","social","subscriptions"] src/app/api/assets/[category]/route.ts:91 groups them. Use 7 days window to piggyback rotation. Handover uses portalTokens src/lib/db/schema-public.ts:169.

4-Step Rotation Workflow

1. Inventory — 60s. Filter clientId Acme + updatedAt asc — >90d api-key or >180d server flag stale. 2. Rotate. Generate new key, edit vault → encrypt(text) fresh gcm:iv:tag:enc src/lib/vault/crypto.ts:48, test assetsHosting ipAddress src/lib/db/schema.ts:193, store metadataEncrypted {lastRotated, nextDue}. 3. Revoke. Filter clientId Beta → portalTokens revokedAt now src/lib/db/schema-public.ts:175 — kills old share. 4. Handover. portalTokens tenantId+clientId unique src/lib/db/schema-public.ts:178 shows domains+hosting+github+social names only; rotate server/api-key before sharing — zero lingering access.

Sheets / 1Password / LastPass vs RunoSO Rotation

Rotation NeedSheets1Password / LastPassRunoSO Vault + Assets + Cron
EncryptionPlaintext — rotation exposes historyAES-256 but no clientId/projectIdAES-256-GCM gcm:iv:tag:enc src/lib/vault/crypto.ts:22 + deriveKey SHA-256 + clientId/projectId FK
Find stale secretsScan Last edited guesses, no categorySort by modified, filter by tag onlyFilter `clientId + category serverapi-key + updatedAt sorted src/lib/db/schema.ts:125` — stale list in 1 query
Linked impactNo link to hosting IP/repoNo asset linkassetsHosting.vaultItemId + clientId src/lib/db/schema.ts:198 → rotate key → know exactly which ipAddress renewalDate is affected
Renewal cueNoneNo domain/hosting cronCron daily 03:30 UTC vercel.json:4 → domain 14/7/3/1/0 + renewal 7/3/1/0 → rotation nudge before expiry panic
Handover/revokeEmail passwords.txt forever validPsst! link per item, manual per clientportalTokens token revokedAt lastAccessedAt src/lib/db/schema-public.ts:169 → one revocable client bundle
HistoryOverwrite cell — history lostHistory per item, no FKmetadataEncrypted encrypted JSON per vault item → lastRotated, nextDue alongside ciphertext

Sheets store secrets. Managers encrypt secrets. RunoSO encrypts + links to asset + ages via updatedAt + alerts via renewalDate + revokes via portalTokens — the full rotation loop.

Mistakes That Keep Windows Open

Empty metadataEncrypted loses rotation log — store {lastRotated} encrypted. Changing vault without testing assetsHosting ipAddress+ vaultItemId breaks deploys. Slack after GCM rotation defeats purpose — use portalTokens.


Every secret you created 90 days ago and never touched is stale. Build the 90-day rotation cadence on linked, encrypted vault — not memory.

→ Lock and Rotate in RunoSO — Free


By Gautam Parmar — rotation is ops, not paranoia.


Keep Reading

  • Never store there: Where freelancers should never store passwords.
  • Hosting twin: Hosting & server management freelancers.
  • Zero-knowledge primer: Zero knowledge explained freelancers.

FAQ

How are vault secrets encrypted at rest? encrypt(text) src/lib/vault/crypto.ts:48 derives 32-byte key via SHA-256(VAULT_MASTER_KEY) src/lib/vault/crypto.ts:18, generates 12-byte iv randomBytes, encrypts AES-256-GCM, authenticates via tag getAuthTag, stores gcm:iv:tag:enc base64 src/lib/vault/crypto.ts:28. decryptGCM verifies tag setAuthTag src/lib/vault/crypto.ts:40 — tampered data returns null.

How do I find which credentials belong to a departing client quickly? vaultItems clientId src/lib/db/schema.ts:133 + projectId src/lib/db/schema.ts:134 + assetsHosting.vaultItemId/assetsSocial.vaultItemId. Filter clientId=Beta in vault and assets → 8 items + 2 hosting boxes + 3 socials in one view — rotate only those, not entire vault, unlike flat 1Password list.

How does handover stay secure after rotation? Generate new secrets, update vault (new gcm:iv:tag:enc ciphertext), then share via portalTokens token src/lib/db/schema-public.ts:169 scoped tenantId+clientId unique with revokedAt. Old token revokedAt set instantly invalidates contractor access; new token shows updated bundle — no email plaintext.

Try RunoSO for Free

Manage clients, invoices, vault, content, and finances — all from one beautiful dashboard.

Start free
Meet RunoSO
SaaS
Unified Workspace
Finance & Invoicing
Credentials Vault
Content Pipeline

Unified Workspace

The ultimate command center for solo operators. Replace Notion, Sheets, and password managers.

  • Unified client database
  • Real-time key metrics
  • Intuitive navigation
Start free todayLearn more about RunoSO

Featured Articles

Build in Public

Why I Ditched Notion & Sheets to Build RunoSO

7 min read
Technical Deep-Dive

How I Built a Zero-Knowledge Vault with AES-256

10 min read
Productivity

Best Freelance Tools in 2026 — Honest Stack Review

11 min read
View all posts
Meet RunoSO
SaaS
Unified Workspace
Finance & Invoicing
Credentials Vault
Content Pipeline

Unified Workspace

The ultimate command center for solo operators. Replace Notion, Sheets, and password managers.

  • Unified client database
  • Real-time key metrics
  • Intuitive navigation
Start free todayLearn more about RunoSO

Related Posts

Technical Deep-Dive

How to Offboard a Developer Without Credential Nightmare

Offboard a freelance developer — revoke vault, rotate hosting keys and portal handover without breaking production daily. RunoSO revokes vault and rotates.

Technical Deep-Dive

How to Store .env Files for Freelance Projects Safely

Store .env files for freelance projects — vault categories, per-project scope and rotation cadence without Slack leaks daily. Track in RunoSO with linked cli.