@@ -458,10 +458,34 @@ function sanitizeStats(raw: any): UsageAnalysisStats | null {
458458 : undefined ,
459459 } ;
460460
461- // Validated pass-through for customizationMatrix ( nested shape check )
461+ // Sanitize customizationMatrix (avoid pass-through of untrusted nested fields )
462462 if ( raw . customizationMatrix && typeof raw . customizationMatrix === 'object'
463463 && Array . isArray ( raw . customizationMatrix . workspaces ) ) {
464- sanitized . customizationMatrix = raw . customizationMatrix as WorkspaceCustomizationMatrix ;
464+ const rawMatrix = raw . customizationMatrix as any ;
465+ const safeWorkspaces = rawMatrix . workspaces
466+ . filter ( ( w : any ) => w && typeof w === 'object' )
467+ . map ( ( w : any ) => ( {
468+ workspacePath : typeof w . workspacePath === 'string' ? w . workspacePath : '' ,
469+ repoName : typeof w . repoName === 'string' ? w . repoName : '' ,
470+ hasCopilotInstructionsMd : ! ! w . hasCopilotInstructionsMd ,
471+ hasAgentsMd : ! ! w . hasAgentsMd ,
472+ hasCopilotSetupStepsMd : ! ! w . hasCopilotSetupStepsMd ,
473+ hasCustomChatmodes : ! ! w . hasCustomChatmodes ,
474+ hasCustomPrompts : ! ! w . hasCustomPrompts ,
475+ totalFiles : coerceNumber ( w . totalFiles ) ,
476+ missingTypes : Array . isArray ( w . missingTypes )
477+ ? w . missingTypes . filter ( ( t : unknown ) => typeof t === 'string' )
478+ : [ ] ,
479+ extraTypes : Array . isArray ( w . extraTypes )
480+ ? w . extraTypes . filter ( ( t : unknown ) => typeof t === 'string' )
481+ : [ ] ,
482+ } ) ) ;
483+
484+ sanitized . customizationMatrix = {
485+ workspaces : safeWorkspaces ,
486+ totalWorkspaces : coerceNumber ( rawMatrix . totalWorkspaces ) ,
487+ workspacesWithIssues : coerceNumber ( rawMatrix . workspacesWithIssues ) ,
488+ } as WorkspaceCustomizationMatrix ;
465489 }
466490
467491 // Validated pass-through for missedPotential (array of objects)
0 commit comments