diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx index ea780add2..acbb30ff2 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/copilot-message.tsx @@ -78,6 +78,7 @@ const CopilotMessage: FC = memo( mode, setMode, isAborting, + maskCredentialValue, } = useCopilotStore() const messageCheckpoints = isUser ? allMessageCheckpoints[message.id] || [] : [] @@ -210,7 +211,10 @@ const CopilotMessage: FC = memo( const isLastTextBlock = index === message.contentBlocks!.length - 1 && block.type === 'text' const parsed = parseSpecialTags(block.content) - const cleanBlockContent = parsed.cleanContent.replace(/\n{3,}/g, '\n\n') + // Mask credential IDs in the displayed content + const cleanBlockContent = maskCredentialValue( + parsed.cleanContent.replace(/\n{3,}/g, '\n\n') + ) if (!cleanBlockContent.trim()) return null @@ -238,7 +242,7 @@ const CopilotMessage: FC = memo( return (
= memo( } return null }) - }, [message.contentBlocks, isActivelyStreaming, parsedTags, isLastMessage]) + }, [message.contentBlocks, isActivelyStreaming, parsedTags, isLastMessage, maskCredentialValue]) if (isUser) { return ( diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx index fd601b7ea..c97025aee 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/tool-call/tool-call.tsx @@ -782,6 +782,7 @@ const SubagentContentRenderer = memo(function SubagentContentRenderer({ const [isExpanded, setIsExpanded] = useState(true) const [duration, setDuration] = useState(0) const startTimeRef = useRef(Date.now()) + const maskCredentialValue = useCopilotStore((s) => s.maskCredentialValue) const wasStreamingRef = useRef(false) // Only show streaming animations for current message @@ -816,14 +817,16 @@ const SubagentContentRenderer = memo(function SubagentContentRenderer({ currentText += parsed.cleanContent } else if (block.type === 'subagent_tool_call' && block.toolCall) { if (currentText.trim()) { - segments.push({ type: 'text', content: currentText }) + // Mask any credential IDs in the accumulated text before displaying + segments.push({ type: 'text', content: maskCredentialValue(currentText) }) currentText = '' } segments.push({ type: 'tool', block }) } } if (currentText.trim()) { - segments.push({ type: 'text', content: currentText }) + // Mask any credential IDs in the accumulated text before displaying + segments.push({ type: 'text', content: maskCredentialValue(currentText) }) } const allParsed = parseSpecialTags(allRawText) @@ -952,6 +955,7 @@ const WorkflowEditSummary = memo(function WorkflowEditSummary({ toolCall: CopilotToolCall }) { const blocks = useWorkflowStore((s) => s.blocks) + const maskCredentialValue = useCopilotStore((s) => s.maskCredentialValue) const cachedBlockInfoRef = useRef>({}) @@ -983,6 +987,7 @@ const WorkflowEditSummary = memo(function WorkflowEditSummary({ title: string value: any isPassword?: boolean + isCredential?: boolean } interface BlockChange { @@ -1091,6 +1096,7 @@ const WorkflowEditSummary = memo(function WorkflowEditSummary({ title: subBlockConfig.title ?? subBlockConfig.id, value, isPassword: subBlockConfig.password === true, + isCredential: subBlockConfig.type === 'oauth-input', }) } } @@ -1172,8 +1178,15 @@ const WorkflowEditSummary = memo(function WorkflowEditSummary({ {subBlocksToShow && subBlocksToShow.length > 0 && (
{subBlocksToShow.map((sb) => { - // Mask password fields like the canvas does - const displayValue = sb.isPassword ? '•••' : getDisplayValue(sb.value) + // Mask password fields and credential IDs + let displayValue: string + if (sb.isPassword) { + displayValue = '•••' + } else { + // Get display value first, then mask any credential IDs that might be in it + const rawValue = getDisplayValue(sb.value) + displayValue = maskCredentialValue(rawValue) + } return (