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
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noInsecureJwt = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
6
|
-
const eslint_devkit_3 = require("@interlace/eslint-devkit");
|
|
7
|
-
exports.noInsecureJwt = (0, eslint_devkit_1.createRule)({
|
|
8
|
-
name: 'no-insecure-jwt',
|
|
9
|
-
meta: {
|
|
10
|
-
type: 'problem',
|
|
11
|
-
deprecated: true,
|
|
12
|
-
replacedBy: ['@see eslint-plugin-jwt for 13 specialized JWT security rules'],
|
|
13
|
-
docs: {
|
|
14
|
-
description: 'Detects insecure JWT operations and missing signature verification',
|
|
15
|
-
},
|
|
16
|
-
fixable: 'code',
|
|
17
|
-
hasSuggestions: true,
|
|
18
|
-
messages: {
|
|
19
|
-
insecureJwtAlgorithm: (0, eslint_devkit_2.formatLLMMessage)({
|
|
20
|
-
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
21
|
-
issueName: 'Insecure JWT Algorithm',
|
|
22
|
-
cwe: 'CWE-347',
|
|
23
|
-
description: 'JWT algorithm confusion vulnerability',
|
|
24
|
-
severity: 'CRITICAL',
|
|
25
|
-
fix: 'Use RS256/ES256 and validate algorithm before verification',
|
|
26
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
27
|
-
}),
|
|
28
|
-
missingSignatureVerification: (0, eslint_devkit_2.formatLLMMessage)({
|
|
29
|
-
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
30
|
-
issueName: 'Missing JWT Signature Verification',
|
|
31
|
-
cwe: 'CWE-347',
|
|
32
|
-
description: 'JWT parsed without signature verification',
|
|
33
|
-
severity: 'CRITICAL',
|
|
34
|
-
fix: 'Use jwt.verify() instead of jwt.decode()',
|
|
35
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
36
|
-
}),
|
|
37
|
-
weakJwtSecret: (0, eslint_devkit_2.formatLLMMessage)({
|
|
38
|
-
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
39
|
-
issueName: 'Weak JWT Secret',
|
|
40
|
-
cwe: 'CWE-347',
|
|
41
|
-
description: 'JWT signed with weak/insufficient secret',
|
|
42
|
-
severity: 'HIGH',
|
|
43
|
-
fix: 'Use minimum 256-bit secret (32+ characters)',
|
|
44
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
45
|
-
}),
|
|
46
|
-
jwtWithoutValidation: (0, eslint_devkit_2.formatLLMMessage)({
|
|
47
|
-
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
48
|
-
issueName: 'JWT Without Validation',
|
|
49
|
-
cwe: 'CWE-347',
|
|
50
|
-
description: 'JWT used without proper validation',
|
|
51
|
-
severity: 'HIGH',
|
|
52
|
-
fix: 'Verify JWT signature before trusting payload',
|
|
53
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
54
|
-
}),
|
|
55
|
-
unsafeJwtParsing: (0, eslint_devkit_2.formatLLMMessage)({
|
|
56
|
-
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
57
|
-
issueName: 'Unsafe JWT Parsing',
|
|
58
|
-
cwe: 'CWE-347',
|
|
59
|
-
description: 'Unsafe JWT parsing pattern detected',
|
|
60
|
-
severity: 'MEDIUM',
|
|
61
|
-
fix: 'Use verified JWT libraries with proper error handling',
|
|
62
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
63
|
-
}),
|
|
64
|
-
useSecureJwtLibrary: (0, eslint_devkit_2.formatLLMMessage)({
|
|
65
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
66
|
-
issueName: 'Use Secure JWT Library',
|
|
67
|
-
description: 'Use jsonwebtoken or jose library',
|
|
68
|
-
severity: 'LOW',
|
|
69
|
-
fix: 'npm install jsonwebtoken && use jwt.verify()',
|
|
70
|
-
documentationLink: 'https://www.npmjs.com/package/jsonwebtoken',
|
|
71
|
-
}),
|
|
72
|
-
verifyBeforeTrust: (0, eslint_devkit_2.formatLLMMessage)({
|
|
73
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
74
|
-
issueName: 'Verify Before Trust',
|
|
75
|
-
description: 'Always verify JWT signature before using payload',
|
|
76
|
-
severity: 'LOW',
|
|
77
|
-
fix: 'jwt.verify(token, secret, callback)',
|
|
78
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
79
|
-
}),
|
|
80
|
-
strategyUseVerifiedLibrary: (0, eslint_devkit_2.formatLLMMessage)({
|
|
81
|
-
icon: eslint_devkit_2.MessageIcons.STRATEGY,
|
|
82
|
-
issueName: 'Verified Library Strategy',
|
|
83
|
-
description: 'Use battle-tested JWT libraries',
|
|
84
|
-
severity: 'LOW',
|
|
85
|
-
fix: 'Use jsonwebtoken, jose, or jwt libraries',
|
|
86
|
-
documentationLink: 'https://www.npmjs.com/package/jsonwebtoken',
|
|
87
|
-
}),
|
|
88
|
-
strategyValidateAlgorithm: (0, eslint_devkit_2.formatLLMMessage)({
|
|
89
|
-
icon: eslint_devkit_2.MessageIcons.STRATEGY,
|
|
90
|
-
issueName: 'Algorithm Validation Strategy',
|
|
91
|
-
description: 'Validate algorithms before use',
|
|
92
|
-
severity: 'LOW',
|
|
93
|
-
fix: 'Whitelist allowed algorithms: ["RS256", "ES256"]',
|
|
94
|
-
documentationLink: 'https://tools.ietf.org/html/rfc8725',
|
|
95
|
-
}),
|
|
96
|
-
strategyStrongSecrets: (0, eslint_devkit_2.formatLLMMessage)({
|
|
97
|
-
icon: eslint_devkit_2.MessageIcons.STRATEGY,
|
|
98
|
-
issueName: 'Strong Secrets Strategy',
|
|
99
|
-
description: 'Use cryptographically strong secrets',
|
|
100
|
-
severity: 'LOW',
|
|
101
|
-
fix: 'Generate 256-bit secrets: crypto.randomBytes(32)',
|
|
102
|
-
documentationLink: 'https://nodejs.org/api/crypto.html',
|
|
103
|
-
})
|
|
104
|
-
},
|
|
105
|
-
schema: [
|
|
106
|
-
{
|
|
107
|
-
type: 'object',
|
|
108
|
-
properties: {
|
|
109
|
-
allowedInsecureAlgorithms: {
|
|
110
|
-
type: 'array',
|
|
111
|
-
items: { type: 'string' },
|
|
112
|
-
default: [],
|
|
113
|
-
},
|
|
114
|
-
minSecretLength: {
|
|
115
|
-
type: 'number',
|
|
116
|
-
minimum: 16,
|
|
117
|
-
default: 32,
|
|
118
|
-
},
|
|
119
|
-
trustedJwtLibraries: {
|
|
120
|
-
type: 'array',
|
|
121
|
-
items: { type: 'string' },
|
|
122
|
-
default: ['jsonwebtoken', 'jose', 'jwt'],
|
|
123
|
-
},
|
|
124
|
-
trustedSanitizers: {
|
|
125
|
-
type: 'array',
|
|
126
|
-
items: { type: 'string' },
|
|
127
|
-
default: [],
|
|
128
|
-
description: 'Additional function names to consider as JWT validators',
|
|
129
|
-
},
|
|
130
|
-
trustedAnnotations: {
|
|
131
|
-
type: 'array',
|
|
132
|
-
items: { type: 'string' },
|
|
133
|
-
default: [],
|
|
134
|
-
description: 'Additional JSDoc annotations to consider as safe markers',
|
|
135
|
-
},
|
|
136
|
-
strictMode: {
|
|
137
|
-
type: 'boolean',
|
|
138
|
-
default: false,
|
|
139
|
-
description: 'Disable all false positive detection (strict mode)',
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
additionalProperties: false,
|
|
143
|
-
},
|
|
144
|
-
],
|
|
145
|
-
},
|
|
146
|
-
defaultOptions: [
|
|
147
|
-
{
|
|
148
|
-
allowedInsecureAlgorithms: [],
|
|
149
|
-
minSecretLength: 32,
|
|
150
|
-
trustedJwtLibraries: ['jsonwebtoken', 'jose', 'jwt'],
|
|
151
|
-
trustedSanitizers: [],
|
|
152
|
-
trustedAnnotations: [],
|
|
153
|
-
strictMode: false,
|
|
154
|
-
},
|
|
155
|
-
],
|
|
156
|
-
create(context) {
|
|
157
|
-
const options = context.options[0] || {};
|
|
158
|
-
const { minSecretLength = 32, trustedJwtLibraries = ['jsonwebtoken', 'jose', 'jwt'], trustedSanitizers = [], trustedAnnotations = [], strictMode = false, } = options;
|
|
159
|
-
const sourceCode = context.sourceCode || context.sourceCode;
|
|
160
|
-
const filename = context.filename || context.getFilename();
|
|
161
|
-
// Create safety checker for false positive detection
|
|
162
|
-
const safetyChecker = (0, eslint_devkit_3.createSafetyChecker)({
|
|
163
|
-
trustedSanitizers,
|
|
164
|
-
trustedAnnotations,
|
|
165
|
-
trustedOrmPatterns: [],
|
|
166
|
-
strictMode,
|
|
167
|
-
});
|
|
168
|
-
/**
|
|
169
|
-
* Check if secret/key is weak
|
|
170
|
-
*/
|
|
171
|
-
const isWeakSecret = (secretNode) => {
|
|
172
|
-
if (secretNode.type === 'Literal' && typeof secretNode.value === 'string') {
|
|
173
|
-
return secretNode.value.length < minSecretLength;
|
|
174
|
-
}
|
|
175
|
-
return false; // Can't determine strength of non-literal secrets
|
|
176
|
-
};
|
|
177
|
-
/**
|
|
178
|
-
* Check if JWT operation has signature verification
|
|
179
|
-
*/
|
|
180
|
-
const hasSignatureVerification = (jwtCall) => {
|
|
181
|
-
// Check if it's jwt.verify() call
|
|
182
|
-
if (jwtCall.callee.type === 'MemberExpression' &&
|
|
183
|
-
jwtCall.callee.property.type === 'Identifier' &&
|
|
184
|
-
jwtCall.callee.property.name === 'verify') {
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
// Check for @verified annotation
|
|
188
|
-
return (0, eslint_devkit_3.hasSafeAnnotation)(jwtCall, context, trustedAnnotations);
|
|
189
|
-
};
|
|
190
|
-
/**
|
|
191
|
-
* Check if this is a trusted JWT library call
|
|
192
|
-
*/
|
|
193
|
-
const isTrustedJwtLibrary = (node) => {
|
|
194
|
-
// Check if callee is a member expression (library.method)
|
|
195
|
-
if (node.callee.type !== 'MemberExpression') {
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
// Check if the object is a JWT library
|
|
199
|
-
const object = node.callee.object;
|
|
200
|
-
if (object.type === 'Identifier') {
|
|
201
|
-
return trustedJwtLibraries.includes(object.name.toLowerCase());
|
|
202
|
-
}
|
|
203
|
-
return false;
|
|
204
|
-
};
|
|
205
|
-
/**
|
|
206
|
-
* Extract JWT-related information from a call
|
|
207
|
-
*/
|
|
208
|
-
const extractJwtInfo = (node) => {
|
|
209
|
-
const sourceText = sourceCode.getText(node);
|
|
210
|
-
// Check for algorithm specification
|
|
211
|
-
const hasAlgorithmSpec = /\b(algorithms?|alg)\s*:/i.test(sourceText);
|
|
212
|
-
// Check for insecure patterns
|
|
213
|
-
const hasNoneAlgorithm = /\b(alg|algorithms?)\s*:\s*(\[\s*)?['"`]\s*none\s*['"`]/i.test(sourceText);
|
|
214
|
-
const hasEmptyAlgorithms = /\b(alg|algorithms?)\s*:\s*\[\s*\]/i.test(sourceText);
|
|
215
|
-
const weakAlgorithms = ['HS256', 'HS384', 'HS512']; // Define weak algorithms
|
|
216
|
-
const hasWeakAlgorithm = weakAlgorithms.some(alg => {
|
|
217
|
-
const regex = new RegExp(`['"\`]${alg}['"\`]`, 'i');
|
|
218
|
-
return regex.test(sourceText);
|
|
219
|
-
});
|
|
220
|
-
return {
|
|
221
|
-
sourceText,
|
|
222
|
-
hasAlgorithmSpec,
|
|
223
|
-
hasNoneAlgorithm: hasNoneAlgorithm || hasEmptyAlgorithms,
|
|
224
|
-
hasWeakAlgorithm,
|
|
225
|
-
isDecodeCall: /\bdecode\b/i.test(sourceText),
|
|
226
|
-
isVerifyCall: /\bverify\b/i.test(sourceText),
|
|
227
|
-
};
|
|
228
|
-
};
|
|
229
|
-
/**
|
|
230
|
-
* Locate the algorithms option node for precise error highlighting
|
|
231
|
-
*/
|
|
232
|
-
const getAlgorithmsNode = (call) => {
|
|
233
|
-
const optionsArg = call.arguments[2];
|
|
234
|
-
if (optionsArg && optionsArg.type === 'ObjectExpression') {
|
|
235
|
-
const algorithmsProp = optionsArg.properties.find((prop) => prop.type === 'Property' &&
|
|
236
|
-
prop.key.type === 'Identifier' &&
|
|
237
|
-
(prop.key.name === 'algorithms' || prop.key.name === 'alg'));
|
|
238
|
-
if (algorithmsProp) {
|
|
239
|
-
return algorithmsProp.value;
|
|
240
|
-
}
|
|
241
|
-
return optionsArg;
|
|
242
|
-
}
|
|
243
|
-
return null;
|
|
244
|
-
};
|
|
245
|
-
/**
|
|
246
|
-
* Check if this looks like a JWT operation (verify/decode/sign)
|
|
247
|
-
*/
|
|
248
|
-
const looksLikeJwtOperation = (node) => {
|
|
249
|
-
if (node.callee.type !== 'MemberExpression') {
|
|
250
|
-
return false;
|
|
251
|
-
}
|
|
252
|
-
const property = node.callee.property;
|
|
253
|
-
if (property.type !== 'Identifier') {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
// Check for JWT-related method names
|
|
257
|
-
const jwtMethods = ['verify', 'decode', 'sign', 'encode'];
|
|
258
|
-
return jwtMethods.includes(property.name);
|
|
259
|
-
};
|
|
260
|
-
return {
|
|
261
|
-
// Check JWT library method calls
|
|
262
|
-
CallExpression(node) {
|
|
263
|
-
// Check both trusted libraries AND generic JWT-like operations
|
|
264
|
-
const isTrusted = isTrustedJwtLibrary(node);
|
|
265
|
-
const looksLikeJwt = looksLikeJwtOperation(node);
|
|
266
|
-
if (!isTrusted && !looksLikeJwt) {
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
const jwtInfo = extractJwtInfo(node);
|
|
270
|
-
// CRITICAL: Algorithm confusion attack (alg: "none" or algorithms: [])
|
|
271
|
-
if (jwtInfo.hasNoneAlgorithm) {
|
|
272
|
-
const algorithmsNode = getAlgorithmsNode(node);
|
|
273
|
-
context.report({
|
|
274
|
-
node: algorithmsNode ?? node,
|
|
275
|
-
messageId: 'insecureJwtAlgorithm',
|
|
276
|
-
data: {
|
|
277
|
-
filePath: filename,
|
|
278
|
-
line: String(node.loc?.start.line ?? 0),
|
|
279
|
-
},
|
|
280
|
-
});
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
// HIGH: Weak algorithm without proper key validation
|
|
284
|
-
if (jwtInfo.hasWeakAlgorithm && node.arguments.length >= 2) {
|
|
285
|
-
const secretArg = node.arguments[1];
|
|
286
|
-
if (isWeakSecret(secretArg)) {
|
|
287
|
-
context.report({
|
|
288
|
-
node: secretArg,
|
|
289
|
-
messageId: 'weakJwtSecret',
|
|
290
|
-
data: {
|
|
291
|
-
filePath: filename,
|
|
292
|
-
line: String(node.loc?.start.line ?? 0),
|
|
293
|
-
},
|
|
294
|
-
});
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
// CRITICAL: Using jwt.decode() instead of jwt.verify()
|
|
299
|
-
if (jwtInfo.isDecodeCall && !jwtInfo.isVerifyCall) {
|
|
300
|
-
// FALSE POSITIVE REDUCTION: Skip if annotated as safe
|
|
301
|
-
if (safetyChecker.isSafe(node, context)) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
context.report({
|
|
305
|
-
node,
|
|
306
|
-
messageId: 'missingSignatureVerification',
|
|
307
|
-
data: {
|
|
308
|
-
filePath: filename,
|
|
309
|
-
line: String(node.loc?.start.line ?? 0),
|
|
310
|
-
},
|
|
311
|
-
suggest: [
|
|
312
|
-
{
|
|
313
|
-
messageId: 'verifyBeforeTrust',
|
|
314
|
-
fix: () => null // Could be complex to auto-fix
|
|
315
|
-
},
|
|
316
|
-
],
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
|
-
// Check for JWT-related variable declarations and assignments
|
|
321
|
-
VariableDeclarator(node) {
|
|
322
|
-
if (!node.init || node.init.type !== 'CallExpression') {
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
const initCall = node.init;
|
|
326
|
-
if (!isTrustedJwtLibrary(initCall) && !looksLikeJwtOperation(initCall)) {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
const jwtInfo = extractJwtInfo(initCall);
|
|
330
|
-
// Variable assigned with unverified JWT data
|
|
331
|
-
if (jwtInfo.isDecodeCall && !jwtInfo.isVerifyCall) {
|
|
332
|
-
/* c8 ignore start -- safetyChecker requires JSDoc annotations not testable via RuleTester */
|
|
333
|
-
if (safetyChecker.isSafe(initCall, context)) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
/* c8 ignore stop */
|
|
337
|
-
context.report({
|
|
338
|
-
node,
|
|
339
|
-
messageId: 'jwtWithoutValidation',
|
|
340
|
-
data: {
|
|
341
|
-
filePath: filename,
|
|
342
|
-
line: String(node.loc?.start.line ?? 0),
|
|
343
|
-
},
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
},
|
|
347
|
-
// Check for JWT token usage without verification
|
|
348
|
-
Literal(node) {
|
|
349
|
-
if (typeof node.value !== 'string') {
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
const value = node.value;
|
|
353
|
-
// Look for JWT patterns in strings
|
|
354
|
-
if (value.includes('eyJ') && value.split('.').length === 3) { // JWT structure
|
|
355
|
-
// Check if this JWT is used unsafely
|
|
356
|
-
let current = node;
|
|
357
|
-
let isVerified = false;
|
|
358
|
-
// Walk up to find if this is within a verified JWT operation
|
|
359
|
-
while (current && !isVerified) {
|
|
360
|
-
if (current.type === 'CallExpression' && hasSignatureVerification(current)) {
|
|
361
|
-
isVerified = true;
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
current = current.parent;
|
|
365
|
-
}
|
|
366
|
-
if (!isVerified && !safetyChecker.isSafe(node, context)) {
|
|
367
|
-
context.report({
|
|
368
|
-
node,
|
|
369
|
-
messageId: 'unsafeJwtParsing',
|
|
370
|
-
data: {
|
|
371
|
-
filePath: filename,
|
|
372
|
-
line: String(node.loc?.start.line ?? 0),
|
|
373
|
-
},
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
},
|
|
380
|
-
});
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export interface Options {
|
|
2
|
-
/** Ignore in test files. Default: true */
|
|
3
|
-
ignoreInTests?: boolean;
|
|
4
|
-
/** Allowed redirect domains. Default: [] */
|
|
5
|
-
allowedDomains?: string[];
|
|
6
|
-
}
|
|
7
|
-
export declare const noInsecureRedirects: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noInsecureRedirects = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
6
|
-
/**
|
|
7
|
-
* Check if redirect URL is validated
|
|
8
|
-
*/
|
|
9
|
-
function isRedirectValidated(node, sourceCode) {
|
|
10
|
-
const callText = sourceCode.getText(node);
|
|
11
|
-
// Check if URL is from user input (req.query, req.body, req.params)
|
|
12
|
-
const userInputPattern = /\b(req\.(query|body|params)|window\.location|document\.location)\b/;
|
|
13
|
-
if (!userInputPattern.test(callText)) {
|
|
14
|
-
// Not from user input, assume safe
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
|
-
// Look for validation patterns in the surrounding code
|
|
18
|
-
// This is a simplified static analysis - in practice, would need data flow analysis
|
|
19
|
-
const program = sourceCode.ast;
|
|
20
|
-
const nodeStart = node.loc?.start;
|
|
21
|
-
const nodeEnd = node.loc?.end;
|
|
22
|
-
/* c8 ignore start -- Guard clause: loc is always present in RuleTester */
|
|
23
|
-
if (!nodeStart || !nodeEnd || !program) {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
/* c8 ignore stop */
|
|
27
|
-
// Check for validation function calls before this redirect
|
|
28
|
-
const validationPatterns = [
|
|
29
|
-
/\b(validateUrl|validateRedirect|isValidUrl|isSafeUrl)\s*\(/,
|
|
30
|
-
/\b(whitelist|allowedDomains|permittedUrls)\s*\./,
|
|
31
|
-
/\b(url\.hostname|url\.host)\s*===/,
|
|
32
|
-
/\ballowedDomains\.includes\s*\(/,
|
|
33
|
-
/\bstartsWith\s*\(\s*['"]/,
|
|
34
|
-
/\bendsWith\s*\(\s*['"]/,
|
|
35
|
-
/\bindexOf\s*\(\s*['"]/,
|
|
36
|
-
/\bmatch\s*\(\s*\//,
|
|
37
|
-
];
|
|
38
|
-
// Look for validation in the same function scope
|
|
39
|
-
let current = node;
|
|
40
|
-
let depth = 0;
|
|
41
|
-
const maxDepth = 20;
|
|
42
|
-
while (current && depth < maxDepth) {
|
|
43
|
-
// Check siblings before this node
|
|
44
|
-
const parent = current.parent;
|
|
45
|
-
if (!parent)
|
|
46
|
-
break;
|
|
47
|
-
if (parent.type === 'BlockStatement') {
|
|
48
|
-
const body = parent.body;
|
|
49
|
-
const currentIndex = body.indexOf(current);
|
|
50
|
-
// Check previous statements in the same block
|
|
51
|
-
for (let i = currentIndex - 1; i >= 0 && i >= currentIndex - 5; i--) {
|
|
52
|
-
const stmt = body[i];
|
|
53
|
-
const stmtText = sourceCode.getText(stmt);
|
|
54
|
-
if (validationPatterns.some(pattern => pattern.test(stmtText))) {
|
|
55
|
-
return true; // Found validation
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
current = parent;
|
|
60
|
-
depth++;
|
|
61
|
-
}
|
|
62
|
-
// No validation found
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
exports.noInsecureRedirects = (0, eslint_devkit_2.createRule)({
|
|
66
|
-
name: 'no-insecure-redirects',
|
|
67
|
-
meta: {
|
|
68
|
-
type: 'problem',
|
|
69
|
-
docs: {
|
|
70
|
-
description: 'Detects open redirect vulnerabilities',
|
|
71
|
-
},
|
|
72
|
-
hasSuggestions: true,
|
|
73
|
-
messages: {
|
|
74
|
-
insecureRedirect: (0, eslint_devkit_1.formatLLMMessage)({
|
|
75
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
76
|
-
issueName: 'Open redirect',
|
|
77
|
-
cwe: 'CWE-601',
|
|
78
|
-
description: 'Unvalidated redirect detected - user-controlled URL',
|
|
79
|
-
severity: 'HIGH',
|
|
80
|
-
fix: 'Whitelist allowed domains or validate redirect target',
|
|
81
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Unvalidated_Redirects_and_Forwards',
|
|
82
|
-
}),
|
|
83
|
-
whitelistDomains: (0, eslint_devkit_1.formatLLMMessage)({
|
|
84
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
85
|
-
issueName: 'Whitelist Domains',
|
|
86
|
-
description: 'Whitelist allowed redirect domains',
|
|
87
|
-
severity: 'LOW',
|
|
88
|
-
fix: 'if (allowedDomains.includes(url.hostname)) redirect(url)',
|
|
89
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Unvalidated_Redirects_and_Forwards',
|
|
90
|
-
}),
|
|
91
|
-
validateRedirect: (0, eslint_devkit_1.formatLLMMessage)({
|
|
92
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
93
|
-
issueName: 'Validate Redirect',
|
|
94
|
-
description: 'Validate redirect URL before use',
|
|
95
|
-
severity: 'LOW',
|
|
96
|
-
fix: 'validateRedirectUrl(userInput) before redirect',
|
|
97
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Unvalidated_Redirects_and_Forwards',
|
|
98
|
-
}),
|
|
99
|
-
useRelativeUrl: (0, eslint_devkit_1.formatLLMMessage)({
|
|
100
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
101
|
-
issueName: 'Use Relative URL',
|
|
102
|
-
description: 'Use relative URLs for internal redirects',
|
|
103
|
-
severity: 'LOW',
|
|
104
|
-
fix: 'redirect("/internal/path") instead of absolute URLs',
|
|
105
|
-
documentationLink: 'https://owasp.org/www-community/vulnerabilities/Unvalidated_Redirects_and_Forwards',
|
|
106
|
-
}),
|
|
107
|
-
},
|
|
108
|
-
schema: [
|
|
109
|
-
{
|
|
110
|
-
type: 'object',
|
|
111
|
-
properties: {
|
|
112
|
-
ignoreInTests: {
|
|
113
|
-
type: 'boolean',
|
|
114
|
-
default: true,
|
|
115
|
-
},
|
|
116
|
-
allowedDomains: {
|
|
117
|
-
type: 'array',
|
|
118
|
-
items: { type: 'string' },
|
|
119
|
-
default: [],
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
additionalProperties: false,
|
|
123
|
-
},
|
|
124
|
-
],
|
|
125
|
-
},
|
|
126
|
-
defaultOptions: [
|
|
127
|
-
{
|
|
128
|
-
ignoreInTests: true,
|
|
129
|
-
allowedDomains: [],
|
|
130
|
-
},
|
|
131
|
-
],
|
|
132
|
-
create(context, [options = {}]) {
|
|
133
|
-
const { ignoreInTests = true } = options || {};
|
|
134
|
-
const filename = context.getFilename();
|
|
135
|
-
const isTestFile = ignoreInTests && /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);
|
|
136
|
-
if (isTestFile) {
|
|
137
|
-
return {};
|
|
138
|
-
}
|
|
139
|
-
const sourceCode = context.sourceCode || context.sourceCode;
|
|
140
|
-
/**
|
|
141
|
-
* Check redirect calls and assignments
|
|
142
|
-
*/
|
|
143
|
-
function checkCallExpression(node) {
|
|
144
|
-
// Check for res.redirect, window.location, etc.
|
|
145
|
-
if (node.callee.type === 'MemberExpression' &&
|
|
146
|
-
node.callee.property.type === 'Identifier') {
|
|
147
|
-
const methodName = node.callee.property.name;
|
|
148
|
-
if (['redirect', 'replace', 'assign'].includes(methodName)) {
|
|
149
|
-
// Check if redirect URL is validated
|
|
150
|
-
if (!isRedirectValidated(node, sourceCode)) {
|
|
151
|
-
context.report({
|
|
152
|
-
node,
|
|
153
|
-
messageId: 'insecureRedirect',
|
|
154
|
-
suggest: [
|
|
155
|
-
{
|
|
156
|
-
messageId: 'whitelistDomains',
|
|
157
|
-
fix: () => null,
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
messageId: 'validateRedirect',
|
|
161
|
-
fix: () => null,
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
messageId: 'useRelativeUrl',
|
|
165
|
-
fix: () => null,
|
|
166
|
-
},
|
|
167
|
-
],
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Check assignment expressions like window.location.href = ...
|
|
175
|
-
*/
|
|
176
|
-
function checkAssignmentExpression(node) {
|
|
177
|
-
// Check for window.location.href assignments
|
|
178
|
-
if (node.left.type === 'MemberExpression' &&
|
|
179
|
-
node.left.object.type === 'MemberExpression' &&
|
|
180
|
-
node.left.object.object.type === 'Identifier' &&
|
|
181
|
-
node.left.object.object.name === 'window' &&
|
|
182
|
-
node.left.object.property.type === 'Identifier' &&
|
|
183
|
-
node.left.object.property.name === 'location' &&
|
|
184
|
-
node.left.property.type === 'Identifier' &&
|
|
185
|
-
['href', 'replace', 'assign'].includes(node.left.property.name)) {
|
|
186
|
-
// Check if assignment value comes from user input
|
|
187
|
-
const rightText = sourceCode.getText(node.right);
|
|
188
|
-
const userInputPattern = /\b(req\.(query|body|params)|window\.location|document\.location)\b/;
|
|
189
|
-
if (userInputPattern.test(rightText)) {
|
|
190
|
-
context.report({
|
|
191
|
-
node,
|
|
192
|
-
messageId: 'insecureRedirect',
|
|
193
|
-
suggest: [
|
|
194
|
-
{
|
|
195
|
-
messageId: 'whitelistDomains',
|
|
196
|
-
fix: () => null,
|
|
197
|
-
},
|
|
198
|
-
{
|
|
199
|
-
messageId: 'validateRedirect',
|
|
200
|
-
fix: () => null,
|
|
201
|
-
},
|
|
202
|
-
{
|
|
203
|
-
messageId: 'useRelativeUrl',
|
|
204
|
-
fix: () => null,
|
|
205
|
-
},
|
|
206
|
-
],
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return {
|
|
212
|
-
CallExpression: checkCallExpression,
|
|
213
|
-
AssignmentExpression: checkAssignmentExpression,
|
|
214
|
-
};
|
|
215
|
-
},
|
|
216
|
-
});
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Require secure WebSocket connections (wss://)
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.noInsecureWebsocket = void 0;
|
|
7
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
8
|
-
exports.noInsecureWebsocket = (0, eslint_devkit_1.createRule)({
|
|
9
|
-
name: 'no-insecure-websocket',
|
|
10
|
-
meta: {
|
|
11
|
-
type: 'problem',
|
|
12
|
-
docs: {
|
|
13
|
-
description: 'Require secure WebSocket connections (wss://)',
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
18
|
-
issueName: 'Insecure WebSocket',
|
|
19
|
-
cwe: 'CWE-319',
|
|
20
|
-
description: 'Insecure WebSocket connection (ws://) - data transmitted in clear text',
|
|
21
|
-
severity: 'HIGH',
|
|
22
|
-
fix: 'Use wss:// instead of ws:// for secure WebSocket connections',
|
|
23
|
-
documentationLink: 'https://cwe.mitre.org/data/definitions/319.html',
|
|
24
|
-
})
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
},
|
|
28
|
-
defaultOptions: [],
|
|
29
|
-
create(context) {
|
|
30
|
-
function report(node) {
|
|
31
|
-
context.report({ node, messageId: 'violationDetected' });
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
NewExpression(node) {
|
|
35
|
-
// Check for new WebSocket('ws://...')
|
|
36
|
-
if (node.callee.type === 'Identifier' && node.callee.name === 'WebSocket') {
|
|
37
|
-
const urlArg = node.arguments[0];
|
|
38
|
-
// Check literal string
|
|
39
|
-
if (urlArg && urlArg.type === 'Literal' &&
|
|
40
|
-
typeof urlArg.value === 'string' &&
|
|
41
|
-
urlArg.value.startsWith('ws://')) {
|
|
42
|
-
report(node);
|
|
43
|
-
}
|
|
44
|
-
// Check template literal
|
|
45
|
-
if (urlArg && urlArg.type === 'TemplateLiteral') {
|
|
46
|
-
const text = context.sourceCode.getText(urlArg);
|
|
47
|
-
if (text.includes('ws://')) {
|
|
48
|
-
report(node);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
Literal(node) {
|
|
54
|
-
// Check for ws:// URLs in string literals
|
|
55
|
-
if (typeof node.value === 'string' && node.value.startsWith('ws://')) {
|
|
56
|
-
report(node);
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
},
|
|
61
|
-
});
|