11// Diagnostics Report webview with tabbed interface
2+
3+ // Ensure numeric values derived from untrusted input are rendered safely as plain text
4+ function sanitizeNumber ( value : unknown ) : string {
5+ const num = Number ( value ) ;
6+ if ( Number . isNaN ( num ) || ! Number . isFinite ( num ) ) {
7+ return '0' ;
8+ }
9+ return String ( num ) ;
10+ }
11+
212type ContextReferenceUsage = {
313 file : number ;
414 selection : number ;
@@ -191,8 +201,8 @@ function renderSessionTable(detailedFiles: SessionFileDetails[], isLoading: bool
191201 : detailedFiles ;
192202
193203 // Summary stats for filtered files
194- const totalInteractions = filteredFiles . reduce ( ( sum , sf ) => sum + sf . interactions , 0 ) ;
195- const totalContextRefs = filteredFiles . reduce ( ( sum , sf ) => sum + getTotalContextRefs ( sf . contextReferences ) , 0 ) ;
204+ const totalInteractions = filteredFiles . reduce ( ( sum , sf ) => sum + Number ( sf . interactions || 0 ) , 0 ) ;
205+ const totalContextRefs = filteredFiles . reduce ( ( sum , sf ) => sum + Number ( getTotalContextRefs ( sf . contextReferences ) || 0 ) , 0 ) ;
196206
197207 // Sort filtered files
198208 const sortedFiles = sortSessionFiles ( filteredFiles ) ;
@@ -203,13 +213,13 @@ function renderSessionTable(detailedFiles: SessionFileDetails[], isLoading: bool
203213 <div class="editor-panel ${ currentEditorFilter === null ? 'active' : '' } " data-editor="">
204214 <div class="editor-panel-icon">🌐</div>
205215 <div class="editor-panel-name">All Editors</div>
206- <div class="editor-panel-stats">${ detailedFiles . length } sessions</div>
216+ <div class="editor-panel-stats">${ sanitizeNumber ( detailedFiles . length ) } sessions</div>
207217 </div>
208218 ${ editors . map ( editor => `
209219 <div class="editor-panel ${ currentEditorFilter === editor ? 'active' : '' } " data-editor="${ escapeHtml ( editor ) } ">
210220 <div class="editor-panel-icon">${ getEditorIcon ( editor ) } </div>
211221 <div class="editor-panel-name">${ escapeHtml ( editor ) } </div>
212- <div class="editor-panel-stats">${ editorStats [ editor ] . count } sessions · ${ editorStats [ editor ] . interactions } interactions</div>
222+ <div class="editor-panel-stats">${ sanitizeNumber ( editorStats [ editor ] . count ) } sessions · ${ sanitizeNumber ( editorStats [ editor ] . interactions ) } interactions</div>
213223 </div>
214224 ` ) . join ( '' ) }
215225 </div>
@@ -221,15 +231,15 @@ function renderSessionTable(detailedFiles: SessionFileDetails[], isLoading: bool
221231 <div class="summary-cards">
222232 <div class="summary-card">
223233 <div class="summary-label">📁 ${ currentEditorFilter ? 'Filtered' : 'Total' } Sessions</div>
224- <div class="summary-value">${ filteredFiles . length } </div>
234+ <div class="summary-value">${ sanitizeNumber ( filteredFiles . length ) } </div>
225235 </div>
226236 <div class="summary-card">
227237 <div class="summary-label">💬 Interactions</div>
228- <div class="summary-value">${ totalInteractions } </div>
238+ <div class="summary-value">${ sanitizeNumber ( totalInteractions ) } </div>
229239 </div>
230240 <div class="summary-card">
231241 <div class="summary-label">🔗 Context References</div>
232- <div class="summary-value">${ totalContextRefs } </div>
242+ <div class="summary-value">${ sanitizeNumber ( totalContextRefs ) } </div>
233243 </div>
234244 <div class="summary-card">
235245 <div class="summary-label">📅 Time Range</div>
0 commit comments