🔒 Added escaping to member export CSV fields

fix https://linear.app/tryghost/issue/ENG-805/
refs https://owasp.org/www-community/attacks/CSV_Injection

- it's possible for certain fields in a member CSV export to be executed
  by software that opens the CSVs
- we can protect against this for the user by escaping any forumulae in
  the CSV fields
- papaparse provides this option natively, so it's just a case of
  providing the field to the unparse method
- credits to Harvey Spec (phulelouch) for reporting
This commit is contained in:
Daniel Lockyer 2024-04-02 09:44:06 +02:00 committed by Daniel Lockyer
parent a732164d54
commit de668e7950
2 changed files with 29 additions and 0 deletions

View File

@ -61,6 +61,7 @@ const unparse = (rows, columns = DEFAULT_COLUMNS.slice()) => {
}); });
return papaparse.unparse(mappedRows, { return papaparse.unparse(mappedRows, {
escapeFormulae: true,
columns columns
}); });
}; };

View File

@ -103,4 +103,32 @@ third-member-email@email.com,"banana, avocado"`;
const expected = `email,tiers\r\nmember-email@email.com,Bronze Level`; const expected = `email,tiers\r\nmember-email@email.com,Bronze Level`;
assert.equal(result, expected); assert.equal(result, expected);
}); });
it('escapes fields starting with CSV injection characters', async function () {
const json = [{
email: 'email@example.com',
name: '=1+2',
note: 'Early supporter'
}];
const result = unparse(json);
assert.ok(result);
const expected = `id,email,name,note,subscribed_to_emails,complimentary_plan,stripe_customer_id,created_at,deleted_at,labels,tiers\r\n,email@example.com,"'=1+2",Early supporter,,,,,,,`;
assert.equal(result, expected);
});
it('escapes fields with CSV injection characters and quotes', async function () {
const json = [{
email: 'email@example.com',
name: `=1+2'" `,
note: 'Early supporter'
}];
const result = unparse(json);
assert.ok(result);
const expected = `id,email,name,note,subscribed_to_emails,complimentary_plan,stripe_customer_id,created_at,deleted_at,labels,tiers\r\n,email@example.com,"'=1+2'"" ",Early supporter,,,,,,,`;
assert.equal(result, expected);
});
}); });