eslint-plugin-secure-coding 2.3.2 → 2.3.3
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/README.md +1 -0
- package/package.json +3 -10
- package/src/index.ts +605 -0
- package/src/rules/__tests__/integration-demo.test.ts +290 -0
- package/src/rules/__tests__/integration-llm.test.ts +89 -0
- package/src/rules/database-injection/database-injection.test.ts +456 -0
- package/src/rules/database-injection/index.ts +488 -0
- package/src/rules/detect-child-process/detect-child-process.test.ts +207 -0
- package/src/rules/detect-child-process/index.ts +634 -0
- package/src/rules/detect-eval-with-expression/detect-eval-with-expression.test.ts +416 -0
- package/src/rules/detect-eval-with-expression/index.ts +463 -0
- package/src/rules/detect-mixed-content/detect-mixed-content.test.ts +28 -0
- package/src/rules/detect-mixed-content/index.ts +52 -0
- package/src/rules/detect-non-literal-fs-filename/detect-non-literal-fs-filename.test.ts +269 -0
- package/src/rules/detect-non-literal-fs-filename/index.ts +551 -0
- package/src/rules/detect-non-literal-regexp/detect-non-literal-regexp.test.ts +189 -0
- package/src/rules/detect-non-literal-regexp/index.ts +490 -0
- package/src/rules/detect-object-injection/detect-object-injection.test.ts +440 -0
- package/src/rules/detect-object-injection/index.ts +674 -0
- package/src/rules/detect-suspicious-dependencies/detect-suspicious-dependencies.test.ts +32 -0
- package/src/rules/detect-suspicious-dependencies/index.ts +84 -0
- package/src/rules/detect-weak-password-validation/detect-weak-password-validation.test.ts +31 -0
- package/src/rules/detect-weak-password-validation/index.ts +68 -0
- package/src/rules/no-allow-arbitrary-loads/index.ts +54 -0
- package/src/rules/no-allow-arbitrary-loads/no-allow-arbitrary-loads.test.ts +28 -0
- package/src/rules/no-arbitrary-file-access/index.ts +238 -0
- package/src/rules/no-arbitrary-file-access/no-arbitrary-file-access.test.ts +119 -0
- package/src/rules/no-buffer-overread/index.ts +724 -0
- package/src/rules/no-buffer-overread/no-buffer-overread.test.ts +313 -0
- package/src/rules/no-clickjacking/index.ts +481 -0
- package/src/rules/no-clickjacking/no-clickjacking.test.ts +253 -0
- package/src/rules/no-client-side-auth-logic/index.ts +81 -0
- package/src/rules/no-client-side-auth-logic/no-client-side-auth-logic.test.ts +33 -0
- package/src/rules/no-credentials-in-query-params/index.ts +69 -0
- package/src/rules/no-credentials-in-query-params/no-credentials-in-query-params.test.ts +33 -0
- package/src/rules/no-credentials-in-storage-api/index.ts +64 -0
- package/src/rules/no-credentials-in-storage-api/no-credentials-in-storage-api.test.ts +31 -0
- package/src/rules/no-data-in-temp-storage/index.ts +75 -0
- package/src/rules/no-data-in-temp-storage/no-data-in-temp-storage.test.ts +33 -0
- package/src/rules/no-debug-code-in-production/index.ts +59 -0
- package/src/rules/no-debug-code-in-production/no-debug-code-in-production.test.ts +26 -0
- package/src/rules/no-directive-injection/index.ts +551 -0
- package/src/rules/no-directive-injection/no-directive-injection.test.ts +305 -0
- package/src/rules/no-disabled-certificate-validation/index.ts +72 -0
- package/src/rules/no-disabled-certificate-validation/no-disabled-certificate-validation.test.ts +33 -0
- package/src/rules/no-document-cookie/index.ts +113 -0
- package/src/rules/no-document-cookie/no-document-cookie.test.ts +382 -0
- package/src/rules/no-dynamic-dependency-loading/index.ts +60 -0
- package/src/rules/no-dynamic-dependency-loading/no-dynamic-dependency-loading.test.ts +27 -0
- package/src/rules/no-electron-security-issues/index.ts +504 -0
- package/src/rules/no-electron-security-issues/no-electron-security-issues.test.ts +324 -0
- package/src/rules/no-exposed-debug-endpoints/index.ts +73 -0
- package/src/rules/no-exposed-debug-endpoints/no-exposed-debug-endpoints.test.ts +40 -0
- package/src/rules/no-exposed-sensitive-data/index.ts +428 -0
- package/src/rules/no-exposed-sensitive-data/no-exposed-sensitive-data.test.ts +75 -0
- package/src/rules/no-format-string-injection/index.ts +801 -0
- package/src/rules/no-format-string-injection/no-format-string-injection.test.ts +437 -0
- package/src/rules/no-graphql-injection/index.ts +508 -0
- package/src/rules/no-graphql-injection/no-graphql-injection.test.ts +371 -0
- package/src/rules/no-hardcoded-credentials/index.ts +478 -0
- package/src/rules/no-hardcoded-credentials/no-hardcoded-credentials.test.ts +639 -0
- package/src/rules/no-hardcoded-session-tokens/index.ts +69 -0
- package/src/rules/no-hardcoded-session-tokens/no-hardcoded-session-tokens.test.ts +42 -0
- package/src/rules/no-http-urls/index.ts +131 -0
- package/src/rules/no-http-urls/no-http-urls.test.ts +60 -0
- package/src/rules/no-improper-sanitization/index.ts +502 -0
- package/src/rules/no-improper-sanitization/no-improper-sanitization.test.ts +156 -0
- package/src/rules/no-improper-type-validation/index.ts +572 -0
- package/src/rules/no-improper-type-validation/no-improper-type-validation.test.ts +372 -0
- package/src/rules/no-insecure-comparison/index.ts +232 -0
- package/src/rules/no-insecure-comparison/no-insecure-comparison.test.ts +218 -0
- package/src/rules/no-insecure-cookie-settings/index.ts +391 -0
- package/src/rules/no-insecure-cookie-settings/no-insecure-cookie-settings.test.ts +409 -0
- package/src/rules/no-insecure-jwt/index.ts +467 -0
- package/src/rules/no-insecure-jwt/no-insecure-jwt.test.ts +259 -0
- package/src/rules/no-insecure-redirects/index.ts +267 -0
- package/src/rules/no-insecure-redirects/no-insecure-redirects.test.ts +108 -0
- package/src/rules/no-insecure-websocket/index.ts +72 -0
- package/src/rules/no-insecure-websocket/no-insecure-websocket.test.ts +42 -0
- package/src/rules/no-insufficient-postmessage-validation/index.ts +497 -0
- package/src/rules/no-insufficient-postmessage-validation/no-insufficient-postmessage-validation.test.ts +360 -0
- package/src/rules/no-insufficient-random/index.ts +288 -0
- package/src/rules/no-insufficient-random/no-insufficient-random.test.ts +246 -0
- package/src/rules/no-ldap-injection/index.ts +547 -0
- package/src/rules/no-ldap-injection/no-ldap-injection.test.ts +317 -0
- package/src/rules/no-missing-authentication/index.ts +408 -0
- package/src/rules/no-missing-authentication/no-missing-authentication.test.ts +350 -0
- package/src/rules/no-missing-cors-check/index.ts +453 -0
- package/src/rules/no-missing-cors-check/no-missing-cors-check.test.ts +392 -0
- package/src/rules/no-missing-csrf-protection/index.ts +229 -0
- package/src/rules/no-missing-csrf-protection/no-missing-csrf-protection.test.ts +222 -0
- package/src/rules/no-missing-security-headers/index.ts +266 -0
- package/src/rules/no-missing-security-headers/no-missing-security-headers.test.ts +98 -0
- package/src/rules/no-password-in-url/index.ts +64 -0
- package/src/rules/no-password-in-url/no-password-in-url.test.ts +27 -0
- package/src/rules/no-permissive-cors/index.ts +78 -0
- package/src/rules/no-permissive-cors/no-permissive-cors.test.ts +28 -0
- package/src/rules/no-pii-in-logs/index.ts +83 -0
- package/src/rules/no-pii-in-logs/no-pii-in-logs.test.ts +26 -0
- package/src/rules/no-postmessage-origin-wildcard/index.ts +67 -0
- package/src/rules/no-postmessage-origin-wildcard/no-postmessage-origin-wildcard.test.ts +27 -0
- package/src/rules/no-privilege-escalation/index.ts +403 -0
- package/src/rules/no-privilege-escalation/no-privilege-escalation.test.ts +306 -0
- package/src/rules/no-redos-vulnerable-regex/index.ts +379 -0
- package/src/rules/no-redos-vulnerable-regex/no-redos-vulnerable-regex.test.ts +83 -0
- package/src/rules/no-sensitive-data-exposure/index.ts +294 -0
- package/src/rules/no-sensitive-data-exposure/no-sensitive-data-exposure.test.ts +262 -0
- package/src/rules/no-sensitive-data-in-analytics/index.ts +73 -0
- package/src/rules/no-sensitive-data-in-analytics/no-sensitive-data-in-analytics.test.ts +42 -0
- package/src/rules/no-sensitive-data-in-cache/index.ts +59 -0
- package/src/rules/no-sensitive-data-in-cache/no-sensitive-data-in-cache.test.ts +32 -0
- package/src/rules/no-sql-injection/index.ts +424 -0
- package/src/rules/no-sql-injection/no-sql-injection.test.ts +303 -0
- package/src/rules/no-timing-attack/index.ts +552 -0
- package/src/rules/no-timing-attack/no-timing-attack.test.ts +348 -0
- package/src/rules/no-toctou-vulnerability/index.ts +250 -0
- package/src/rules/no-toctou-vulnerability/no-toctou-vulnerability.test.ts +60 -0
- package/src/rules/no-tracking-without-consent/index.ts +78 -0
- package/src/rules/no-tracking-without-consent/no-tracking-without-consent.test.ts +34 -0
- package/src/rules/no-unchecked-loop-condition/index.ts +781 -0
- package/src/rules/no-unchecked-loop-condition/no-unchecked-loop-condition.test.ts +459 -0
- package/src/rules/no-unencrypted-local-storage/index.ts +73 -0
- package/src/rules/no-unencrypted-local-storage/no-unencrypted-local-storage.test.ts +41 -0
- package/src/rules/no-unencrypted-transmission/index.ts +296 -0
- package/src/rules/no-unencrypted-transmission/no-unencrypted-transmission.test.ts +287 -0
- package/src/rules/no-unescaped-url-parameter/index.ts +424 -0
- package/src/rules/no-unescaped-url-parameter/no-unescaped-url-parameter.test.ts +263 -0
- package/src/rules/no-unlimited-resource-allocation/index.ts +767 -0
- package/src/rules/no-unlimited-resource-allocation/no-unlimited-resource-allocation.test.ts +544 -0
- package/src/rules/no-unsafe-deserialization/index.ts +593 -0
- package/src/rules/no-unsafe-deserialization/no-unsafe-deserialization.test.ts +310 -0
- package/src/rules/no-unsafe-dynamic-require/index.ts +125 -0
- package/src/rules/no-unsafe-dynamic-require/no-unsafe-dynamic-require.test.ts +151 -0
- package/src/rules/no-unsafe-regex-construction/index.ts +370 -0
- package/src/rules/no-unsafe-regex-construction/no-unsafe-regex-construction.test.ts +181 -0
- package/src/rules/no-unsanitized-html/index.ts +400 -0
- package/src/rules/no-unsanitized-html/no-unsanitized-html.test.ts +488 -0
- package/src/rules/no-unvalidated-deeplinks/index.ts +73 -0
- package/src/rules/no-unvalidated-deeplinks/no-unvalidated-deeplinks.test.ts +29 -0
- package/src/rules/no-unvalidated-user-input/index.ts +498 -0
- package/src/rules/no-unvalidated-user-input/no-unvalidated-user-input.test.ts +463 -0
- package/src/rules/no-verbose-error-messages/index.ts +83 -0
- package/src/rules/no-verbose-error-messages/no-verbose-error-messages.test.ts +34 -0
- package/src/rules/no-weak-crypto/index.ts +447 -0
- package/src/rules/no-weak-crypto/no-weak-crypto.test.ts +297 -0
- package/src/rules/no-weak-password-recovery/index.ts +509 -0
- package/src/rules/no-weak-password-recovery/no-weak-password-recovery.test.ts +184 -0
- package/src/rules/no-xpath-injection/index.ts +596 -0
- package/src/rules/no-xpath-injection/no-xpath-injection.test.ts +405 -0
- package/src/rules/no-xxe-injection/index.ts +342 -0
- package/src/rules/no-xxe-injection/no-xxe-injection.test.ts +122 -0
- package/src/rules/no-zip-slip/index.ts +526 -0
- package/src/rules/no-zip-slip/no-zip-slip.test.ts +305 -0
- package/src/rules/require-backend-authorization/index.ts +71 -0
- package/src/rules/require-backend-authorization/require-backend-authorization.test.ts +31 -0
- package/src/rules/require-code-minification/index.ts +54 -0
- package/src/rules/require-code-minification/require-code-minification.test.ts +30 -0
- package/src/rules/require-csp-headers/index.ts +74 -0
- package/src/rules/require-csp-headers/require-csp-headers.test.ts +34 -0
- package/src/rules/require-data-minimization/index.ts +65 -0
- package/src/rules/require-data-minimization/require-data-minimization.test.ts +31 -0
- package/src/rules/require-dependency-integrity/index.ts +78 -0
- package/src/rules/require-dependency-integrity/require-dependency-integrity.test.ts +44 -0
- package/src/rules/require-https-only/index.ts +75 -0
- package/src/rules/require-https-only/require-https-only.test.ts +26 -0
- package/src/rules/require-mime-type-validation/index.ts +77 -0
- package/src/rules/require-mime-type-validation/require-mime-type-validation.test.ts +32 -0
- package/src/rules/require-network-timeout/index.ts +58 -0
- package/src/rules/require-network-timeout/require-network-timeout.test.ts +26 -0
- package/src/rules/require-package-lock/index.ts +75 -0
- package/src/rules/require-package-lock/require-package-lock.test.ts +27 -0
- package/src/rules/require-secure-credential-storage/index.ts +60 -0
- package/src/rules/require-secure-credential-storage/require-secure-credential-storage.test.ts +26 -0
- package/src/rules/require-secure-defaults/index.ts +54 -0
- package/src/rules/require-secure-defaults/require-secure-defaults.test.ts +26 -0
- package/src/rules/require-secure-deletion/index.ts +52 -0
- package/src/rules/require-secure-deletion/require-secure-deletion.test.ts +29 -0
- package/src/rules/require-storage-encryption/index.ts +60 -0
- package/src/rules/require-storage-encryption/require-storage-encryption.test.ts +26 -0
- package/src/rules/require-url-validation/index.ts +85 -0
- package/src/rules/require-url-validation/require-url-validation.test.ts +32 -0
- package/src/types/{index.d.ts → index.ts} +157 -53
- package/src/index.d.ts +0 -32
- package/src/index.js +0 -465
- package/src/rules/database-injection/index.d.ts +0 -13
- package/src/rules/database-injection/index.js +0 -406
- package/src/rules/detect-child-process/index.d.ts +0 -11
- package/src/rules/detect-child-process/index.js +0 -529
- package/src/rules/detect-eval-with-expression/index.d.ts +0 -9
- package/src/rules/detect-eval-with-expression/index.js +0 -392
- package/src/rules/detect-mixed-content/index.d.ts +0 -8
- package/src/rules/detect-mixed-content/index.js +0 -44
- package/src/rules/detect-non-literal-fs-filename/index.d.ts +0 -7
- package/src/rules/detect-non-literal-fs-filename/index.js +0 -454
- package/src/rules/detect-non-literal-regexp/index.d.ts +0 -9
- package/src/rules/detect-non-literal-regexp/index.js +0 -403
- package/src/rules/detect-object-injection/index.d.ts +0 -11
- package/src/rules/detect-object-injection/index.js +0 -560
- package/src/rules/detect-suspicious-dependencies/index.d.ts +0 -8
- package/src/rules/detect-suspicious-dependencies/index.js +0 -71
- package/src/rules/detect-weak-password-validation/index.d.ts +0 -6
- package/src/rules/detect-weak-password-validation/index.js +0 -58
- package/src/rules/no-allow-arbitrary-loads/index.d.ts +0 -8
- package/src/rules/no-allow-arbitrary-loads/index.js +0 -47
- package/src/rules/no-arbitrary-file-access/index.d.ts +0 -13
- package/src/rules/no-arbitrary-file-access/index.js +0 -195
- package/src/rules/no-buffer-overread/index.d.ts +0 -29
- package/src/rules/no-buffer-overread/index.js +0 -606
- package/src/rules/no-clickjacking/index.d.ts +0 -10
- package/src/rules/no-clickjacking/index.js +0 -396
- package/src/rules/no-client-side-auth-logic/index.d.ts +0 -6
- package/src/rules/no-client-side-auth-logic/index.js +0 -69
- package/src/rules/no-credentials-in-query-params/index.d.ts +0 -8
- package/src/rules/no-credentials-in-query-params/index.js +0 -57
- package/src/rules/no-credentials-in-storage-api/index.d.ts +0 -6
- package/src/rules/no-credentials-in-storage-api/index.js +0 -54
- package/src/rules/no-data-in-temp-storage/index.d.ts +0 -6
- package/src/rules/no-data-in-temp-storage/index.js +0 -64
- package/src/rules/no-debug-code-in-production/index.d.ts +0 -8
- package/src/rules/no-debug-code-in-production/index.js +0 -51
- package/src/rules/no-directive-injection/index.d.ts +0 -12
- package/src/rules/no-directive-injection/index.js +0 -457
- package/src/rules/no-disabled-certificate-validation/index.d.ts +0 -6
- package/src/rules/no-disabled-certificate-validation/index.js +0 -61
- package/src/rules/no-document-cookie/index.d.ts +0 -5
- package/src/rules/no-document-cookie/index.js +0 -89
- package/src/rules/no-dynamic-dependency-loading/index.d.ts +0 -8
- package/src/rules/no-dynamic-dependency-loading/index.js +0 -51
- package/src/rules/no-electron-security-issues/index.d.ts +0 -10
- package/src/rules/no-electron-security-issues/index.js +0 -423
- package/src/rules/no-exposed-debug-endpoints/index.d.ts +0 -6
- package/src/rules/no-exposed-debug-endpoints/index.js +0 -62
- package/src/rules/no-exposed-sensitive-data/index.d.ts +0 -11
- package/src/rules/no-exposed-sensitive-data/index.js +0 -340
- package/src/rules/no-format-string-injection/index.d.ts +0 -17
- package/src/rules/no-format-string-injection/index.js +0 -660
- package/src/rules/no-graphql-injection/index.d.ts +0 -12
- package/src/rules/no-graphql-injection/index.js +0 -411
- package/src/rules/no-hardcoded-credentials/index.d.ts +0 -26
- package/src/rules/no-hardcoded-credentials/index.js +0 -376
- package/src/rules/no-hardcoded-session-tokens/index.d.ts +0 -6
- package/src/rules/no-hardcoded-session-tokens/index.js +0 -59
- package/src/rules/no-http-urls/index.d.ts +0 -12
- package/src/rules/no-http-urls/index.js +0 -114
- package/src/rules/no-improper-sanitization/index.d.ts +0 -12
- package/src/rules/no-improper-sanitization/index.js +0 -411
- package/src/rules/no-improper-type-validation/index.d.ts +0 -10
- package/src/rules/no-improper-type-validation/index.js +0 -475
- package/src/rules/no-insecure-comparison/index.d.ts +0 -7
- package/src/rules/no-insecure-comparison/index.js +0 -193
- package/src/rules/no-insecure-cookie-settings/index.d.ts +0 -9
- package/src/rules/no-insecure-cookie-settings/index.js +0 -306
- package/src/rules/no-insecure-jwt/index.d.ts +0 -10
- package/src/rules/no-insecure-jwt/index.js +0 -380
- package/src/rules/no-insecure-redirects/index.d.ts +0 -7
- package/src/rules/no-insecure-redirects/index.js +0 -216
- package/src/rules/no-insecure-websocket/index.d.ts +0 -6
- package/src/rules/no-insecure-websocket/index.js +0 -61
- package/src/rules/no-insufficient-postmessage-validation/index.d.ts +0 -14
- package/src/rules/no-insufficient-postmessage-validation/index.js +0 -392
- package/src/rules/no-insufficient-random/index.d.ts +0 -9
- package/src/rules/no-insufficient-random/index.js +0 -208
- package/src/rules/no-ldap-injection/index.d.ts +0 -10
- package/src/rules/no-ldap-injection/index.js +0 -455
- package/src/rules/no-missing-authentication/index.d.ts +0 -13
- package/src/rules/no-missing-authentication/index.js +0 -333
- package/src/rules/no-missing-cors-check/index.d.ts +0 -9
- package/src/rules/no-missing-cors-check/index.js +0 -399
- package/src/rules/no-missing-csrf-protection/index.d.ts +0 -11
- package/src/rules/no-missing-csrf-protection/index.js +0 -180
- package/src/rules/no-missing-security-headers/index.d.ts +0 -7
- package/src/rules/no-missing-security-headers/index.js +0 -218
- package/src/rules/no-password-in-url/index.d.ts +0 -8
- package/src/rules/no-password-in-url/index.js +0 -54
- package/src/rules/no-permissive-cors/index.d.ts +0 -8
- package/src/rules/no-permissive-cors/index.js +0 -65
- package/src/rules/no-pii-in-logs/index.d.ts +0 -8
- package/src/rules/no-pii-in-logs/index.js +0 -70
- package/src/rules/no-postmessage-origin-wildcard/index.d.ts +0 -8
- package/src/rules/no-postmessage-origin-wildcard/index.js +0 -56
- package/src/rules/no-privilege-escalation/index.d.ts +0 -13
- package/src/rules/no-privilege-escalation/index.js +0 -321
- package/src/rules/no-redos-vulnerable-regex/index.d.ts +0 -7
- package/src/rules/no-redos-vulnerable-regex/index.js +0 -306
- package/src/rules/no-sensitive-data-exposure/index.d.ts +0 -11
- package/src/rules/no-sensitive-data-exposure/index.js +0 -250
- package/src/rules/no-sensitive-data-in-analytics/index.d.ts +0 -8
- package/src/rules/no-sensitive-data-in-analytics/index.js +0 -62
- package/src/rules/no-sensitive-data-in-cache/index.d.ts +0 -8
- package/src/rules/no-sensitive-data-in-cache/index.js +0 -52
- package/src/rules/no-sql-injection/index.d.ts +0 -10
- package/src/rules/no-sql-injection/index.js +0 -335
- package/src/rules/no-timing-attack/index.d.ts +0 -10
- package/src/rules/no-timing-attack/index.js +0 -447
- package/src/rules/no-toctou-vulnerability/index.d.ts +0 -7
- package/src/rules/no-toctou-vulnerability/index.js +0 -208
- package/src/rules/no-tracking-without-consent/index.d.ts +0 -6
- package/src/rules/no-tracking-without-consent/index.js +0 -67
- package/src/rules/no-unchecked-loop-condition/index.d.ts +0 -12
- package/src/rules/no-unchecked-loop-condition/index.js +0 -646
- package/src/rules/no-unencrypted-local-storage/index.d.ts +0 -8
- package/src/rules/no-unencrypted-local-storage/index.js +0 -61
- package/src/rules/no-unencrypted-transmission/index.d.ts +0 -11
- package/src/rules/no-unencrypted-transmission/index.js +0 -236
- package/src/rules/no-unescaped-url-parameter/index.d.ts +0 -9
- package/src/rules/no-unescaped-url-parameter/index.js +0 -355
- package/src/rules/no-unlimited-resource-allocation/index.d.ts +0 -12
- package/src/rules/no-unlimited-resource-allocation/index.js +0 -643
- package/src/rules/no-unsafe-deserialization/index.d.ts +0 -10
- package/src/rules/no-unsafe-deserialization/index.js +0 -491
- package/src/rules/no-unsafe-dynamic-require/index.d.ts +0 -5
- package/src/rules/no-unsafe-dynamic-require/index.js +0 -106
- package/src/rules/no-unsafe-regex-construction/index.d.ts +0 -9
- package/src/rules/no-unsafe-regex-construction/index.js +0 -291
- package/src/rules/no-unsanitized-html/index.d.ts +0 -9
- package/src/rules/no-unsanitized-html/index.js +0 -335
- package/src/rules/no-unvalidated-deeplinks/index.d.ts +0 -6
- package/src/rules/no-unvalidated-deeplinks/index.js +0 -62
- package/src/rules/no-unvalidated-user-input/index.d.ts +0 -9
- package/src/rules/no-unvalidated-user-input/index.js +0 -420
- package/src/rules/no-verbose-error-messages/index.d.ts +0 -8
- package/src/rules/no-verbose-error-messages/index.js +0 -68
- package/src/rules/no-weak-crypto/index.d.ts +0 -11
- package/src/rules/no-weak-crypto/index.js +0 -351
- package/src/rules/no-weak-password-recovery/index.d.ts +0 -12
- package/src/rules/no-weak-password-recovery/index.js +0 -424
- package/src/rules/no-xpath-injection/index.d.ts +0 -10
- package/src/rules/no-xpath-injection/index.js +0 -487
- package/src/rules/no-xxe-injection/index.d.ts +0 -7
- package/src/rules/no-xxe-injection/index.js +0 -266
- package/src/rules/no-zip-slip/index.d.ts +0 -9
- package/src/rules/no-zip-slip/index.js +0 -445
- package/src/rules/require-backend-authorization/index.d.ts +0 -6
- package/src/rules/require-backend-authorization/index.js +0 -60
- package/src/rules/require-code-minification/index.d.ts +0 -8
- package/src/rules/require-code-minification/index.js +0 -47
- package/src/rules/require-csp-headers/index.d.ts +0 -6
- package/src/rules/require-csp-headers/index.js +0 -64
- package/src/rules/require-data-minimization/index.d.ts +0 -8
- package/src/rules/require-data-minimization/index.js +0 -53
- package/src/rules/require-dependency-integrity/index.d.ts +0 -6
- package/src/rules/require-dependency-integrity/index.js +0 -64
- package/src/rules/require-https-only/index.d.ts +0 -8
- package/src/rules/require-https-only/index.js +0 -62
- package/src/rules/require-mime-type-validation/index.d.ts +0 -6
- package/src/rules/require-mime-type-validation/index.js +0 -66
- package/src/rules/require-network-timeout/index.d.ts +0 -8
- package/src/rules/require-network-timeout/index.js +0 -50
- package/src/rules/require-package-lock/index.d.ts +0 -8
- package/src/rules/require-package-lock/index.js +0 -63
- package/src/rules/require-secure-credential-storage/index.d.ts +0 -8
- package/src/rules/require-secure-credential-storage/index.js +0 -50
- package/src/rules/require-secure-defaults/index.d.ts +0 -8
- package/src/rules/require-secure-defaults/index.js +0 -47
- package/src/rules/require-secure-deletion/index.d.ts +0 -8
- package/src/rules/require-secure-deletion/index.js +0 -44
- package/src/rules/require-storage-encryption/index.d.ts +0 -8
- package/src/rules/require-storage-encryption/index.js +0 -50
- package/src/rules/require-url-validation/index.d.ts +0 -6
- package/src/rules/require-url-validation/index.js +0 -72
- package/src/types/index.js +0 -17
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESLint Rule: no-missing-cors-check
|
|
3
|
+
* Detects missing CORS validation (wildcard CORS, missing origin check)
|
|
4
|
+
* CWE-346: Origin Validation Error
|
|
5
|
+
*
|
|
6
|
+
* @see https://cwe.mitre.org/data/definitions/346.html
|
|
7
|
+
* @see https://owasp.org/www-community/attacks/CORS_Misconfiguration
|
|
8
|
+
*/
|
|
9
|
+
import type { TSESLint, TSESTree } from '@interlace/eslint-devkit';
|
|
10
|
+
import { formatLLMMessage, MessageIcons } from '@interlace/eslint-devkit';
|
|
11
|
+
import { createRule } from '@interlace/eslint-devkit';
|
|
12
|
+
|
|
13
|
+
type MessageIds = 'missingCorsCheck' | 'useOriginValidation' | 'useCorsMiddleware';
|
|
14
|
+
|
|
15
|
+
export interface Options {
|
|
16
|
+
/** Allow missing CORS checks in test files. Default: false */
|
|
17
|
+
allowInTests?: boolean;
|
|
18
|
+
|
|
19
|
+
/** Trusted CORS libraries. Default: ['cors', '@koa/cors', 'express-cors'] */
|
|
20
|
+
trustedLibraries?: string[];
|
|
21
|
+
|
|
22
|
+
/** Additional safe patterns to ignore. Default: [] */
|
|
23
|
+
ignorePatterns?: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
type RuleOptions = [Options?];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if a string matches any ignore pattern
|
|
30
|
+
*/
|
|
31
|
+
function matchesIgnorePattern(text: string, ignorePatterns: string[]): boolean {
|
|
32
|
+
return ignorePatterns.some(pattern => {
|
|
33
|
+
try {
|
|
34
|
+
const regex = new RegExp(pattern, 'i');
|
|
35
|
+
return regex.test(text);
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const noMissingCorsCheck = createRule<RuleOptions, MessageIds>({
|
|
43
|
+
name: 'no-missing-cors-check',
|
|
44
|
+
meta: {
|
|
45
|
+
type: 'problem',
|
|
46
|
+
deprecated: true,
|
|
47
|
+
replacedBy: ['@see eslint-plugin-express-security/no-permissive-cors'],
|
|
48
|
+
docs: {
|
|
49
|
+
description: 'Detects missing CORS validation (wildcard CORS, missing origin check)',
|
|
50
|
+
},
|
|
51
|
+
hasSuggestions: true,
|
|
52
|
+
messages: {
|
|
53
|
+
missingCorsCheck: formatLLMMessage({
|
|
54
|
+
icon: MessageIcons.SECURITY,
|
|
55
|
+
issueName: 'Missing CORS Validation',
|
|
56
|
+
cwe: 'CWE-346',
|
|
57
|
+
description: 'Missing CORS validation detected: {{issue}}',
|
|
58
|
+
severity: 'HIGH',
|
|
59
|
+
fix: '{{safeAlternative}}',
|
|
60
|
+
documentationLink: 'https://cwe.mitre.org/data/definitions/346.html',
|
|
61
|
+
}),
|
|
62
|
+
useOriginValidation: formatLLMMessage({
|
|
63
|
+
icon: MessageIcons.INFO,
|
|
64
|
+
issueName: 'Validate Origin',
|
|
65
|
+
description: 'Validate CORS origin',
|
|
66
|
+
severity: 'LOW',
|
|
67
|
+
fix: 'cors({ origin: (origin, cb) => allowedOrigins.includes(origin) ? cb(null, true) : cb(new Error()) })',
|
|
68
|
+
documentationLink: 'https://github.com/expressjs/cors#configuration-options',
|
|
69
|
+
}),
|
|
70
|
+
useCorsMiddleware: formatLLMMessage({
|
|
71
|
+
icon: MessageIcons.INFO,
|
|
72
|
+
issueName: 'Use CORS Middleware',
|
|
73
|
+
description: 'Use CORS middleware with origin validation',
|
|
74
|
+
severity: 'LOW',
|
|
75
|
+
fix: 'app.use(cors({ origin: allowedOrigins }))',
|
|
76
|
+
documentationLink: 'https://github.com/expressjs/cors',
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
schema: [
|
|
80
|
+
{
|
|
81
|
+
type: 'object',
|
|
82
|
+
properties: {
|
|
83
|
+
allowInTests: {
|
|
84
|
+
type: 'boolean',
|
|
85
|
+
default: false,
|
|
86
|
+
description: 'Allow missing CORS checks in test files',
|
|
87
|
+
},
|
|
88
|
+
trustedLibraries: {
|
|
89
|
+
type: 'array',
|
|
90
|
+
items: { type: 'string' },
|
|
91
|
+
default: [],
|
|
92
|
+
description: 'Custom CORS libraries to trust (wildcard origins in these libraries will not be reported)',
|
|
93
|
+
},
|
|
94
|
+
ignorePatterns: {
|
|
95
|
+
type: 'array',
|
|
96
|
+
items: { type: 'string' },
|
|
97
|
+
default: [],
|
|
98
|
+
description: 'Additional safe patterns to ignore',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
additionalProperties: false,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
defaultOptions: [
|
|
106
|
+
{
|
|
107
|
+
allowInTests: false,
|
|
108
|
+
trustedLibraries: [], // Empty by default - users can add custom CORS libraries they trust
|
|
109
|
+
ignorePatterns: [],
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
create(
|
|
113
|
+
context: TSESLint.RuleContext<MessageIds, RuleOptions>,
|
|
114
|
+
[options = {}]
|
|
115
|
+
) {
|
|
116
|
+
const {
|
|
117
|
+
allowInTests = false,
|
|
118
|
+
trustedLibraries: corsTrustedLibraries = [],
|
|
119
|
+
ignorePatterns = [],
|
|
120
|
+
} = options as Options;
|
|
121
|
+
|
|
122
|
+
const trustedLibraries = corsTrustedLibraries;
|
|
123
|
+
|
|
124
|
+
const filename = context.getFilename();
|
|
125
|
+
const isTestFile = allowInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
126
|
+
const sourceCode = context.sourceCode || context.sourceCode;
|
|
127
|
+
|
|
128
|
+
function checkLiteral(node: TSESTree.Literal) {
|
|
129
|
+
if (isTestFile) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check for wildcard CORS origin
|
|
134
|
+
if (node.value === '*' && typeof node.value === 'string') {
|
|
135
|
+
const text = sourceCode.getText(node);
|
|
136
|
+
|
|
137
|
+
// Check if it matches any ignore pattern
|
|
138
|
+
if (matchesIgnorePattern(text, ignorePatterns)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check if it's in contexts handled by other checkers
|
|
143
|
+
// 1. setHeader/header calls - checkMemberExpression handles these
|
|
144
|
+
// 2. app.use(cors({ origin: "*" })) - checkCallExpression handles these with suggestions
|
|
145
|
+
let shouldSkip = false;
|
|
146
|
+
let current: TSESTree.Node | null = node;
|
|
147
|
+
while (current && current.parent) {
|
|
148
|
+
current = current.parent as TSESTree.Node;
|
|
149
|
+
if (current.type === 'CallExpression') {
|
|
150
|
+
const callText = sourceCode.getText(current);
|
|
151
|
+
// Check if it's a setHeader/header call with Access-Control-Allow-Origin
|
|
152
|
+
// Skip these - checkMemberExpression handles them
|
|
153
|
+
if (/\b(setHeader|header)\s*\(/i.test(callText) && /\bAccess-Control-Allow-Origin\b/i.test(callText)) {
|
|
154
|
+
shouldSkip = true;
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
// Check if it's app.use(cors({ origin: "*" })) - checkCallExpression handles these with suggestions
|
|
158
|
+
if (/\buse\s*\(/i.test(callText) && /\bcors\s*\(/i.test(callText)) {
|
|
159
|
+
// Check if the literal is in an object property named "origin"
|
|
160
|
+
if (node.parent && node.parent.type === 'Property') {
|
|
161
|
+
const prop = node.parent as TSESTree.Property;
|
|
162
|
+
if (prop.key.type === 'Identifier' && prop.key.name === 'origin') {
|
|
163
|
+
shouldSkip = true;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Skip if it's in a context handled by another checker
|
|
172
|
+
if (shouldSkip) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Check if it's in a CORS-related context
|
|
177
|
+
// Only report if it's actually in a CORS configuration (app.use(cors(...)), etc.)
|
|
178
|
+
// Not just any object with origin: "*"
|
|
179
|
+
let isActualCorsContext = false;
|
|
180
|
+
|
|
181
|
+
// Check if it's in app.use(cors(...)) or similar
|
|
182
|
+
current = node;
|
|
183
|
+
while (current && current.parent) {
|
|
184
|
+
current = current.parent as TSESTree.Node;
|
|
185
|
+
if (current.type === 'CallExpression') {
|
|
186
|
+
const callText = sourceCode.getText(current);
|
|
187
|
+
// Check if it's a CORS middleware call
|
|
188
|
+
if (/\b(use|cors)\s*\(/i.test(callText) && /\bcors\s*\(/i.test(callText)) {
|
|
189
|
+
isActualCorsContext = true;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Also check if it's in an object property with name "origin" or "allowedOrigins"
|
|
196
|
+
// but only if it's in a CORS-related call expression
|
|
197
|
+
if (node.parent && node.parent.type === 'Property') {
|
|
198
|
+
const prop = node.parent as TSESTree.Property;
|
|
199
|
+
if (prop.key.type === 'Identifier') {
|
|
200
|
+
const keyName = prop.key.name.toLowerCase();
|
|
201
|
+
if (keyName === 'origin' || keyName === 'allowedorigins') {
|
|
202
|
+
// Check if this property is in a CORS call context
|
|
203
|
+
let inCorsCall = false;
|
|
204
|
+
let checkNode: TSESTree.Node | null = prop;
|
|
205
|
+
while (checkNode && checkNode.parent) {
|
|
206
|
+
checkNode = checkNode.parent as TSESTree.Node;
|
|
207
|
+
if (checkNode.type === 'CallExpression') {
|
|
208
|
+
const callText = sourceCode.getText(checkNode);
|
|
209
|
+
if (/\bcors\s*\(/i.test(callText) ||
|
|
210
|
+
(/\buse\s*\(/i.test(callText) && /\bcors/i.test(callText))) {
|
|
211
|
+
inCorsCall = true;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (inCorsCall) {
|
|
218
|
+
// Always report wildcard CORS origin - it's never safe
|
|
219
|
+
context.report({
|
|
220
|
+
node,
|
|
221
|
+
messageId: 'missingCorsCheck',
|
|
222
|
+
data: {
|
|
223
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
224
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
225
|
+
},
|
|
226
|
+
suggest: [
|
|
227
|
+
{
|
|
228
|
+
messageId: 'useOriginValidation',
|
|
229
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
230
|
+
fix: (_fixer: TSESLint.RuleFixer) => null,
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Only report if it's in an actual CORS context
|
|
241
|
+
if (isActualCorsContext) {
|
|
242
|
+
// Always report wildcard CORS origin - it's never safe
|
|
243
|
+
context.report({
|
|
244
|
+
node,
|
|
245
|
+
messageId: 'missingCorsCheck',
|
|
246
|
+
data: {
|
|
247
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
248
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
249
|
+
},
|
|
250
|
+
suggest: [
|
|
251
|
+
{
|
|
252
|
+
messageId: 'useOriginValidation',
|
|
253
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
254
|
+
fix: (_fixer: TSESLint.RuleFixer) => null,
|
|
255
|
+
},
|
|
256
|
+
],
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function checkCallExpression(node: TSESTree.CallExpression) {
|
|
263
|
+
if (isTestFile) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Check for app.use(cors({ origin: "*" })) or similar
|
|
268
|
+
if (node.callee.type === 'MemberExpression') {
|
|
269
|
+
const property = node.callee.property;
|
|
270
|
+
if (property.type === 'Identifier' && property.name === 'use') {
|
|
271
|
+
// Check if CORS is being used
|
|
272
|
+
const text = sourceCode.getText(node);
|
|
273
|
+
|
|
274
|
+
// Check if it matches any ignore pattern
|
|
275
|
+
if (matchesIgnorePattern(text, ignorePatterns)) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Check if it's a CORS middleware call
|
|
280
|
+
// Check for cors() or trusted library calls
|
|
281
|
+
const firstArg = node.arguments.length > 0 ? node.arguments[0] : null;
|
|
282
|
+
let isCorsCall = /\bcors\s*\(/i.test(text);
|
|
283
|
+
if (!isCorsCall && firstArg && firstArg.type === 'CallExpression' && firstArg.callee.type === 'Identifier') {
|
|
284
|
+
const callee = firstArg.callee;
|
|
285
|
+
const calleeName = callee.name.toLowerCase();
|
|
286
|
+
// Check if it's the standard 'cors' library or a trusted library
|
|
287
|
+
isCorsCall = calleeName === 'cors' || trustedLibraries.some(lib => {
|
|
288
|
+
return calleeName.includes(lib.toLowerCase());
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check if it's a trusted library - skip if explicitly trusted
|
|
293
|
+
let isTrustedLibrary = false;
|
|
294
|
+
if (firstArg && firstArg.type === 'CallExpression' && firstArg.callee.type === 'Identifier') {
|
|
295
|
+
const calleeName = firstArg.callee.name.toLowerCase();
|
|
296
|
+
isTrustedLibrary = trustedLibraries.some(lib => calleeName.includes(lib.toLowerCase()));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (isTrustedLibrary) {
|
|
300
|
+
return; // Trusted library, skip
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Check if it's a CORS call
|
|
304
|
+
if (/\bcors\s*\(/i.test(text) || isCorsCall) {
|
|
305
|
+
// Check arguments for wildcard origin
|
|
306
|
+
// For app.use(cors({ origin: "*" })), we need to check the arguments to cors(), not app.use()
|
|
307
|
+
const corsCallArg = firstArg && firstArg.type === 'CallExpression' ? firstArg : null;
|
|
308
|
+
const argsToCheck = corsCallArg ? corsCallArg.arguments : node.arguments;
|
|
309
|
+
|
|
310
|
+
for (const arg of argsToCheck) {
|
|
311
|
+
if (arg.type === 'ObjectExpression') {
|
|
312
|
+
// Check for origin property with wildcard value
|
|
313
|
+
for (const prop of arg.properties) {
|
|
314
|
+
if (prop.type === 'Property' &&
|
|
315
|
+
prop.key.type === 'Identifier' &&
|
|
316
|
+
prop.key.name === 'origin' &&
|
|
317
|
+
prop.value.type === 'Literal' &&
|
|
318
|
+
prop.value.value === '*') {
|
|
319
|
+
context.report({
|
|
320
|
+
node: prop.value,
|
|
321
|
+
messageId: 'missingCorsCheck',
|
|
322
|
+
data: {
|
|
323
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
324
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
325
|
+
},
|
|
326
|
+
suggest: [
|
|
327
|
+
{
|
|
328
|
+
messageId: 'useOriginValidation',
|
|
329
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
330
|
+
fix: (_fixer: TSESLint.RuleFixer) => null,
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
} else if (arg.type === 'Identifier') {
|
|
337
|
+
// Check if this identifier was assigned an object literal with origin: "*"
|
|
338
|
+
// For cases like: const config = { origin: "*" }; app.use(cors(config));
|
|
339
|
+
const varName = arg.name;
|
|
340
|
+
// Traverse the AST to find the variable declaration
|
|
341
|
+
let current: TSESTree.Node | null = node;
|
|
342
|
+
while (current) {
|
|
343
|
+
if (current.type === 'Program' || current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression' || current.type === 'ArrowFunctionExpression') {
|
|
344
|
+
// Search for variable declarations in this scope
|
|
345
|
+
const scopeBody = current.type === 'Program' ? current.body :
|
|
346
|
+
(current.type === 'FunctionDeclaration' || current.type === 'FunctionExpression' || current.type === 'ArrowFunctionExpression') ?
|
|
347
|
+
(current.body.type === 'BlockStatement' ? current.body.body : []) : [];
|
|
348
|
+
|
|
349
|
+
for (const stmt of scopeBody) {
|
|
350
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
351
|
+
for (const declarator of stmt.declarations) {
|
|
352
|
+
if (declarator.id.type === 'Identifier' && declarator.id.name === varName && declarator.init) {
|
|
353
|
+
// Check if init is an object literal with origin: "*"
|
|
354
|
+
if (declarator.init.type === 'ObjectExpression') {
|
|
355
|
+
for (const prop of declarator.init.properties) {
|
|
356
|
+
if (prop.type === 'Property' &&
|
|
357
|
+
prop.key.type === 'Identifier' &&
|
|
358
|
+
prop.key.name === 'origin' &&
|
|
359
|
+
prop.value.type === 'Literal' &&
|
|
360
|
+
prop.value.value === '*') {
|
|
361
|
+
context.report({
|
|
362
|
+
node: arg,
|
|
363
|
+
messageId: 'missingCorsCheck',
|
|
364
|
+
data: {
|
|
365
|
+
issue: 'Wildcard CORS origin (*) allows all origins',
|
|
366
|
+
safeAlternative: 'Use origin validation: app.use(cors({ origin: (origin, callback) => { if (allowedOrigins.includes(origin)) callback(null, true); else callback(new Error("Not allowed")); } } }));',
|
|
367
|
+
},
|
|
368
|
+
suggest: [
|
|
369
|
+
{
|
|
370
|
+
messageId: 'useOriginValidation',
|
|
371
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
372
|
+
fix: (_fixer: TSESLint.RuleFixer) => null,
|
|
373
|
+
},
|
|
374
|
+
],
|
|
375
|
+
});
|
|
376
|
+
return; // Found and reported, exit
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
break; // Only check the immediate scope
|
|
385
|
+
}
|
|
386
|
+
if (current.parent) {
|
|
387
|
+
current = current.parent as TSESTree.Node;
|
|
388
|
+
} else {
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function checkMemberExpression(node: TSESTree.MemberExpression) {
|
|
400
|
+
if (isTestFile) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Check for Access-Control-Allow-Origin header without validation
|
|
405
|
+
if (node.property.type === 'Identifier') {
|
|
406
|
+
const propertyName = node.property.name;
|
|
407
|
+
|
|
408
|
+
if (propertyName === 'setHeader' || propertyName === 'header') {
|
|
409
|
+
// Check if it matches any ignore pattern
|
|
410
|
+
const text = sourceCode.getText(node);
|
|
411
|
+
if (matchesIgnorePattern(text, ignorePatterns)) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Check if it's setting CORS headers
|
|
416
|
+
// Need to check the full call expression, not just the member expression
|
|
417
|
+
const parent = node.parent;
|
|
418
|
+
if (parent && parent.type === 'CallExpression') {
|
|
419
|
+
const callText = sourceCode.getText(parent);
|
|
420
|
+
if (/\bAccess-Control-Allow-Origin\b/i.test(callText)) {
|
|
421
|
+
// Check if the value is a wildcard
|
|
422
|
+
const args = parent.arguments;
|
|
423
|
+
if (args.length >= 2 && args[1].type === 'Literal' && args[1].value === '*') {
|
|
424
|
+
context.report({
|
|
425
|
+
node: args[1],
|
|
426
|
+
messageId: 'missingCorsCheck',
|
|
427
|
+
data: {
|
|
428
|
+
issue: 'Wildcard CORS header allows all origins',
|
|
429
|
+
safeAlternative: 'Validate origin before setting header: res.setHeader("Access-Control-Allow-Origin", allowedOrigins.includes(origin) ? origin : "null");',
|
|
430
|
+
},
|
|
431
|
+
suggest: [
|
|
432
|
+
{
|
|
433
|
+
messageId: 'useOriginValidation',
|
|
434
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
435
|
+
fix: (_fixer: TSESLint.RuleFixer) => null,
|
|
436
|
+
},
|
|
437
|
+
],
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return {
|
|
447
|
+
Literal: checkLiteral,
|
|
448
|
+
CallExpression: checkCallExpression,
|
|
449
|
+
MemberExpression: checkMemberExpression,
|
|
450
|
+
};
|
|
451
|
+
},
|
|
452
|
+
});
|
|
453
|
+
|