From 9a254ba1fa0315e90e0cb2eed5038eaf418a19cd Mon Sep 17 00:00:00 2001 From: "Adam Perry @ OpenAI" Date: Tue, 18 Aug 2026 05:15:44 +0000 Subject: [PATCH] Redact auth tokens from app-server response logs (#39141) ## Why App-server response diagnostics can include access tokens returned by the ChatGPT auth refresh flow. ## What changed - Log successfully parsed server responses instead of raw JSON-RPC response payloads. - Redact `access_token` from the `Debug` representation of `ChatgptAuthTokensRefreshResponse`. - Avoid formatting callback send errors that can retain the original response payload. GitOrigin-RevId: fd47485b38ed89527b25937c759b3273581f6ae6 --- .../src/protocol/v2/account.rs | 13 ++++++++++++- codex-rs/app-server/src/message_processor.rs | 1 - codex-rs/app-server/src/outgoing_message.rs | 15 ++++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/codex-rs/app-server-protocol/src/protocol/v2/account.rs b/codex-rs/app-server-protocol/src/protocol/v2/account.rs index d42abf1de5..bbc7959674 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/account.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/account.rs @@ -13,6 +13,7 @@ use codex_protocol::protocol::SpendControlLimitSnapshot as CoreSpendControlLimit use serde::Deserialize; use serde::Serialize; use std::collections::HashMap; +use std::fmt; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(tag = "type", rename_all = "camelCase")] @@ -277,7 +278,7 @@ pub struct ChatgptAuthTokensRefreshParams { pub previous_account_id: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] pub struct ChatgptAuthTokensRefreshResponse { @@ -286,6 +287,16 @@ pub struct ChatgptAuthTokensRefreshResponse { pub chatgpt_plan_type: Option, } +impl fmt::Debug for ChatgptAuthTokensRefreshResponse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ChatgptAuthTokensRefreshResponse") + .field("access_token", &"") + .field("chatgpt_account_id", &self.chatgpt_account_id) + .field("chatgpt_plan_type", &self.chatgpt_plan_type) + .finish() + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index 74fdbcfdf4..e6d82f010a 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -815,7 +815,6 @@ impl MessageProcessor { /// Handle a standalone JSON-RPC response originating from the peer. pub(crate) async fn process_response(&self, response: JSONRPCResponse) { - tracing::info!("<- response: {:?}", response); let JSONRPCResponse { id, result, .. } = response; self.outgoing.notify_client_response(id, result).await } diff --git a/codex-rs/app-server/src/outgoing_message.rs b/codex-rs/app-server/src/outgoing_message.rs index d0dc22a12a..262c674ae6 100644 --- a/codex-rs/app-server/src/outgoing_message.rs +++ b/codex-rs/app-server/src/outgoing_message.rs @@ -386,14 +386,15 @@ impl OutgoingMessageSender { match entry { Some((id, entry)) => { let completed_at_ms = now_unix_timestamp_ms(); - if let Ok(response) = entry.request.response_from_result(result.clone()) - && !matches!(response, ServerResponse::PermissionsRequestApproval { .. }) - { - self.analytics_events_client - .track_server_response(completed_at_ms, response); + if let Ok(response) = entry.request.response_from_result(result.clone()) { + tracing::info!("<- response: {response:?}"); + if !matches!(response, ServerResponse::PermissionsRequestApproval { .. }) { + self.analytics_events_client + .track_server_response(completed_at_ms, response); + } } - if let Err(err) = entry.callback.send(Ok(result)) { - warn!("could not notify callback for {id:?} due to: {err:?}"); + if entry.callback.send(Ok(result)).is_err() { + warn!("could not notify callback for {id:?}: receiver dropped"); } } None => {