Migrate from xlsx to exceljs to fix security vulnerabilities

- Replace xlsx package (v0.18.5) with exceljs (v4.4.0)
- Remove @types/xlsx dependency (exceljs has built-in TypeScript types)
- Update biaMatchingService.ts to use ExcelJS API:
  - Replace XLSX.read() with workbook.xlsx.load()
  - Replace XLSX.utils.sheet_to_json() with eachRow() iteration
  - Handle 1-based column indexing correctly
- Make loadBIAData() and findBIAMatch() async functions
- Update all callers in applications.ts and claude.ts to use await
- Fix npm audit: 0 vulnerabilities (was 1 high severity)

This migration eliminates the Prototype Pollution and ReDoS vulnerabilities
in the xlsx package while maintaining full functionality.
This commit is contained in:
2026-01-15 09:59:43 +01:00
parent c60fbe8821
commit e276e77fbc
5 changed files with 852 additions and 145 deletions

View File

@@ -103,7 +103,7 @@ router.get('/bia-test', async (req: Request, res: Response) => {
if (getQueryString(req, 'clear') === 'true') {
clearBIACache();
}
const biaData = loadBIAData();
const biaData = await loadBIAData();
res.json({
recordCount: biaData.length,
records: biaData.slice(0, 20), // First 20 records
@@ -119,7 +119,7 @@ router.get('/bia-test', async (req: Request, res: Response) => {
router.get('/bia-debug', async (req: Request, res: Response) => {
try {
clearBIACache();
const biaData = loadBIAData();
const biaData = await loadBIAData();
// Get a few sample applications
const searchResult = await dataService.searchApplications({}, 1, 50);
@@ -138,7 +138,7 @@ router.get('/bia-debug', async (req: Request, res: Response) => {
// Test each sample app
for (const app of [...sampleApps, ...testApps]) {
const matchResult = findBIAMatch(app.name, app.searchReference ?? null);
const matchResult = await findBIAMatch(app.name, app.searchReference ?? null);
// Find all potential matches in Excel data for detailed analysis
const normalizedAppName = app.name.toLowerCase().trim();
@@ -207,7 +207,7 @@ router.get('/bia-comparison', async (req: Request, res: Response) => {
clearBIACache();
// Load fresh data
const testBIAData = loadBIAData();
const testBIAData = await loadBIAData();
logger.info(`BIA comparison: Loaded ${testBIAData.length} records from Excel file`);
if (testBIAData.length === 0) {
logger.error('BIA comparison: No Excel data loaded - check if BIA.xlsx exists and is readable');
@@ -251,7 +251,7 @@ router.get('/bia-comparison', async (req: Request, res: Response) => {
for (const app of applications) {
// Find BIA match in Excel
const matchResult = findBIAMatch(app.name, app.searchReference ?? null);
const matchResult = await findBIAMatch(app.name, app.searchReference ?? null);
// Log first few matches for debugging
if (comparisonItems.length < 5) {