diff --git a/ghost/members-csv/lib/unparse.js b/ghost/members-csv/lib/unparse.js index 5cf4f1f046..983cff741f 100644 --- a/ghost/members-csv/lib/unparse.js +++ b/ghost/members-csv/lib/unparse.js @@ -61,6 +61,7 @@ const unparse = (rows, columns = DEFAULT_COLUMNS.slice()) => { }); return papaparse.unparse(mappedRows, { + escapeFormulae: true, columns }); }; diff --git a/ghost/members-csv/test/unparse.test.js b/ghost/members-csv/test/unparse.test.js index f139f10998..e04352d951 100644 --- a/ghost/members-csv/test/unparse.test.js +++ b/ghost/members-csv/test/unparse.test.js @@ -103,4 +103,32 @@ third-member-email@email.com,"banana, avocado"`; const expected = `email,tiers\r\nmember-email@email.com,Bronze Level`; 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); + }); });