Skip to main content

CSV injection

Need

Prevention of CSV injection attacks

Context

  • Usage of TypeScript for type-checking and compiling JavaScript code
  • Usage of Express for building web applications and handling HTTP requests
  • Usage of csv-writer for writing data to CSV files

Description

Non compliant code

import express from 'express';
import csv from 'csv-writer';

const app = express();

app.get('/export', (req, res) => {
const data = [
{ name: 'John Doe', email: '=SUM(1+2)' },
{ name: 'Jane Smith', email: '[email protected]' },
];

const csvWriter = csv.createObjectCsvWriter({
path: 'export.csv',
header: [
{ id: 'name', title: 'Name' },
{ id: 'email', title: 'Email' },
],
});

csvWriter.writeRecords(data)
.then(() => {
res.download('export.csv');
})
.catch((err) => {
res.status(500).send('Error exporting CSV');
});
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

The vulnerability in this code is a CSV injection.

In the data array, there is a field called email that contains the value '=SUM(1+2)'. When this data is written to the CSV file using the csvWriter.writeRecords(data) function, the value '=SUM(1+2)' is written as is, without any sanitization or validation.

CSV files can be opened in spreadsheet applications like Excel, and when a cell in a CSV file starts with an equal sign (=), Excel interprets it as a formula. In this case, the injected formula =SUM(1+2) would be executed by Excel, resulting in the value 3 being displayed in the corresponding cell.

This vulnerability allows an attacker to inject malicious formulas into the exported CSV file. Depending on the capabilities of the formula language, an attacker could potentially execute arbitrary code, access sensitive data, or perform other malicious actions.

To mitigate this vulnerability, all fields that will be exported to the CSV file should be properly sanitized or escaped to prevent any unintended interpretation as formulas by spreadsheet applications.

Steps

  • Sanitize the 'email' field before writing it to the CSV file. Remove any special characters or formulas that could be interpreted by Excel.
  • Use a library or function to sanitize the 'email' field, such as the 'sanitize-html' library or a custom sanitization function.
  • Update the code to use the sanitized value for the 'email' field when writing records to the CSV file.
  • Test the updated code to ensure that the 'email' field is properly sanitized and does not contain any malicious formulas.

Compliant code

import express from 'express';
import csv from 'csv-writer';
import sanitizeHtml from 'sanitize-html';

const app = express();

app.get('/export', (req, res) => {
const data = [
{ name: 'John Doe', email: '=SUM(1+2)' },
{ name: 'Jane Smith', email: '[email protected]' },
];

const sanitizedData = data.map((record) => {
return {
name: record.name,
email: sanitizeHtml(record.email),
};
});

const csvWriter = csv.createObjectCsvWriter({
path: 'export.csv',
header: [
{ id: 'name', title: 'Name' },
{ id: 'email', title: 'Email' },
],
});

csvWriter.writeRecords(sanitizedData)
.then(() => {
res.download('export.csv');
})
.catch((err) => {
res.status(500).send('Error exporting CSV');
});
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

The fixed code addresses the vulnerability by sanitizing the data before exporting it to a CSV file. Here's how it works:

  1. The code imports the necessary modules: express for creating the server, csv-writer for generating the CSV file, and sanitize-html for sanitizing the data.

  2. The code defines an Express route handler for the /export endpoint.

  3. Inside the route handler, an array of data objects is created. Each object represents a record with a name and an email field. The email field contains a potentially malicious formula (=SUM(1+2)).

  4. The sanitizedData array is created by mapping over the original data array. For each record, the sanitizeHtml function is used to sanitize the email field, removing any potentially harmful HTML or formulas.

  5. The csvWriter object is created using createObjectCsvWriter from the csv-writer module. It specifies the file path and the headers for the CSV file.

  6. The writeRecords method of csvWriter is called with the sanitized data array. This writes the records to the CSV file.

  7. If the writing process is successful, the server responds with the CSV file for download using the res.download method.

  8. If any error occurs during the writing process, the server responds with a 500 status code and an error message.

  9. Finally, the server starts listening on port 3000.

By using the sanitizeHtml function to sanitize the email field before exporting it to the CSV file, the code prevents any potentially malicious formulas from being injected and executed when the CSV file is opened in Excel.

References