11// Diagnostics Report webview with tabbed interface
22import { buttonHtml } from '../shared/buttonConfig' ;
33
4+ // Ensure numeric values derived from untrusted input are rendered safely as plain text
5+ function sanitizeNumber ( value : unknown ) : string {
6+ const num = Number ( value ) ;
7+ if ( Number . isNaN ( num ) || ! Number . isFinite ( num ) ) {
8+ return '0' ;
9+ }
10+ return String ( num ) ;
11+ }
12+
413type ContextReferenceUsage = {
514 file : number ;
615 selection : number ;
@@ -193,8 +202,8 @@ function renderSessionTable(detailedFiles: SessionFileDetails[], isLoading: bool
193202 : detailedFiles ;
194203
195204 // Summary stats for filtered files
196- const totalInteractions = filteredFiles . reduce ( ( sum , sf ) => sum + sf . interactions , 0 ) ;
197- const totalContextRefs = filteredFiles . reduce ( ( sum , sf ) => sum + getTotalContextRefs ( sf . contextReferences ) , 0 ) ;
205+ const totalInteractions = filteredFiles . reduce ( ( sum , sf ) => sum + Number ( sf . interactions || 0 ) , 0 ) ;
206+ const totalContextRefs = filteredFiles . reduce ( ( sum , sf ) => sum + Number ( getTotalContextRefs ( sf . contextReferences ) || 0 ) , 0 ) ;
198207
199208 // Sort filtered files
200209 const sortedFiles = sortSessionFiles ( filteredFiles ) ;
@@ -205,13 +214,13 @@ function renderSessionTable(detailedFiles: SessionFileDetails[], isLoading: bool
205214 <div class="editor-panel ${ currentEditorFilter === null ? 'active' : '' } " data-editor="">
206215 <div class="editor-panel-icon">🌐</div>
207216 <div class="editor-panel-name">All Editors</div>
208- <div class="editor-panel-stats">${ detailedFiles . length } sessions</div>
217+ <div class="editor-panel-stats">${ sanitizeNumber ( detailedFiles . length ) } sessions</div>
209218 </div>
210219 ${ editors . map ( editor => `
211220 <div class="editor-panel ${ currentEditorFilter === editor ? 'active' : '' } " data-editor="${ escapeHtml ( editor ) } ">
212221 <div class="editor-panel-icon">${ getEditorIcon ( editor ) } </div>
213222 <div class="editor-panel-name">${ escapeHtml ( editor ) } </div>
214- <div class="editor-panel-stats">${ editorStats [ editor ] . count } sessions · ${ editorStats [ editor ] . interactions } interactions</div>
223+ <div class="editor-panel-stats">${ sanitizeNumber ( editorStats [ editor ] . count ) } sessions · ${ sanitizeNumber ( editorStats [ editor ] . interactions ) } interactions</div>
215224 </div>
216225 ` ) . join ( '' ) }
217226 </div>
@@ -223,15 +232,15 @@ function renderSessionTable(detailedFiles: SessionFileDetails[], isLoading: bool
223232 <div class="summary-cards">
224233 <div class="summary-card">
225234 <div class="summary-label">📁 ${ currentEditorFilter ? 'Filtered' : 'Total' } Sessions</div>
226- <div class="summary-value">${ filteredFiles . length } </div>
235+ <div class="summary-value">${ sanitizeNumber ( filteredFiles . length ) } </div>
227236 </div>
228237 <div class="summary-card">
229238 <div class="summary-label">💬 Interactions</div>
230- <div class="summary-value">${ totalInteractions } </div>
239+ <div class="summary-value">${ sanitizeNumber ( totalInteractions ) } </div>
231240 </div>
232241 <div class="summary-card">
233242 <div class="summary-label">🔗 Context References</div>
234- <div class="summary-value">${ totalContextRefs } </div>
243+ <div class="summary-value">${ sanitizeNumber ( totalContextRefs ) } </div>
235244 </div>
236245 <div class="summary-card">
237246 <div class="summary-label">📅 Time Range</div>
0 commit comments