Deep Dive Field-Level Encryption in FlowSquad: How Your API Keys Are Protected
Deep-Dive Security Engineers ยท CISOs

Field-Level Encryption in FlowSquad: How Your API Keys Are Protected

Fernet (AES-128) encrypts every API key at the field level before it touches the database. Key rotation, environment variables, and what happens if your DB is breached.

May 22, 2026 · 9 min read · Security EngineersCISOs
TL;DR

What Is Field-Level Encryption and Why Does It Matter?

Database encryption comes in multiple forms, and they offer radically different security guarantees. Disk-level encryption (e.g., LUKS, BitLocker) protects data on stolen physical media but provides no protection against a running attacker with database credentials โ€” the database server decrypts everything transparently. Transport encryption (TLS) protects data in transit between application and database, but again, data sits as plaintext in the database itself. Field-level encryption (FLE) is different: the application encrypts specific field values before they ever reach the database, so the database stores ciphertext โ€” and a database-layer compromise (SQL injection, stolen DB credentials, database server breach) yields only encrypted data.

For FlowSquad specifically, the most sensitive data is API keys: OpenAI keys, Anthropic keys, Jira API tokens, GitHub OAuth secrets, SAML certificates, and Confluence tokens. These secrets are worth significantly more to an attacker than the application data they protect โ€” a stolen $0.01/1k-token OpenAI key can run up thousands of dollars in fraudulent API usage within hours. FLE ensures that even if your FlowSquad PostgreSQL instance is fully compromised, no API key material is recoverable without the host-level Fernet key.

How Does FlowSquad Implement Fernet Encryption?

FlowSquad uses Python's cryptography library, which implements the Fernet specification: AES-128-CBC symmetric encryption with PKCS7 padding, combined with HMAC-SHA256 for authentication. The Fernet token format is: Version(1) || Timestamp(8) || IV(16) || Ciphertext(n) || HMAC(32) โ€” all base64url-encoded. The HMAC component is critical: it detects any tampering with the ciphertext in the database and raises an exception before decryption is attempted, preventing padding oracle attacks.

# FlowSquad Field-Level Encryption โ€” illustrative implementation from cryptography.fernet import Fernet, MultiFernet import os # Key loaded from environment, never from DB _fernet = Fernet(os.environ["FERNET_KEY"].encode()) def encrypt_field(plaintext: str) -> str: """Encrypt a sensitive field value before DB write.""" if not plaintext: return plaintext return _fernet.encrypt(plaintext.encode()).decode() def decrypt_field(ciphertext: str) -> str: """Decrypt a field value after DB read.""" if not ciphertext or not ciphertext.startswith("gAAAAA"): return ciphertext # Not an encrypted field return _fernet.decrypt(ciphertext.encode()).decode() # Key rotation โ€” MultiFernet tries keys in order def build_rotation_fernet(old_key: str, new_key: str) -> MultiFernet: return MultiFernet([Fernet(new_key), Fernet(old_key)])

What Data Is Encrypted at the Field Level?

FlowSquad applies field-level encryption to 14 field types across its data models. These are annotated in the ORM layer with a custom EncryptedField descriptor that transparently encrypts on write and decrypts on read. Application code above the model layer never handles ciphertext directly.

Field / ModelData StoredEncryption
LLM Provider API KeyOpenAI / Anthropic / Azure API keysFernet AES-128
Jira API TokenJira Cloud / Server API tokenFernet AES-128
Confluence API TokenConfluence REST API tokenFernet AES-128
Git OAuth SecretGitHub / GitLab / Bitbucket OAuth app secretFernet AES-128
Git Personal Access TokenPAT for repository accessFernet AES-128
SAML CertificateIdP signing certificate (PEM)Fernet AES-128
VectorDB API KeyPinecone API key (if used)Fernet AES-128
SMTP PasswordEmail notification SMTP credentialsFernet AES-128
Webhook SecretGit provider webhook HMAC secretsFernet AES-128
SSO Client SecretOAuth 2.0 client secret for OIDCFernet AES-128

How Does Key Rotation Work Without Downtime?

