📌 Description
Several sensitive columns are stored in plaintext: webhook subscriber secrets,
and potentially verifier callback credentials. API keys are hashed (not
reversible), but webhook HMAC secrets must remain reversible to re-sign, so
hashing is not an option — they need encryption at rest. There is no shared
envelope-encryption helper today.
Goal: reversible secrets are encrypted at rest with a rotatable key,
decrypted only in memory at use time.
🎯 Requirements and Context
src/lib/encryption.ts provides encryptField/decryptField using
authenticated encryption (AES-256-GCM) with a key resolved from
src/config/env.ts (FIELD_ENCRYPTION_KEY), supporting key-id tagging for
rotation.
- Stored ciphertext carries the key id so old data decrypts after rotation.
- Applied to webhook secrets (and any other reversible secret columns).
- Decryption failures are surfaced clearly, never silently returning ciphertext.
🛠️ Suggested Execution
1. Create a branch
git checkout -b feature/field-encryption-at-rest
2. Implement changes
- Add
src/lib/encryption.ts and wire it into webhook secret read/write.
- Add
FIELD_ENCRYPTION_KEY(s) to env validation.
- Document key rotation in
docs/security-ci.md (or a new doc).
3. Test and commit
- Add
src/tests/encryption.test.ts covering round-trip, tamper detection
(GCM auth failure), key-id rotation decrypt, and missing-key startup failure.
- Run
bun test src/tests/encryption.test.ts.
- Edge cases: tampered ciphertext, wrong key, rotated key, empty plaintext.
Example commit message
security: AES-256-GCM field encryption at rest for reversible secrets
✅ Guidelines
- Minimum 95% test coverage on new/changed lines.
- Document the key-rotation procedure.
- Timeframe: 96 hours.
🏷️ Labels
type-security · area-backend · type-feature · MAYBE REWARDED · GRANTFOX OSS · OFFICIAL CAMPAIGN
💬 Community & Support
📌 Description
Several sensitive columns are stored in plaintext: webhook subscriber secrets,
and potentially verifier callback credentials. API keys are hashed (not
reversible), but webhook HMAC secrets must remain reversible to re-sign, so
hashing is not an option — they need encryption at rest. There is no shared
envelope-encryption helper today.
🎯 Requirements and Context
src/lib/encryption.tsprovidesencryptField/decryptFieldusingauthenticated encryption (AES-256-GCM) with a key resolved from
src/config/env.ts(FIELD_ENCRYPTION_KEY), supporting key-id tagging forrotation.
🛠️ Suggested Execution
1. Create a branch
2. Implement changes
src/lib/encryption.tsand wire it into webhook secret read/write.FIELD_ENCRYPTION_KEY(s) to env validation.docs/security-ci.md(or a new doc).3. Test and commit
src/tests/encryption.test.tscovering round-trip, tamper detection(GCM auth failure), key-id rotation decrypt, and missing-key startup failure.
bun test src/tests/encryption.test.ts.Example commit message
✅ Guidelines
🏷️ Labels
type-security·area-backend·type-feature·MAYBE REWARDED·GRANTFOX OSS·OFFICIAL CAMPAIGN💬 Community & Support