eslint-plugin-security
Version:
Security rules for eslint
100 lines (88 loc) • 2.98 kB
JavaScript
/**
* Detect invisible characters that can be used to hide malicious code from reviewers
* @author electrohyun
*/
;
const invisibleCharsRegexp = /[\u3164\uFFA0]/gu;
/**
* Detects all the invisible characters in a given source text
*
* @param {object} options - Options
* @param {string} options.sourceText - The source text to search for invisible characters
* @param {number} options.firstLineOffset - The offset of the first line in the source text
* @returns {Array<{line: number, column: number}>} - An array of reports, each report is an
* object with the line and column of the invisible character
*/
function detectInvisibleCharacters({ sourceText, firstLineOffset }) {
const sourceTextToSearch = sourceText.toString();
const lines = sourceTextToSearch.split(/\r\n|[\r\n\u2028\u2029]/);
return lines.reduce((reports, line, lineIndex) => {
let match;
let offset = lineIndex == 0 ? firstLineOffset : 0;
while ((match = invisibleCharsRegexp.exec(line)) !== null) {
reports.push({ line: lineIndex, column: offset + match.index });
}
return reports;
}, []);
}
function report({ context, node, tokens, message, firstLineOffset }) {
if (!tokens || !Array.isArray(tokens)) {
return;
}
tokens.forEach((token) => {
const reports = detectInvisibleCharacters({ sourceText: token.value, firstLineOffset: token.loc.start.column + firstLineOffset });
reports.forEach((report) => {
context.report({
node: node,
data: {
text: token.value,
},
loc: {
start: {
line: token.loc.start.line + report.line,
column: report.column,
},
end: {
line: token.loc.start.line + report.line,
column: report.column + 1,
},
},
message,
});
});
});
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'Detects invisible characters that have no visible glyph and can be used to hide malicious code.',
category: 'Possible Security Vulnerability',
recommended: true,
url: 'https://github.com/eslint-community/eslint-plugin-security/blob/main/docs/rules/detect-invisible-characters.md',
},
},
create(context) {
return {
Program: function (node) {
report({
context,
node,
tokens: node.tokens,
firstLineOffset: 0,
message: "Detected an invisible character introduced in this code: '{{text}}'.",
});
report({
context,
node,
tokens: node.comments,
firstLineOffset: 2,
message: "Detected an invisible character introduced in this comment: '{{text}}'.",
});
},
};
},
};