Skip to content

fix(security): reject encrypted-envelope credentials at provider create/update validation - #15932

Merged
diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.52from
hongkongkiwi:fix/enc-envelope-credential-guard
Oct 9, 2026
Merged

diegosouzapw merged 1 commit into
diegosouzapw:release/v3.8.52from
hongkongkiwi:fix/enc-envelope-credential-guard

Conversation

@hongkongkiwi

Copy link
Copy Markdown
Contributor

Closes #15930

What

Rejects provider credentials that arrive already carrying the enc:v1: envelope prefix at both validation seams:

  • createProviderSchema (POST /api/providers)
  • updateProviderConnectionSchema (PATCH /api/providers/{id})

with a clear message: "apiKey looks like an encrypted envelope from a credential store, not a plaintext key — store the plaintext API key" — instead of today's flow, where the envelope is stored verbatim and surfaces only as a misleading 5ms Missing API key / auth_missing on the connection test.

Why schema-level

encrypt() deliberately skips re-encrypting values that already carry the prefix (src/lib/db/encryption.ts), so the envelope gets stored as-is, then decryptConnectionFields returns null at runtime. Plaintext keys from every provider (sk-…, tvly-…, JWTs, cookie headers, JSON storage state) start with something else, so the rejection is near-zero-false-positive — per the analysis in #15930.

The check is inline in the schemas rather than reusing looksEncrypted(): both schemas are imported by client-side dashboard code (providerOnboardingApi.ts), and the crypto-backed module must not enter that bundle.

Also in this diff

  • Drops 10 unused imports in schemas/provider.ts (pre-existing on release/v3.8.52) that trip the pre-commit no-unused-vars gate for any change to this file, plus their now-stale entries in config/quality/eslint-suppressions.json.

Tests

New tests/unit/15930-encrypted-envelope-credential-rejected.test.ts (follows the issue-number naming convention):

  • create + update reject an enc:v1:-prefixed credential with an apiKey-path issue
  • create still accepts plaintext keys, including values containing enc:v1: mid-string (startsWith semantics)
  • update still accepts plaintext keys and unrelated patches; the "No valid fields to update" empty-patch rejection is preserved

Verified locally: 4/4 new + 74/74 existing provider-schema tests pass; eslint-suppressions-pruned consistency test 5/5.

…te/update validation

A credential arriving with the enc:v1: prefix is an encrypted envelope from a
credential store, not a plaintext key. encrypt() deliberately skips re-encrypting
prefixed values, so such a payload was stored verbatim, failed to decrypt at
runtime, and surfaced only as a misleading 5ms "Missing API key" on the
connection test (auth_missing) despite the row showing api_key SET.

Plaintext keys from every provider (sk-…, tvly-…, JWTs, cookie headers, JSON
storage state) start with something else, so the schema-level rejection is
near-zero-false-positive. Checked inline rather than via looksEncrypted() because
these schemas are imported by client-side dashboard code (node:crypto-free).

Also drops 10 unused imports in schemas/provider.ts (with their now-stale eslint
suppression entries) that trip the pre-commit hook for any change to this file.

Closes diegosouzapw#15930
@diegosouzapw
diegosouzapw merged commit 9103923 into diegosouzapw:release/v3.8.52 Oct 9, 2026
3 checks passed
@diegosouzapw

Copy link
Copy Markdown
Owner

Thanks @hongkongkiwi — creating or updating a provider now rejects an apiKey that is still an enc:v1: envelope. This is in the upcoming release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(security): credentials that already carry the enc:v1: prefix are stored verbatim — foreign ciphertext fails later as a confusing "Missing API key"

2 participants