ESLint Plugin No Unsanitized is a security-focused ESLint plugin designed to detect and prevent unsafe coding practices that could lead to security vulnerabilities. It provides comprehensive rules to disallow unsanitized code patterns, specifically targeting dangerous assignments to DOM properties and unsafe method calls that can introduce XSS vulnerabilities.
npm install --save-dev eslint-plugin-no-unsanitizedimport nounsanitized from "eslint-plugin-no-unsanitized";For CommonJS:
const nounsanitized = require("eslint-plugin-no-unsanitized");import nounsanitized from "eslint-plugin-no-unsanitized";
export default [nounsanitized.configs.recommended];Or with custom configuration:
import nounsanitized from "eslint-plugin-no-unsanitized";
export default [
{
files: ["**/*.js"],
plugins: { "no-unsanitized": nounsanitized },
rules: {
"no-unsanitized/method": "error",
"no-unsanitized/property": "error",
},
},
];{
"extends": ["plugin:no-unsanitized/recommended-legacy"]
}Or with custom configuration:
{
"plugins": ["no-unsanitized"],
"rules": {
"no-unsanitized/method": "error",
"no-unsanitized/property": "error"
}
}The plugin is built around several key components:
Prevents unsafe assignment to DOM properties like innerHTML and outerHTML that can lead to XSS vulnerabilities.
// Plugin exports
const plugin = {
rules: {
property: PropertyRule
}
};
// Rule configuration schema
interface PropertyRuleOptions {
escape?: {
taggedTemplates?: string[];
methods?: string[];
};
variableTracing?: boolean;
}Prevents unsafe method calls like document.write(), insertAdjacentHTML(), and dynamic import() that can introduce security vulnerabilities.
// Plugin exports
const plugin = {
rules: {
method: MethodRule
}
};
// Rule configuration schema
interface MethodRuleOptions {
defaultDisable?: boolean;
escape?: {
taggedTemplates?: string[];
methods?: string[];
};
objectMatches?: string[];
properties?: number[];
variableTracing?: boolean;
}Pre-configured rule sets and plugin metadata for easy ESLint integration.
interface ESLintPlugin {
meta: {
name: string;
version: string;
};
rules: {
property: ESLintRule;
method: ESLintRule;
};
configs: {
recommended: ESLintConfig;
"recommended-legacy": ESLintConfig;
DOM: ESLintConfig; // deprecated
};
}
interface ESLintConfig {
plugins: string[] | Record<string, ESLintPlugin>;
rules: Record<string, string | [string, any]>;
}Core validation logic shared between rules, providing expression analysis, variable tracing, and security validation functionality.
// Rule Helper instance creation
const ruleHelper = new RuleHelper(context: ESLintRuleContext, defaultRuleChecks: object);
// Core validation methods
interface RuleHelper {
allowedExpression(expression: any, escapeObject: EscapeConfiguration, details: ValidationDetails): boolean;
isAllowedIdentifier(expression: IdentifierNode, escapeObject: EscapeConfiguration, details: ValidationDetails): boolean;
checkMethod(node: CallExpressionNode): void;
checkProperty(node: AssignmentExpressionNode): void;
}// Core rule function type
interface ESLintRule {
meta: {
type: "problem" | "suggestion" | "layout";
docs: {
description: string;
category: string;
url: string;
};
schema: JSONSchema[];
};
create(context: ESLintRuleContext): ESLintRuleVisitor;
}
interface ESLintRuleContext {
options: any[];
sourceCode?: {
getScope(node: any): Scope;
getText(node: any): string;
};
getScope?(node: any): Scope;
report(node: any, message: string): void;
}
interface ESLintRuleVisitor {
[key: string]: (node: any) => void;
}
// Security validation types
interface EscapeConfiguration {
taggedTemplates?: string[];
methods?: string[];
}
interface RuleCheck {
properties?: number[];
objectMatches?: string[];
escape?: EscapeConfiguration;
}
// AST Node types for method calls
interface CallExpressionNode {
type: "CallExpression";
callee: any;
arguments: any[];
}
interface ImportExpressionNode {
type: "ImportExpression";
source: any;
}
interface AssignmentExpressionNode {
type: "AssignmentExpression";
left: {
property: {
name: string;
};
};
right: any;
operator: string;
}
interface IdentifierNode {
type: "Identifier";
name: string;
}
// Validation details for error reporting
interface ValidationDetails {
message?: string;
}