FlowSquad's key rotation leverages Python cryptography's MultiFernet class, which accepts a list of Fernet keys and tries them in order during decryption. The rotation process proceeds in three phases and requires zero downtime:

Phase 1 โ€” Dual-key mode (5 minutes): The new key is added as the primary key in FERNET_KEY, and the old key is added as FERNET_KEY_PREVIOUS. The application creates a MultiFernet instance with both keys. New writes use the new key; existing ciphertext from the old key is still decryptable.

Phase 2 โ€” Background re-encryption (2โ€“3 minutes): An admin triggers the "Rotate Encryption" background job from Admin โ†’ Security โ†’ Key Rotation. The job reads every encrypted field, decrypts with MultiFernet (which handles both old and new keys), and re-writes using the new key only. Progress is shown in a real-time progress bar.

Phase 3 โ€” Old key removal: Once the job completes, FERNET_KEY_PREVIOUS is removed from the environment. All ciphertext in the database is now encrypted with the new key only. The old key is securely destroyed per the organization's key management policy.

What Happens to Your Data If the Database Is Breached?

A database-only breach โ€” where an attacker gains read access to all tables and rows but does not have access to the application host or its environment variables โ€” yields exclusively ciphertext for all 14 encrypted field types. The Fernet format does not expose the key length, algorithm parameters, or any plaintext prefix. Without the FERNET_KEY environment variable, the ciphertext is computationally infeasible to decrypt โ€” AES-128 brute-force at current compute rates would require longer than the heat death of the universe.

Breach scenario verdict: A database dump from a compromised FlowSquad PostgreSQL instance exposes: user email addresses (not encrypted โ€” used for login), hashed passwords (bcrypt, not decryptable), product names and generated content (not encrypted by design), and Fernet ciphertext for all 14 secret field types. No API keys, OAuth secrets, or certificates are recoverable. An attacker cannot pivot from a DB breach to LLM API abuse or code repository access.

Frequently Asked Questions

Is Fernet encryption the same as AES-256? Is AES-128 strong enough?

Fernet uses AES-128-CBC. While AES-256 has a larger key space, AES-128 has no known practical vulnerabilities and is considered computationally secure by NIST through at least 2030. The effective security of the Fernet key comes from the randomness of the 128-bit key material, not from brute-force resistance differences between 128 and 256 bits at current compute levels. FlowSquad's Enterprise tier supports AES-256 via a configurable cipher upgrade (roadmap Q2 2026).

Where should the FERNET_KEY be stored in production?

The FERNET_KEY should be stored in a secrets manager (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager) and injected as an environment variable at container startup. It should never be committed to source control, logged, or written to disk in plaintext. FlowSquad's deployment Helm chart includes a SecretKeyRef reference for Kubernetes deployments.

Are user passwords also encrypted with Fernet?

No. User passwords are hashed with bcrypt (cost factor 12), not encrypted. Hashing is the correct mechanism for passwords because it is one-way โ€” FlowSquad never needs to recover a plaintext password, only to verify a candidate password against the stored hash. Fernet encryption is used for secrets that must be recoverable (API keys, tokens) โ€” a fundamentally different use case.

What happens to encrypted fields during a FlowSquad version upgrade?

Database migrations (applied automatically or via manage.py migrate) never touch encrypted field values โ€” they only modify schema structure (add/remove columns, change indices). Encrypted field values are written and read by application code only, not by migration scripts. This means the Fernet key environment variable continuity across upgrades is the only requirement for encrypted fields to remain decryptable post-upgrade.

Does FlowSquad support Hardware Security Modules (HSMs) for key management?

Direct HSM integration (via PKCS#11) is on the Enterprise roadmap for Q3 2026. In the meantime, cloud HSM-backed secrets managers (AWS KMS + Secrets Manager, Azure Key Vault) can be used as the source of the FERNET_KEY environment variable, providing HSM-grade key protection for the Fernet key material itself without requiring direct PKCS#11 integration in FlowSquad's application code.

Share on dev.to Share on Hashnode Share on Medium Share on LinkedIn