@lipemat/eslint-config 5.0.1 → 5.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/helpers/config.js +1 -0
- package/helpers/config.js.map +1 -0
- package/{types/helpers/config.d.ts → helpers/config.ts} +16 -5
- package/index.js +1 -0
- package/package.json +8 -11
- package/plugins/security/helpers/dom-purify.js +1 -0
- package/plugins/security/helpers/dom-purify.js.map +1 -0
- package/plugins/security/helpers/dom-purify.ts +21 -0
- package/plugins/security/helpers/element.js +1 -0
- package/plugins/security/helpers/element.js.map +1 -0
- package/plugins/security/helpers/element.ts +22 -0
- package/plugins/security/helpers/string.js +1 -0
- package/plugins/security/helpers/string.js.map +1 -0
- package/plugins/security/helpers/string.ts +44 -0
- package/plugins/security/helpers/ts-types.js +1 -0
- package/plugins/security/helpers/ts-types.js.map +1 -0
- package/plugins/security/helpers/ts-types.ts +11 -0
- package/plugins/security/index.js +10 -0
- package/plugins/security/index.js.map +1 -0
- package/plugins/security/index.ts +74 -0
- package/plugins/security/package.json +25 -0
- package/plugins/security/rules/dangerously-set-inner-html.js +1 -0
- package/plugins/security/rules/dangerously-set-inner-html.js.map +1 -0
- package/plugins/security/rules/dangerously-set-inner-html.ts +93 -0
- package/plugins/security/rules/html-executing-assignment.js +1 -0
- package/plugins/security/rules/html-executing-assignment.js.map +1 -0
- package/plugins/security/rules/html-executing-assignment.ts +78 -0
- package/plugins/security/rules/html-executing-function.js +1 -0
- package/plugins/security/rules/html-executing-function.js.map +1 -0
- package/plugins/security/rules/html-executing-function.ts +164 -0
- package/plugins/security/rules/html-sinks.js +1 -0
- package/plugins/security/rules/html-sinks.js.map +1 -0
- package/plugins/security/rules/html-sinks.ts +146 -0
- package/plugins/security/rules/html-string-concat.js +1 -0
- package/plugins/security/rules/html-string-concat.js.map +1 -0
- package/plugins/security/rules/html-string-concat.ts +71 -0
- package/plugins/security/rules/jquery-executing.js +1 -0
- package/plugins/security/rules/jquery-executing.js.map +1 -0
- package/plugins/security/rules/jquery-executing.ts +134 -0
- package/plugins/security/rules/no-at-html-tags.js +53 -0
- package/plugins/security/rules/no-at-html-tags.js.map +1 -0
- package/plugins/security/rules/no-at-html-tags.ts +74 -0
- package/plugins/security/rules/vulnerable-tag-stripping.js +1 -0
- package/plugins/security/rules/vulnerable-tag-stripping.js.map +1 -0
- package/plugins/security/rules/vulnerable-tag-stripping.ts +89 -0
- package/plugins/security/rules/window-escaping.js +2 -1
- package/plugins/security/rules/window-escaping.js.map +1 -0
- package/plugins/security/rules/window-escaping.ts +220 -0
- package/plugins/tsconfig.json +8 -0
- package/types/index.d.ts +0 -3
- package/types/plugins/security/helpers/dom-purify.d.ts +0 -6
- package/types/plugins/security/helpers/element.d.ts +0 -10
- package/types/plugins/security/helpers/string.d.ts +0 -20
- package/types/plugins/security/helpers/ts-types.d.ts +0 -6
- package/types/plugins/security/index.d.ts +0 -8
- package/types/plugins/security/rules/dangerously-set-inner-html.d.ts +0 -4
- package/types/plugins/security/rules/html-executing-assignment.d.ts +0 -4
- package/types/plugins/security/rules/html-executing-function.d.ts +0 -6
- package/types/plugins/security/rules/html-sinks.d.ts +0 -4
- package/types/plugins/security/rules/html-string-concat.d.ts +0 -9
- package/types/plugins/security/rules/jquery-executing.d.ts +0 -17
- package/types/plugins/security/rules/vulnerable-tag-stripping.d.ts +0 -4
- package/types/plugins/security/rules/window-escaping.d.ts +0 -5
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {type TSESLint, type TSESTree} from '@typescript-eslint/utils';
|
|
2
|
+
import type {AST} from 'svelte-eslint-parser';
|
|
3
|
+
import {isSanitized} from '../helpers/dom-purify.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type MessageIds = 'dangerousHtml' | 'domPurify' | 'sanitize';
|
|
7
|
+
|
|
8
|
+
type RuleOptions = Exclude<TSESLint.ReportDescriptor<MessageIds>, 'node'> | {
|
|
9
|
+
node: AST.SvelteMustacheTag,
|
|
10
|
+
readonly messageId: MessageIds;
|
|
11
|
+
readonly suggest?: Readonly<TSESLint.ReportSuggestionArray<MessageIds>> | null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SvelteContext extends TSESLint.RuleContext<MessageIds, []> {
|
|
15
|
+
report( options: RuleOptions ): void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Module extends TSESLint.RuleModule<MessageIds> {
|
|
19
|
+
create( context: SvelteContext ): TSESLint.RuleListener;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const plugin: Module = {
|
|
23
|
+
defaultOptions: [],
|
|
24
|
+
meta: {
|
|
25
|
+
docs: {
|
|
26
|
+
description: 'disallow using `{@html}` to prevent XSS attack. Make sure it\'s properly escaped.',
|
|
27
|
+
},
|
|
28
|
+
schema: [],
|
|
29
|
+
messages: {
|
|
30
|
+
dangerousHtml: '`{@html}` can lead to XSS attack.',
|
|
31
|
+
|
|
32
|
+
// Suggestions
|
|
33
|
+
domPurify: 'Wrap the content with a `DOMPurify.sanitize()` call.',
|
|
34
|
+
sanitize: 'Wrap the content with a `sanitize()` call.',
|
|
35
|
+
},
|
|
36
|
+
hasSuggestions: true,
|
|
37
|
+
type: 'problem',
|
|
38
|
+
},
|
|
39
|
+
create( context: SvelteContext ) {
|
|
40
|
+
return {
|
|
41
|
+
'SvelteMustacheTag[kind=raw]'( node: AST.SvelteMustacheTag ) {
|
|
42
|
+
if ( isSanitized( node.expression ) ) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const expression: TSESTree.Node = node.expression as TSESTree.Node;
|
|
46
|
+
|
|
47
|
+
context.report( {
|
|
48
|
+
node,
|
|
49
|
+
messageId: 'dangerousHtml',
|
|
50
|
+
suggest: [
|
|
51
|
+
{
|
|
52
|
+
messageId: 'domPurify',
|
|
53
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
54
|
+
const argText = context.sourceCode.getText( expression );
|
|
55
|
+
// @ts-expect-error - TS2345: Not a node, but has all required Node properties.
|
|
56
|
+
return fixer.replaceText( node, `{@html DOMPurify.sanitize( ${argText} )}` );
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
messageId: 'sanitize',
|
|
61
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
62
|
+
const argText = context.sourceCode.getText( expression );
|
|
63
|
+
// @ts-expect-error - TS2345: Not a node, but has all required Node properties.
|
|
64
|
+
return fixer.replaceText( node, `{@html sanitize( ${argText} )}` );
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
} );
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export default plugin;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vulnerable-tag-stripping.js","sourceRoot":"","sources":["vulnerable-tag-stripping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAA+B,MAAM,0BAA0B,CAAC;AACtF,OAAO,EAAC,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAMnD;;;;;;GAMG;AACH,SAAS,eAAe,CAAE,IAA6B;IACtD,kCAAkC;IAClC,IAAK,cAAc,CAAC,gBAAgB,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAE,CAAE,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAE,EAAG,CAAC;QACpG,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAG,CAAC;QAC5C,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;IACtC,IAAK,cAAc,CAAC,cAAc,KAAK,UAAU,CAAC,IAAI,EAAG,CAAC;QACzD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAK,cAAc,CAAC,gBAAgB,KAAK,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,CAAE,CAAE,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAE,EAAG,CAAC;QAChH,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAK,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,EAAG,CAAC;QAClD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,YAAY,CAAE,UAAU,CAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC9D,CAAC;AAGD,MAAM,MAAM,GAAkC;IAC7C,cAAc,EAAE,EAAE;IAClB,IAAI,EAAE;QACL,IAAI,EAAE;YACL,WAAW,EAAE,qFAAqF;SAClG;QACD,cAAc,EAAE,IAAI;QACpB,QAAQ,EAAE;YACT,sBAAsB,EAAE,8FAA8F;YACtH,WAAW,EAAE,iDAAiD;SAC9D;QACD,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,SAAS;KACf;IACD,MAAM,CAAE,OAAgB;QACvB,OAAO;YACN,cAAc,CAAE,IAA6B;gBAC5C,MAAM,YAAY,GAAG,eAAe,CAAE,IAAI,CAAE,CAAC;gBAC7C,IAAK,IAAI,KAAK,YAAY,EAAG,CAAC;oBAC7B,OAAO;gBACR,CAAC;gBACD,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,CAAC;gBAC3C,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC;gBACvC,IAAK,cAAc,CAAC,cAAc,KAAK,UAAU,CAAC,IAAI,EAAG,CAAC;oBACzD,OAAO;gBACR,CAAC;gBACD,MAAM,OAAO,GAAG,UAAU,CAAC,SAAS,CAAE,CAAC,CAAE,CAAC;gBAE1C,OAAO,CAAC,MAAM,CAAE;oBACf,IAAI;oBACJ,SAAS,EAAE,wBAAwB;oBACnC,OAAO,EAAE;wBACR;4BACC,SAAS,EAAE,aAAa;4BACxB,GAAG,EAAE,CAAE,KAAyB,EAAG,EAAE;gCACpC,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAE,cAAc,CAAE,CAAC;gCAClE,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAE,OAAO,CAAE,CAAC;gCACtD,OAAO,KAAK,CAAC,WAAW,CAAE,IAAI,EAAE,GAAG,YAAY,UAAU,OAAO,IAAI,CAAE,CAAC;4BACxE,CAAC;yBACD;qBACD;iBACD,CAAE,CAAC;YACL,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import {AST_NODE_TYPES, type TSESLint, type TSESTree} from '@typescript-eslint/utils';
|
|
2
|
+
import {isJQueryCall} from './jquery-executing.js';
|
|
3
|
+
|
|
4
|
+
type Messages = 'vulnerableTagStripping' | 'useTextOnly';
|
|
5
|
+
type Context = TSESLint.RuleContext<Messages, []>;
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Detects a vulnerable tag stripping pattern: .html(value).text()
|
|
10
|
+
*
|
|
11
|
+
* This pattern can lead to XSS vulnerabilities when HTML is inserted and then text is extracted.
|
|
12
|
+
*
|
|
13
|
+
* @link https://docs.wpvip.com/security/javascript-security-recommendations/#h-stripping-tags
|
|
14
|
+
*/
|
|
15
|
+
function isTextAfterHtml( node: TSESTree.CallExpression ): TSESTree.MemberExpression | null {
|
|
16
|
+
// Check if this is a .text() call
|
|
17
|
+
if ( AST_NODE_TYPES.MemberExpression !== node.callee.type || ! ( 'name' in node.callee.property ) ) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if ( node.callee.property.name !== 'text' ) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const parentCall = node.callee.object;
|
|
26
|
+
if ( AST_NODE_TYPES.CallExpression !== parentCall.type ) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if ( AST_NODE_TYPES.MemberExpression !== parentCall.callee.type || ! ( 'name' in parentCall.callee.property ) ) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if ( parentCall.callee.property.name !== 'html' ) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return isJQueryCall( parentCall ) ? parentCall.callee : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const plugin: TSESLint.RuleModule<Messages> = {
|
|
43
|
+
defaultOptions: [],
|
|
44
|
+
meta: {
|
|
45
|
+
docs: {
|
|
46
|
+
description: 'Disallow jQuery .html().text() chaining which can lead to XSS through tag stripping',
|
|
47
|
+
},
|
|
48
|
+
hasSuggestions: true,
|
|
49
|
+
messages: {
|
|
50
|
+
vulnerableTagStripping: 'Using .html().text() can lead to XSS vulnerabilities through tag stripping. Use only .text()',
|
|
51
|
+
useTextOnly: 'Remove .html() and move the argument to .text()',
|
|
52
|
+
},
|
|
53
|
+
schema: [],
|
|
54
|
+
type: 'problem',
|
|
55
|
+
},
|
|
56
|
+
create( context: Context ): TSESLint.RuleListener {
|
|
57
|
+
return {
|
|
58
|
+
CallExpression( node: TSESTree.CallExpression ) {
|
|
59
|
+
const htmlProperty = isTextAfterHtml( node );
|
|
60
|
+
if ( null === htmlProperty ) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const jquerySelector = htmlProperty.object;
|
|
64
|
+
const parentCall = htmlProperty.parent;
|
|
65
|
+
if ( AST_NODE_TYPES.CallExpression !== parentCall.type ) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const htmlArg = parentCall.arguments[ 0 ];
|
|
69
|
+
|
|
70
|
+
context.report( {
|
|
71
|
+
node,
|
|
72
|
+
messageId: 'vulnerableTagStripping',
|
|
73
|
+
suggest: [
|
|
74
|
+
{
|
|
75
|
+
messageId: 'useTextOnly',
|
|
76
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
77
|
+
const selectorText = context.sourceCode.getText( jquerySelector );
|
|
78
|
+
const argText = context.sourceCode.getText( htmlArg );
|
|
79
|
+
return fixer.replaceText( node, `${selectorText}.text( ${argText} )` );
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
} );
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export default plugin;
|
|
@@ -57,7 +57,7 @@ const plugin = {
|
|
|
57
57
|
messages: {
|
|
58
58
|
unsafeWindow: 'Assignment to "{{propName}}" must be sanitized.',
|
|
59
59
|
unsafeWindowLocation: 'Assignment to window.location.{{propName}} must be sanitized.',
|
|
60
|
-
unsafeRead: 'Data from JS global {{propName}} may contain user-supplied values and should be sanitized before
|
|
60
|
+
unsafeRead: 'Data from JS global {{propName}} may contain user-supplied values and should be sanitized before using to prevent XSS.',
|
|
61
61
|
// Suggestions
|
|
62
62
|
domPurify: 'Wrap the argument with a `DOMPurify.sanitize()` call.',
|
|
63
63
|
sanitize: 'Wrap the argument with a `sanitize()` call.',
|
|
@@ -179,3 +179,4 @@ const plugin = {
|
|
|
179
179
|
},
|
|
180
180
|
};
|
|
181
181
|
export default plugin;
|
|
182
|
+
//# sourceMappingURL=window-escaping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"window-escaping.js","sourceRoot":"","sources":["window-escaping.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {AST_NODE_TYPES, type TSESLint, type TSESTree} from '@typescript-eslint/utils';
|
|
2
|
+
import {isLiteralString} from '../helpers/string.js';
|
|
3
|
+
import {isSanitized} from '../helpers/dom-purify.js';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
type Messages =
|
|
7
|
+
'unsafeWindow'
|
|
8
|
+
| 'unsafeRead'
|
|
9
|
+
| 'unsafeWindowLocation'
|
|
10
|
+
| 'domPurify'
|
|
11
|
+
| 'sanitize'
|
|
12
|
+
|
|
13
|
+
type Context = TSESLint.RuleContext<Messages, []>;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// Window and location properties that need special handling
|
|
17
|
+
const LOCATION_PROPS = new Set( [ 'href', 'src', 'action',
|
|
18
|
+
'protocol', 'host', 'hostname', 'pathname', 'search', 'hash', 'username', 'port', 'name', 'status',
|
|
19
|
+
] );
|
|
20
|
+
|
|
21
|
+
const WINDOW_PROPS = new Set( [ 'name', 'status' ] );
|
|
22
|
+
|
|
23
|
+
export function isSafeUrlString( value: string ): boolean {
|
|
24
|
+
return ! /^\s*(?:javascript|data|vbscript|about|livescript)\s*:/i.test( decodeURIComponent( value.replace( /[\u0000-\u001F\u007F]+/g, '' ) ) );
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function isSafeUrlLiteral( node: TSESTree.Expression ): boolean {
|
|
29
|
+
return isLiteralString( node ) && isSafeUrlString( node.value );
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
function isWindowLocationAssignment( node: TSESTree.AssignmentExpression ): boolean {
|
|
34
|
+
// window.location.<prop> = ...
|
|
35
|
+
return (
|
|
36
|
+
AST_NODE_TYPES.MemberExpression === node.left.type &&
|
|
37
|
+
AST_NODE_TYPES.MemberExpression === node.left.object.type &&
|
|
38
|
+
AST_NODE_TYPES.Identifier === node.left.object.property.type &&
|
|
39
|
+
AST_NODE_TYPES.Identifier === node.left.object.object.type &&
|
|
40
|
+
AST_NODE_TYPES.Identifier === node.left.property.type &&
|
|
41
|
+
'window' === node.left.object.object.name &&
|
|
42
|
+
'location' === node.left.object.property.name &&
|
|
43
|
+
LOCATION_PROPS.has( node.left.property.name )
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
function isWindowAssignment( node: TSESTree.AssignmentExpression ): boolean {
|
|
49
|
+
// window.<prop> = ...
|
|
50
|
+
return (
|
|
51
|
+
AST_NODE_TYPES.MemberExpression === node.left.type &&
|
|
52
|
+
AST_NODE_TYPES.Identifier === node.left.object.type &&
|
|
53
|
+
AST_NODE_TYPES.Identifier === node.left.property.type &&
|
|
54
|
+
'window' === node.left.object.name &&
|
|
55
|
+
WINDOW_PROPS.has( node.left.property.name )
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
function isWindowOrLocation( expression: TSESTree.MemberExpression ): boolean {
|
|
61
|
+
// Helper to detect a window.* or window.location.*
|
|
62
|
+
if ( AST_NODE_TYPES.MemberExpression !== expression.type ) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if ( AST_NODE_TYPES.Identifier === expression.object.type && 'window' === expression.object.name ) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if ( AST_NODE_TYPES.MemberExpression === expression.object.type ) {
|
|
69
|
+
const memberObject = expression.object;
|
|
70
|
+
const isObjectWindow = AST_NODE_TYPES.Identifier === memberObject.object.type && 'window' === memberObject.object.name;
|
|
71
|
+
const isPropertyLocation = AST_NODE_TYPES.Identifier === memberObject.property.type && 'location' === memberObject.property.name;
|
|
72
|
+
|
|
73
|
+
return isObjectWindow && isPropertyLocation;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
const plugin: TSESLint.RuleModule<Messages> = {
|
|
81
|
+
defaultOptions: [],
|
|
82
|
+
meta: {
|
|
83
|
+
type: 'problem',
|
|
84
|
+
docs: {
|
|
85
|
+
description: 'Require proper escaping for the window and location property access',
|
|
86
|
+
},
|
|
87
|
+
messages: {
|
|
88
|
+
unsafeWindow: 'Assignment to "{{propName}}" must be sanitized.',
|
|
89
|
+
unsafeWindowLocation: 'Assignment to window.location.{{propName}} must be sanitized.',
|
|
90
|
+
unsafeRead: 'Data from JS global {{propName}} may contain user-supplied values and should be sanitized before using to prevent XSS.',
|
|
91
|
+
|
|
92
|
+
// Suggestions
|
|
93
|
+
domPurify: 'Wrap the argument with a `DOMPurify.sanitize()` call.',
|
|
94
|
+
sanitize: 'Wrap the argument with a `sanitize()` call.',
|
|
95
|
+
},
|
|
96
|
+
schema: [],
|
|
97
|
+
hasSuggestions: true,
|
|
98
|
+
},
|
|
99
|
+
create( context: Context ): TSESLint.RuleListener {
|
|
100
|
+
return {
|
|
101
|
+
AssignmentExpression( node: TSESTree.AssignmentExpression ): void {
|
|
102
|
+
const right: TSESTree.Expression = node.right;
|
|
103
|
+
if ( AST_NODE_TYPES.MemberExpression !== node.left.type || ! ( 'name' in node.left.property ) ) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const propName = node.left.property.name;
|
|
107
|
+
|
|
108
|
+
// window.location.<prop> = ...
|
|
109
|
+
if ( isWindowLocationAssignment( node ) ) {
|
|
110
|
+
const rhsResolved: TSESTree.Expression = right;
|
|
111
|
+
if ( ! LOCATION_PROPS.has( propName ) ) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if ( isSafeUrlLiteral( rhsResolved ) || isSanitized( rhsResolved ) ) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
context.report( {
|
|
118
|
+
node,
|
|
119
|
+
messageId: 'unsafeWindowLocation',
|
|
120
|
+
data: {
|
|
121
|
+
propName,
|
|
122
|
+
},
|
|
123
|
+
suggest: [
|
|
124
|
+
{
|
|
125
|
+
messageId: 'sanitize',
|
|
126
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
127
|
+
const argText = context.sourceCode.getText( right );
|
|
128
|
+
return fixer.replaceText( right, `sanitize( ${argText} )` );
|
|
129
|
+
},
|
|
130
|
+
}, {
|
|
131
|
+
messageId: 'domPurify',
|
|
132
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
133
|
+
const argText = context.sourceCode.getText( right );
|
|
134
|
+
return fixer.replaceText( right, `DOMPurify.sanitize( ${argText} )` );
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
} );
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// window.<prop> = ...
|
|
143
|
+
if ( isWindowAssignment( node ) ) {
|
|
144
|
+
if ( isSanitized( node.right ) ) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
context.report( {
|
|
148
|
+
node,
|
|
149
|
+
messageId: 'unsafeWindow',
|
|
150
|
+
data: {
|
|
151
|
+
propName,
|
|
152
|
+
},
|
|
153
|
+
suggest: [
|
|
154
|
+
{
|
|
155
|
+
messageId: 'sanitize',
|
|
156
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
157
|
+
const argText = context.sourceCode.getText( right );
|
|
158
|
+
return fixer.replaceText( right, `sanitize( ${argText} )` );
|
|
159
|
+
},
|
|
160
|
+
}, {
|
|
161
|
+
messageId: 'domPurify',
|
|
162
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
163
|
+
const argText = context.sourceCode.getText( right );
|
|
164
|
+
return fixer.replaceText( right, `DOMPurify.sanitize( ${argText} )` );
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
} );
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
// Check for reading from the window.location properties
|
|
174
|
+
MemberExpression( node: TSESTree.MemberExpression ): void {
|
|
175
|
+
const parent = node.parent;
|
|
176
|
+
if ( AST_NODE_TYPES.AssignmentExpression === parent.type && parent.left === node ) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if ( ! isWindowOrLocation( node ) || ! ( 'name' in node.property ) ) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const propName = node.property.name;
|
|
184
|
+
if ( ! LOCATION_PROPS.has( propName ) ) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if ( AST_NODE_TYPES.CallExpression === parent.type && isSanitized( parent ) ) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
context.report( {
|
|
193
|
+
node,
|
|
194
|
+
messageId: 'unsafeRead',
|
|
195
|
+
data: {
|
|
196
|
+
propName,
|
|
197
|
+
},
|
|
198
|
+
suggest: [
|
|
199
|
+
{
|
|
200
|
+
messageId: 'sanitize',
|
|
201
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
202
|
+
const argText = context.sourceCode.getText( node );
|
|
203
|
+
return fixer.replaceText( node, `sanitize( ${argText} )` );
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
messageId: 'domPurify',
|
|
208
|
+
fix: ( fixer: TSESLint.RuleFixer ) => {
|
|
209
|
+
const argText = context.sourceCode.getText( node );
|
|
210
|
+
return fixer.replaceText( node, `DOMPurify.sanitize( ${argText} )` );
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
} );
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
export default plugin;
|
package/types/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
/**
|
|
3
|
-
* Check if a node is a call to a known sanitization function.
|
|
4
|
-
* - Currently recognizes `sanitize(...)` and `DOMPurify.sanitize(...)`.
|
|
5
|
-
*/
|
|
6
|
-
export declare function isSanitized(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
/**
|
|
3
|
-
* Is the type of variable being passed a DOM element?
|
|
4
|
-
*
|
|
5
|
-
* - DOM elements are of the type `HTML{*}Element`.
|
|
6
|
-
* - DOM elements do not require sanitization.
|
|
7
|
-
*
|
|
8
|
-
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
9
|
-
*/
|
|
10
|
-
export declare function isDomElementType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): boolean;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
/**
|
|
3
|
-
* Is the node of type string.
|
|
4
|
-
* - String literals.
|
|
5
|
-
* - constants of type string.
|
|
6
|
-
* - template literals.
|
|
7
|
-
* - intrinsic type string.
|
|
8
|
-
*/
|
|
9
|
-
export declare function isStringLike(node: TSESTree.CallExpressionArgument, context: Readonly<TSESLint.RuleContext<string, readonly []>>): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Check if a node is a literal string
|
|
12
|
-
*/
|
|
13
|
-
export declare function isLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): node is TSESTree.StringLiteral;
|
|
14
|
-
/**
|
|
15
|
-
* Check if a node is a literal string that is safe to use in an HTML context.
|
|
16
|
-
* - Must be a literal string. Or a conditional expression where both branches are safe literal strings.
|
|
17
|
-
* - Must not contain `<script`.
|
|
18
|
-
* - Must not start with a dangerous protocol (javascript:, data:, vbscript:, about:, livescript:).
|
|
19
|
-
*/
|
|
20
|
-
export declare function isSafeLiteralString(node: TSESTree.Property['value'] | TSESTree.CallExpressionArgument): boolean;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
import type { Type } from 'typescript';
|
|
3
|
-
/**
|
|
4
|
-
* Get the TypeScript type of node.
|
|
5
|
-
*/
|
|
6
|
-
export declare function getType<Context extends Readonly<TSESLint.RuleContext<string, readonly []>>>(expression: TSESTree.CallExpressionArgument, context: Context): Type;
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type TSESLint } from '@typescript-eslint/utils';
|
|
2
|
-
type HtmlExecutingFunctions = 'document.write' | 'document.writeln';
|
|
3
|
-
type UnsafeCalls = 'after' | 'append' | 'before' | 'insertAdjacentHTML' | 'prepend' | 'replaceWith' | 'setAttribute';
|
|
4
|
-
type Messages = HtmlExecutingFunctions | UnsafeCalls | 'sanitize' | 'domPurify';
|
|
5
|
-
declare const plugin: TSESLint.RuleModule<Messages>;
|
|
6
|
-
export default plugin;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
/**
|
|
3
|
-
* Check if an expression contains any HTML-like strings.
|
|
4
|
-
* - Looks for `<` or `>` characters in string literals and template literals.
|
|
5
|
-
* - Recursively checks binary expressions with the ` + ` operator.
|
|
6
|
-
*/
|
|
7
|
-
export declare function hasHtmlLikeStrings(node: TSESTree.Expression | TSESTree.PrivateIdentifier): boolean;
|
|
8
|
-
declare const plugin: TSESLint.RuleModule<'htmlStringConcat'>;
|
|
9
|
-
export default plugin;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
|
|
2
|
-
type UnsafeCalls = 'after' | 'append' | 'appendTo' | 'before' | 'html' | 'insertAfter' | 'insertBefore' | 'prepend' | 'prependTo' | 'replaceAll' | 'replaceWith';
|
|
3
|
-
type Messages = 'needsEscaping' | 'sanitize' | 'domPurify';
|
|
4
|
-
type Context = TSESLint.RuleContext<Messages, []>;
|
|
5
|
-
/**
|
|
6
|
-
* Is the type of variable being passed a jQuery element?
|
|
7
|
-
*
|
|
8
|
-
* - jQuery elements are of type `JQuery`.
|
|
9
|
-
* - jQuery elements do not require sanitization.
|
|
10
|
-
*
|
|
11
|
-
* @link https://typescript-eslint.io/developers/custom-rules/#typed-rules
|
|
12
|
-
*/
|
|
13
|
-
export declare function isJQueryElementType(arg: TSESTree.CallExpressionArgument, context: Context): boolean;
|
|
14
|
-
export declare function isJQueryCall(node: TSESTree.CallExpression): boolean;
|
|
15
|
-
export declare function getJQueryCall(node: TSESTree.CallExpression): UnsafeCalls | null;
|
|
16
|
-
declare const plugin: TSESLint.RuleModule<Messages>;
|
|
17
|
-
export default plugin;
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { type TSESLint } from '@typescript-eslint/utils';
|
|
2
|
-
type Messages = 'unsafeWindow' | 'unsafeRead' | 'unsafeWindowLocation' | 'domPurify' | 'sanitize';
|
|
3
|
-
export declare function isSafeUrlString(value: string): boolean;
|
|
4
|
-
declare const plugin: TSESLint.RuleModule<Messages>;
|
|
5
|
-
export default plugin;
|