Skip to content

fix(pam): atomic recording secret mint - #8043

Open
bernie-g wants to merge 4 commits into
mainfrom
bernie/pam-463-investigate-session-recording-endpoint-error-spike
Open

fix(pam): atomic recording secret mint#8043
bernie-g wants to merge 4 commits into
mainfrom
bernie/pam-463-investigate-session-recording-endpoint-error-spike

Conversation

@bernie-g

@bernie-g bernie-g commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Context

Recording secrets were minted with an unguarded read-decide-write on encryptedSessionKey, so two concurrent credential fetches for one session both minted and the later write won, leaving the earlier caller with a session key and upload token the row no longer matched. That gateway's chunk uploads then 400ed forever, and anything it had already uploaded became undecryptable at playback.

Fixes PAM-463, which accounted for 99.75% of Infisical Cloud US platform errors. The gateway-side half is in Infisical/cli#392.

Steps to verify the change

Race concurrent credential fetches at one live, never-minted session and check that every response carries the same session key, exactly one carries an upload token, and the stored hash is sha256 of that token.

Six concurrent fetches through the real stack, before and after:

Before After
Runs 6 8
Session keys diverged 5 of 6 0
Distinct keys issued for one session up to 6 always 1
Verdict 5 fail 8/8 pass

Also verified the guarded UPDATE against Postgres directly: eight concurrent claims on one row yield exactly one winner over five runs, where the unguarded version yields eight winners.

The second commit only renames error variants, so the four verifyGatewayUploadToken branches are distinguishable in logs. The client-facing message is deliberately unchanged, which keeps the response shape and the router's PAM_SESSION_UPLOAD_TOKEN_INVALID audit trigger working. After deploy, group chunk-route errors by errorName like /PamUploadToken/: all PamUploadTokenHashMismatch confirms the race.

Type

  • Fix

Checklist

  • Title follows the conventional commit format: type(scope): short description (scope is optional, e.g., fix: prevent crash on sync or fix(api): handle null response).
  • Tested locally
  • Updated docs (if needed)
  • Updated CLAUDE.md files (if needed)
  • Read the contributing guide

The mint was an unguarded read-decide-write: two concurrent credential fetches
both saw a null session key, both minted, and the later write won. The earlier
caller kept a session key and upload token the row no longer matched, so its
chunk uploads 400ed forever and anything already uploaded was undecryptable at
playback.

Guard the update on the key still being null and adopt the winner's secrets
when the claim is lost. Verified against Postgres: six concurrent fetches
previously issued up to six distinct session keys, now always one.
Four branches in verifyGatewayUploadToken threw the same opaque message, so a
malformed token and a token that simply does not match were indistinguishable
in logs despite pointing at different causes.

Give each branch a distinct error name and keep the client-facing message
identical, which leaves the response shape and the router's audit-log trigger
unchanged. Also drop the unreachable catch: Buffer.from discards invalid base64
rather than throwing, so a bad encoding shows up as a short decode.
@linear

linear Bot commented Sep 8, 2026

Copy link
Copy Markdown

PAM-463

@infisical-review-police

Copy link
Copy Markdown

💬 Discussion in Slack: #pr-review-infisical-8043-fix-pam-atomic-recording-secret-mint

Posted by Review Police — reviews, comments, new commits, and CI failures will stream into this channel.

@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

The PR should not merge until the losing claim path reads the winner's key consistently rather than potentially failing under read-replica lag.

Findings

  1. P1 Replica Lag Breaks Recovery
  2. P2 Atomic Claim Lacks Coverage

Summary

  • Uses a guarded update so only one concurrent credential fetch stores newly generated recording secrets.
  • Makes losing fetches adopt the stored session key.
  • Distinguishes missing, malformed, malformed-hash, and mismatched upload-token errors for operational diagnosis.
  • The loser lookup needs a primary-consistent read to avoid transient failures under replica lag.

Comment thread backend/src/ee/services/pam-session/pam-session-service.ts Outdated
Comment thread backend/src/ee/services/pam-session/pam-session-service.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8bbc9ed40

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread backend/src/ee/services/pam-session/pam-session-service.ts Outdated
The lost-claim path re-read the session through findById, which goes to
db.replicaNode(). Replication lag could return the pre-claim row with a null
key, so a recoverable race answered with a 500 instead of the winner's session
key.

Fold the claim into one primary-side statement that sets the secrets only when
the row has none and returns whichever key is stored afterwards, so the loser
adopts the winner's key with no follow-up read. A missing row is now a 404
rather than a 500, since the only way to get there is the session being deleted
concurrently.

Also drop the ticket references from the new comments, per the repo's comment
rules.
@bernie-g
bernie-g requested a review from lb-vn September 8, 2026 19:12
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.

1 participant