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,560 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.detectObjectInjection = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* ESLint Rule: detect-object-injection
|
|
6
|
-
* Detects variable[key] as a left- or right-hand assignment operand (prototype pollution)
|
|
7
|
-
* LLM-optimized with comprehensive object injection prevention guidance
|
|
8
|
-
*
|
|
9
|
-
* Type-Aware Enhancement:
|
|
10
|
-
* This rule uses TypeScript type information when available to reduce false positives.
|
|
11
|
-
* If a property key is constrained to a union of string literals (e.g., 'name' | 'email'),
|
|
12
|
-
* the access is considered safe because the values are statically known at compile time.
|
|
13
|
-
*
|
|
14
|
-
* @see https://portswigger.net/web-security/prototype-pollution
|
|
15
|
-
* @see https://cwe.mitre.org/data/definitions/915.html
|
|
16
|
-
*/
|
|
17
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
18
|
-
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
19
|
-
const eslint_devkit_3 = require("@interlace/eslint-devkit");
|
|
20
|
-
const OBJECT_INJECTION_PATTERNS = [
|
|
21
|
-
{
|
|
22
|
-
pattern: '__proto__',
|
|
23
|
-
dangerous: true,
|
|
24
|
-
vulnerability: 'prototype-pollution',
|
|
25
|
-
safeAlternative: 'Object.create(null) or Map',
|
|
26
|
-
example: {
|
|
27
|
-
bad: 'obj[userInput] = value; // if userInput is "__proto__"',
|
|
28
|
-
good: 'const map = new Map(); map.set(userInput, value);'
|
|
29
|
-
},
|
|
30
|
-
effort: '15-20 minutes',
|
|
31
|
-
riskLevel: 'critical'
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
pattern: 'prototype',
|
|
35
|
-
dangerous: true,
|
|
36
|
-
vulnerability: 'prototype-pollution',
|
|
37
|
-
safeAlternative: 'Avoid prototype manipulation',
|
|
38
|
-
example: {
|
|
39
|
-
bad: 'obj[userInput] = value; // if userInput is "prototype"',
|
|
40
|
-
good: 'if (!obj.hasOwnProperty(userInput)) obj[userInput] = value;'
|
|
41
|
-
},
|
|
42
|
-
effort: '10-15 minutes',
|
|
43
|
-
riskLevel: 'high'
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
pattern: 'constructor',
|
|
47
|
-
dangerous: true,
|
|
48
|
-
vulnerability: 'method-injection',
|
|
49
|
-
safeAlternative: 'Validate property names against whitelist',
|
|
50
|
-
example: {
|
|
51
|
-
bad: 'obj[userInput] = value; // if userInput is "constructor"',
|
|
52
|
-
good: 'const ALLOWED_KEYS = [\'name\', \'age\', \'email\']; if (ALLOWED_KEYS.includes(userInput)) obj[userInput] = value;'
|
|
53
|
-
},
|
|
54
|
-
effort: '10-15 minutes',
|
|
55
|
-
riskLevel: 'medium'
|
|
56
|
-
}
|
|
57
|
-
];
|
|
58
|
-
exports.detectObjectInjection = (0, eslint_devkit_3.createRule)({
|
|
59
|
-
name: 'detect-object-injection',
|
|
60
|
-
meta: {
|
|
61
|
-
type: 'problem',
|
|
62
|
-
docs: {
|
|
63
|
-
description: 'Detects variable[key] as a left- or right-hand assignment operand',
|
|
64
|
-
},
|
|
65
|
-
messages: {
|
|
66
|
-
// 🎯 Token optimization: 37% reduction (54→34 tokens) - removes verbose current/fix/doc labels
|
|
67
|
-
objectInjection: (0, eslint_devkit_2.formatLLMMessage)({
|
|
68
|
-
icon: eslint_devkit_2.MessageIcons.WARNING,
|
|
69
|
-
issueName: 'Object injection',
|
|
70
|
-
cwe: 'CWE-915',
|
|
71
|
-
description: 'Object injection/Prototype pollution (incl. model/tool outputs)',
|
|
72
|
-
severity: '{{riskLevel}}',
|
|
73
|
-
fix: '{{safeAlternative}}',
|
|
74
|
-
documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
|
|
75
|
-
}),
|
|
76
|
-
useMapInstead: (0, eslint_devkit_2.formatLLMMessage)({
|
|
77
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
78
|
-
issueName: 'Use Map',
|
|
79
|
-
description: 'Use Map instead of plain objects',
|
|
80
|
-
severity: 'LOW',
|
|
81
|
-
fix: 'const map = new Map(); map.set(key, value);',
|
|
82
|
-
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map',
|
|
83
|
-
}),
|
|
84
|
-
useHasOwnProperty: (0, eslint_devkit_2.formatLLMMessage)({
|
|
85
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
86
|
-
issueName: 'Use hasOwnProperty',
|
|
87
|
-
description: 'Check hasOwnProperty to avoid prototype properties',
|
|
88
|
-
severity: 'LOW',
|
|
89
|
-
fix: 'if (obj.hasOwnProperty(key)) { obj[key] = value; }',
|
|
90
|
-
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty',
|
|
91
|
-
}),
|
|
92
|
-
whitelistKeys: (0, eslint_devkit_2.formatLLMMessage)({
|
|
93
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
94
|
-
issueName: 'Whitelist Keys',
|
|
95
|
-
description: 'Whitelist allowed property names',
|
|
96
|
-
severity: 'LOW',
|
|
97
|
-
fix: 'const ALLOWED = ["name", "email"]; if (ALLOWED.includes(key)) obj[key] = value; // reject model/tool-supplied unknown keys',
|
|
98
|
-
documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
|
|
99
|
-
}),
|
|
100
|
-
useObjectCreate: (0, eslint_devkit_2.formatLLMMessage)({
|
|
101
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
102
|
-
issueName: 'Use Object.create(null)',
|
|
103
|
-
description: 'Create clean objects without prototypes',
|
|
104
|
-
severity: 'LOW',
|
|
105
|
-
fix: 'const obj = Object.create(null);',
|
|
106
|
-
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create',
|
|
107
|
-
}),
|
|
108
|
-
freezePrototypes: (0, eslint_devkit_2.formatLLMMessage)({
|
|
109
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
110
|
-
issueName: 'Freeze Prototypes',
|
|
111
|
-
description: 'Freeze Object.prototype to prevent pollution',
|
|
112
|
-
severity: 'LOW',
|
|
113
|
-
fix: 'Object.freeze(Object.prototype);',
|
|
114
|
-
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze',
|
|
115
|
-
}),
|
|
116
|
-
strategyValidate: (0, eslint_devkit_2.formatLLMMessage)({
|
|
117
|
-
icon: eslint_devkit_2.MessageIcons.STRATEGY,
|
|
118
|
-
issueName: 'Validate Input',
|
|
119
|
-
description: 'Add input validation before property access',
|
|
120
|
-
severity: 'LOW',
|
|
121
|
-
fix: 'Validate key against allowed values before access',
|
|
122
|
-
documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
|
|
123
|
-
}),
|
|
124
|
-
strategyWhitelist: (0, eslint_devkit_2.formatLLMMessage)({
|
|
125
|
-
icon: eslint_devkit_2.MessageIcons.STRATEGY,
|
|
126
|
-
issueName: 'Whitelist Properties',
|
|
127
|
-
description: 'Whitelist allowed property names only',
|
|
128
|
-
severity: 'LOW',
|
|
129
|
-
fix: 'Define allowed keys and validate against them',
|
|
130
|
-
documentationLink: 'https://portswigger.net/web-security/prototype-pollution',
|
|
131
|
-
}),
|
|
132
|
-
strategyFreeze: (0, eslint_devkit_2.formatLLMMessage)({
|
|
133
|
-
icon: eslint_devkit_2.MessageIcons.STRATEGY,
|
|
134
|
-
issueName: 'Freeze Prototypes',
|
|
135
|
-
description: 'Freeze prototypes to prevent pollution',
|
|
136
|
-
severity: 'LOW',
|
|
137
|
-
fix: 'Object.freeze(Object.prototype) at app startup',
|
|
138
|
-
documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze',
|
|
139
|
-
})
|
|
140
|
-
},
|
|
141
|
-
schema: [
|
|
142
|
-
{
|
|
143
|
-
type: 'object',
|
|
144
|
-
properties: {
|
|
145
|
-
allowLiterals: {
|
|
146
|
-
type: 'boolean',
|
|
147
|
-
default: false,
|
|
148
|
-
description: 'Allow bracket notation with literal strings'
|
|
149
|
-
},
|
|
150
|
-
additionalMethods: {
|
|
151
|
-
type: 'array',
|
|
152
|
-
items: { type: 'string' },
|
|
153
|
-
default: [],
|
|
154
|
-
description: 'Additional object methods to check for injection'
|
|
155
|
-
},
|
|
156
|
-
dangerousProperties: {
|
|
157
|
-
type: 'array',
|
|
158
|
-
items: { type: 'string' },
|
|
159
|
-
default: ['__proto__', 'prototype', 'constructor'],
|
|
160
|
-
description: 'Properties to consider dangerous'
|
|
161
|
-
},
|
|
162
|
-
strategy: {
|
|
163
|
-
type: 'string',
|
|
164
|
-
enum: ['validate', 'whitelist', 'freeze', 'auto'],
|
|
165
|
-
default: 'auto',
|
|
166
|
-
description: 'Strategy for fixing object injection (auto = smart detection)'
|
|
167
|
-
}
|
|
168
|
-
},
|
|
169
|
-
additionalProperties: false,
|
|
170
|
-
},
|
|
171
|
-
],
|
|
172
|
-
},
|
|
173
|
-
defaultOptions: [
|
|
174
|
-
{
|
|
175
|
-
allowLiterals: false,
|
|
176
|
-
additionalMethods: [],
|
|
177
|
-
dangerousProperties: ['__proto__', 'prototype', 'constructor'],
|
|
178
|
-
strategy: 'auto'
|
|
179
|
-
},
|
|
180
|
-
],
|
|
181
|
-
create(context) {
|
|
182
|
-
const options = context.options[0] || {};
|
|
183
|
-
const { allowLiterals = false, dangerousProperties = ['__proto__', 'prototype', 'constructor'], } = options || {};
|
|
184
|
-
// Track MemberExpressions that are part of AssignmentExpressions to avoid double-reporting
|
|
185
|
-
const handledMemberExpressions = new WeakSet();
|
|
186
|
-
// Check if TypeScript parser services are available for type-aware checking
|
|
187
|
-
const hasTypeInfo = (0, eslint_devkit_2.hasParserServices)(context);
|
|
188
|
-
const parserServices = hasTypeInfo ? (0, eslint_devkit_2.getParserServices)(context) : null;
|
|
189
|
-
/**
|
|
190
|
-
* Check if a node is a literal string (potentially safe)
|
|
191
|
-
*/
|
|
192
|
-
const isLiteralString = (node) => {
|
|
193
|
-
return node.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof node.value === 'string';
|
|
194
|
-
};
|
|
195
|
-
/**
|
|
196
|
-
* Check if a property is part of a typed union (safe access)
|
|
197
|
-
*
|
|
198
|
-
* Type-Aware Enhancement:
|
|
199
|
-
* When TypeScript parser services are available, we can check if a variable
|
|
200
|
-
* is typed as a union of string literals (e.g., 'name' | 'email').
|
|
201
|
-
* Such accesses are safe because the values are statically constrained.
|
|
202
|
-
*
|
|
203
|
-
* @example
|
|
204
|
-
* // This is now detected as SAFE (no false positive):
|
|
205
|
-
* const key: 'name' | 'email' = getKey();
|
|
206
|
-
* obj[key] = value;
|
|
207
|
-
*
|
|
208
|
-
* // This is still detected as DANGEROUS:
|
|
209
|
-
* const key: string = getUserInput();
|
|
210
|
-
* obj[key] = value;
|
|
211
|
-
*/
|
|
212
|
-
const isTypedUnionAccess = (propertyNode) => {
|
|
213
|
-
// Check if property is a literal string (typed access like obj['name'])
|
|
214
|
-
if (isLiteralString(propertyNode)) {
|
|
215
|
-
return true; // Literal strings are safe - they're typed at compile time
|
|
216
|
-
}
|
|
217
|
-
// Type-aware check: If we have TypeScript type information, check if the
|
|
218
|
-
// property key is constrained to a union of safe string literals
|
|
219
|
-
/* c8 ignore start -- TypeScript parser services often unavailable in RuleTester */
|
|
220
|
-
if (parserServices && propertyNode.type === eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
221
|
-
try {
|
|
222
|
-
const type = (0, eslint_devkit_2.getTypeOfNode)(propertyNode, parserServices);
|
|
223
|
-
// Check if the type is a union of safe string literals
|
|
224
|
-
// (excludes '__proto__', 'prototype', 'constructor')
|
|
225
|
-
if ((0, eslint_devkit_2.isUnionOfSafeStringLiterals)(type, dangerousProperties)) {
|
|
226
|
-
return true; // Safe - statically constrained to safe values
|
|
227
|
-
}
|
|
228
|
-
// Also check for single string literal type (e.g., const key: 'name' = ...)
|
|
229
|
-
const literalValues = (0, eslint_devkit_2.getStringLiteralValues)(type);
|
|
230
|
-
if (literalValues && literalValues.length === 1) {
|
|
231
|
-
// Single literal - safe if not dangerous
|
|
232
|
-
if (!dangerousProperties.includes(literalValues[0])) {
|
|
233
|
-
return true;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
catch {
|
|
238
|
-
// If type checking fails, fall back to treating as potentially dangerous
|
|
239
|
-
// This can happen with malformed AST or missing type information
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
/* c8 ignore stop */
|
|
243
|
-
// Without type information, treat all identifiers as potentially dangerous
|
|
244
|
-
return false;
|
|
245
|
-
};
|
|
246
|
-
/**
|
|
247
|
-
* Check if the property key has been validated before use.
|
|
248
|
-
*
|
|
249
|
-
* Detects patterns like:
|
|
250
|
-
* - if (ARRAY.includes(key)) { obj[key] = value; }
|
|
251
|
-
* - if (Object.prototype.hasOwnProperty.call(obj, key)) { return obj[key]; }
|
|
252
|
-
* - if (Object.hasOwn(obj, key)) { return obj[key]; }
|
|
253
|
-
*
|
|
254
|
-
* @param propertyNode - The property node (key in obj[key])
|
|
255
|
-
* @param node - The current node being checked
|
|
256
|
-
* @returns true if the key has been validated, false otherwise
|
|
257
|
-
*/
|
|
258
|
-
const hasPrecedingValidation = (propertyNode, node) => {
|
|
259
|
-
// Only check for identifier keys (obj[key] where key is a variable)
|
|
260
|
-
if (propertyNode.type !== eslint_devkit_1.AST_NODE_TYPES.Identifier) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
const keyName = propertyNode.name;
|
|
264
|
-
// AST-based validation detection (faster than getText + regex)
|
|
265
|
-
const isIncludesCall = (testNode) => {
|
|
266
|
-
// Pattern: ARRAY.includes(keyName)
|
|
267
|
-
if (testNode.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
|
|
268
|
-
testNode.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
269
|
-
testNode.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
270
|
-
testNode.callee.property.name === 'includes' &&
|
|
271
|
-
testNode.arguments.length > 0 &&
|
|
272
|
-
testNode.arguments[0].type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
273
|
-
testNode.arguments[0].name === keyName) {
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
// Handle negation: !ARRAY.includes(key)
|
|
277
|
-
if (testNode.type === eslint_devkit_1.AST_NODE_TYPES.UnaryExpression &&
|
|
278
|
-
testNode.operator === '!' &&
|
|
279
|
-
testNode.argument.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression) {
|
|
280
|
-
return isIncludesCall(testNode.argument);
|
|
281
|
-
}
|
|
282
|
-
return false;
|
|
283
|
-
};
|
|
284
|
-
const isHasOwnPropertyCall = (testNode) => {
|
|
285
|
-
// Pattern: Object.prototype.hasOwnProperty.call(obj, key) OR obj.hasOwnProperty(key) OR Object.hasOwn(obj, key)
|
|
286
|
-
if (testNode.type !== eslint_devkit_1.AST_NODE_TYPES.CallExpression)
|
|
287
|
-
return false;
|
|
288
|
-
const callee = testNode.callee;
|
|
289
|
-
const args = testNode.arguments;
|
|
290
|
-
// Object.prototype.hasOwnProperty.call(obj, key)
|
|
291
|
-
if (callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
292
|
-
callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
293
|
-
callee.property.name === 'call' &&
|
|
294
|
-
args.length >= 2 &&
|
|
295
|
-
args[1].type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
296
|
-
args[1].name === keyName) {
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
// obj.hasOwnProperty(key) OR Object.hasOwn(obj, key)
|
|
300
|
-
if (callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
|
|
301
|
-
callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
302
|
-
(callee.property.name === 'hasOwnProperty' || callee.property.name === 'hasOwn')) {
|
|
303
|
-
const keyArg = callee.property.name === 'hasOwn' ? args[1] : args[0];
|
|
304
|
-
if (keyArg?.type === eslint_devkit_1.AST_NODE_TYPES.Identifier && keyArg.name === keyName) {
|
|
305
|
-
return true;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return false;
|
|
309
|
-
};
|
|
310
|
-
const isInOperator = (testNode) => {
|
|
311
|
-
// Pattern: key in obj
|
|
312
|
-
return testNode.type === eslint_devkit_1.AST_NODE_TYPES.BinaryExpression &&
|
|
313
|
-
testNode.operator === 'in' &&
|
|
314
|
-
testNode.left.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
315
|
-
testNode.left.name === keyName;
|
|
316
|
-
};
|
|
317
|
-
const hasValidation = (testNode) => {
|
|
318
|
-
return isIncludesCall(testNode) || isHasOwnPropertyCall(testNode) || isInOperator(testNode);
|
|
319
|
-
};
|
|
320
|
-
const hasEarlyExit = (consequent) => {
|
|
321
|
-
// Check if block contains throw or return
|
|
322
|
-
if (consequent.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement) {
|
|
323
|
-
return consequent.body.some(stmt => stmt.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement ||
|
|
324
|
-
stmt.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement);
|
|
325
|
-
}
|
|
326
|
-
return consequent.type === eslint_devkit_1.AST_NODE_TYPES.ThrowStatement ||
|
|
327
|
-
consequent.type === eslint_devkit_1.AST_NODE_TYPES.ReturnStatement;
|
|
328
|
-
};
|
|
329
|
-
// Walk up to find enclosing IfStatement with validation
|
|
330
|
-
let current = node.parent;
|
|
331
|
-
let foundFunctionBody = false;
|
|
332
|
-
while (current && !foundFunctionBody) {
|
|
333
|
-
// Check if we're inside an if-block with validation in the condition
|
|
334
|
-
if (current.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement) {
|
|
335
|
-
if (hasValidation(current.test)) {
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
// Check for function body - look for preceding sibling if-statements with early exit
|
|
340
|
-
if (current.type === eslint_devkit_1.AST_NODE_TYPES.BlockStatement && current.parent && (current.parent.type === eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration ||
|
|
341
|
-
current.parent.type === eslint_devkit_1.AST_NODE_TYPES.FunctionExpression ||
|
|
342
|
-
current.parent.type === eslint_devkit_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
|
|
343
|
-
foundFunctionBody = true;
|
|
344
|
-
const blockBody = current.body;
|
|
345
|
-
const nodeIndex = blockBody.findIndex((stmt) => {
|
|
346
|
-
let check = node;
|
|
347
|
-
while (check) {
|
|
348
|
-
if (check === stmt)
|
|
349
|
-
return true;
|
|
350
|
-
check = check.parent;
|
|
351
|
-
}
|
|
352
|
-
return false;
|
|
353
|
-
});
|
|
354
|
-
// Look at preceding statements for validation patterns with early exit
|
|
355
|
-
for (let i = 0; i < nodeIndex; i++) {
|
|
356
|
-
const stmt = blockBody[i];
|
|
357
|
-
if (stmt.type === eslint_devkit_1.AST_NODE_TYPES.IfStatement &&
|
|
358
|
-
hasValidation(stmt.test) &&
|
|
359
|
-
hasEarlyExit(stmt.consequent)) {
|
|
360
|
-
return true;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
current = current.parent;
|
|
365
|
-
}
|
|
366
|
-
return false;
|
|
367
|
-
};
|
|
368
|
-
/**
|
|
369
|
-
* Check if property access is potentially dangerous
|
|
370
|
-
*/
|
|
371
|
-
const isDangerousPropertyAccess = (propertyNode) => {
|
|
372
|
-
// SAFE: Numeric literals (array index access like items[0], items[1])
|
|
373
|
-
if (propertyNode.type === eslint_devkit_1.AST_NODE_TYPES.Literal && typeof propertyNode.value === 'number') {
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
// Check if it's a literal string first
|
|
377
|
-
if (isLiteralString(propertyNode)) {
|
|
378
|
-
const propName = String(propertyNode.value);
|
|
379
|
-
// DANGEROUS: Literal strings that match dangerous properties (always flag these)
|
|
380
|
-
// Check this BEFORE checking typed union access
|
|
381
|
-
if (dangerousProperties.includes(propName)) {
|
|
382
|
-
return true;
|
|
383
|
-
}
|
|
384
|
-
// SAFE: Typed union access (obj[typedKey] where typedKey is 'primary' | 'secondary')
|
|
385
|
-
// Only safe if it's NOT a dangerous property
|
|
386
|
-
if (isTypedUnionAccess(propertyNode)) {
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
// SAFE: Literal strings that are NOT dangerous properties (if allowLiterals is true)
|
|
390
|
-
if (allowLiterals) {
|
|
391
|
-
return false;
|
|
392
|
-
}
|
|
393
|
-
// If allowLiterals is false, non-dangerous literal strings are still considered safe
|
|
394
|
-
// (they're static and known at compile time)
|
|
395
|
-
return false;
|
|
396
|
-
}
|
|
397
|
-
// DANGEROUS: Any untyped/dynamic property access (e.g., obj[userInput])
|
|
398
|
-
return true;
|
|
399
|
-
};
|
|
400
|
-
/**
|
|
401
|
-
* Extract property access information
|
|
402
|
-
*/
|
|
403
|
-
const extractPropertyAccess = (node) => {
|
|
404
|
-
const sourceCode = context.sourceCode || context.sourceCode;
|
|
405
|
-
let object;
|
|
406
|
-
let property;
|
|
407
|
-
let propertyNode;
|
|
408
|
-
let isAssignment = false;
|
|
409
|
-
if (node.type === eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression && node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
410
|
-
// Assignment: obj[key] = value
|
|
411
|
-
object = sourceCode.getText(node.left.object);
|
|
412
|
-
property = sourceCode.getText(node.left.property);
|
|
413
|
-
propertyNode = node.left.property;
|
|
414
|
-
isAssignment = true;
|
|
415
|
-
}
|
|
416
|
-
else if (node.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
417
|
-
// Access: obj[key]
|
|
418
|
-
object = sourceCode.getText(node.object);
|
|
419
|
-
property = sourceCode.getText(node.property);
|
|
420
|
-
propertyNode = node.property;
|
|
421
|
-
isAssignment = false;
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
return { object: '', property: '', propertyNode: node, isAssignment: false, pattern: null };
|
|
425
|
-
}
|
|
426
|
-
// Check if property matches dangerous patterns
|
|
427
|
-
const pattern = OBJECT_INJECTION_PATTERNS.find(p => new RegExp(p.pattern, 'i').test(property) ||
|
|
428
|
-
dangerousProperties.includes(property.replace(/['"]/g, ''))) || null;
|
|
429
|
-
return { object, property, propertyNode, isAssignment, pattern };
|
|
430
|
-
};
|
|
431
|
-
/**
|
|
432
|
-
* Determine if this is a high-risk assignment
|
|
433
|
-
*/
|
|
434
|
-
const isHighRiskAssignment = (node) => {
|
|
435
|
-
if (node.left.type !== 'MemberExpression') {
|
|
436
|
-
return false;
|
|
437
|
-
}
|
|
438
|
-
// Only check computed member access (bracket notation)
|
|
439
|
-
// Dot notation (obj.name) is safe
|
|
440
|
-
if (!node.left.computed) {
|
|
441
|
-
return false;
|
|
442
|
-
}
|
|
443
|
-
const { propertyNode } = extractPropertyAccess(node);
|
|
444
|
-
// Skip if the key has been validated (e.g., includes() or hasOwnProperty check)
|
|
445
|
-
if (hasPrecedingValidation(propertyNode, node)) {
|
|
446
|
-
return false;
|
|
447
|
-
}
|
|
448
|
-
// Check for dangerous property access in assignment
|
|
449
|
-
return isDangerousPropertyAccess(propertyNode);
|
|
450
|
-
};
|
|
451
|
-
/**
|
|
452
|
-
* Determine if this is a high-risk member access
|
|
453
|
-
*/
|
|
454
|
-
const isHighRiskMemberAccess = (node) => {
|
|
455
|
-
// Only check computed member access (bracket notation)
|
|
456
|
-
if (!node.computed) {
|
|
457
|
-
return false;
|
|
458
|
-
}
|
|
459
|
-
const { propertyNode } = extractPropertyAccess(node);
|
|
460
|
-
// Skip if the key has been validated (e.g., includes() or hasOwnProperty check)
|
|
461
|
-
if (hasPrecedingValidation(propertyNode, node)) {
|
|
462
|
-
return false;
|
|
463
|
-
}
|
|
464
|
-
// Check for dangerous property access
|
|
465
|
-
return isDangerousPropertyAccess(propertyNode);
|
|
466
|
-
};
|
|
467
|
-
/**
|
|
468
|
-
* Determine risk level based on the pattern and context
|
|
469
|
-
*/
|
|
470
|
-
const determineRiskLevel = (pattern, isAssignment) => {
|
|
471
|
-
if (pattern?.riskLevel === 'critical' || (pattern && isAssignment)) {
|
|
472
|
-
return 'CRITICAL';
|
|
473
|
-
}
|
|
474
|
-
if (pattern?.riskLevel === 'high' || isAssignment) {
|
|
475
|
-
return 'HIGH';
|
|
476
|
-
}
|
|
477
|
-
return 'MEDIUM';
|
|
478
|
-
};
|
|
479
|
-
/**
|
|
480
|
-
* Check assignment expressions for object injection
|
|
481
|
-
*/
|
|
482
|
-
const checkAssignmentExpression = (node) => {
|
|
483
|
-
if (!isHighRiskAssignment(node)) {
|
|
484
|
-
return;
|
|
485
|
-
}
|
|
486
|
-
// Mark the MemberExpression as handled to avoid double-reporting
|
|
487
|
-
if (node.left.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression) {
|
|
488
|
-
handledMemberExpressions.add(node.left);
|
|
489
|
-
}
|
|
490
|
-
const { object, property, isAssignment, pattern } = extractPropertyAccess(node);
|
|
491
|
-
const riskLevel = determineRiskLevel(pattern, isAssignment);
|
|
492
|
-
context.report({
|
|
493
|
-
node,
|
|
494
|
-
messageId: 'objectInjection',
|
|
495
|
-
data: {
|
|
496
|
-
pattern: `${object}[${property}]`,
|
|
497
|
-
riskLevel,
|
|
498
|
-
vulnerability: pattern?.vulnerability || 'object injection',
|
|
499
|
-
safeAlternative: pattern?.safeAlternative || 'Use Map or property whitelisting',
|
|
500
|
-
},
|
|
501
|
-
suggest: [
|
|
502
|
-
{
|
|
503
|
-
messageId: 'useMapInstead',
|
|
504
|
-
fix: () => null
|
|
505
|
-
},
|
|
506
|
-
{
|
|
507
|
-
messageId: 'useHasOwnProperty',
|
|
508
|
-
fix: () => null
|
|
509
|
-
},
|
|
510
|
-
{
|
|
511
|
-
messageId: 'whitelistKeys',
|
|
512
|
-
fix: () => null
|
|
513
|
-
},
|
|
514
|
-
{
|
|
515
|
-
messageId: 'useObjectCreate',
|
|
516
|
-
fix: () => null
|
|
517
|
-
},
|
|
518
|
-
{
|
|
519
|
-
messageId: 'freezePrototypes',
|
|
520
|
-
fix: () => null
|
|
521
|
-
}
|
|
522
|
-
]
|
|
523
|
-
});
|
|
524
|
-
};
|
|
525
|
-
/**
|
|
526
|
-
* Check member expressions for object injection
|
|
527
|
-
*/
|
|
528
|
-
const checkMemberExpression = (node) => {
|
|
529
|
-
if (!isHighRiskMemberAccess(node)) {
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
// Skip if this MemberExpression was already handled as part of an AssignmentExpression
|
|
533
|
-
if (handledMemberExpressions.has(node)) {
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
// Also check parent - if it's an AssignmentExpression and this node is the left side, skip
|
|
537
|
-
// (This handles cases where WeakSet check didn't work due to visitor order)
|
|
538
|
-
const parent = node.parent;
|
|
539
|
-
if (parent && parent.type === eslint_devkit_1.AST_NODE_TYPES.AssignmentExpression && parent.left === node) {
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
const { object, property, isAssignment, pattern } = extractPropertyAccess(node);
|
|
543
|
-
const riskLevel = determineRiskLevel(pattern, isAssignment);
|
|
544
|
-
context.report({
|
|
545
|
-
node,
|
|
546
|
-
messageId: 'objectInjection',
|
|
547
|
-
data: {
|
|
548
|
-
pattern: `${object}[${property}]`,
|
|
549
|
-
riskLevel,
|
|
550
|
-
vulnerability: pattern?.vulnerability || 'object injection',
|
|
551
|
-
safeAlternative: pattern?.safeAlternative || 'Use Map or property whitelisting',
|
|
552
|
-
}
|
|
553
|
-
});
|
|
554
|
-
};
|
|
555
|
-
return {
|
|
556
|
-
AssignmentExpression: checkAssignmentExpression,
|
|
557
|
-
MemberExpression: checkMemberExpression
|
|
558
|
-
};
|
|
559
|
-
},
|
|
560
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Detect potential typosquatting in dependencies
|
|
3
|
-
* @see https://owasp.org/www-project-mobile-top-10/
|
|
4
|
-
* @see https://cwe.mitre.org/data/definitions/506.html
|
|
5
|
-
*/
|
|
6
|
-
export interface Options {
|
|
7
|
-
}
|
|
8
|
-
export declare const detectSuspiciousDependencies: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* @fileoverview Detect potential typosquatting in dependencies
|
|
4
|
-
* @see https://owasp.org/www-project-mobile-top-10/
|
|
5
|
-
* @see https://cwe.mitre.org/data/definitions/506.html
|
|
6
|
-
*/
|
|
7
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.detectSuspiciousDependencies = void 0;
|
|
9
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
exports.detectSuspiciousDependencies = (0, eslint_devkit_1.createRule)({
|
|
11
|
-
name: 'detect-suspicious-dependencies',
|
|
12
|
-
meta: {
|
|
13
|
-
type: 'problem',
|
|
14
|
-
docs: {
|
|
15
|
-
description: 'Detect typosquatting in package names',
|
|
16
|
-
},
|
|
17
|
-
messages: {
|
|
18
|
-
violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
|
|
19
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
20
|
-
issueName: 'Suspicious Dependency',
|
|
21
|
-
cwe: 'CWE-506',
|
|
22
|
-
description: 'Suspicious package name detected - possible typosquatting',
|
|
23
|
-
severity: 'HIGH',
|
|
24
|
-
fix: 'Verify package authenticity on npm registry',
|
|
25
|
-
documentationLink: 'https://cwe.mitre.org/data/definitions/506.html',
|
|
26
|
-
})
|
|
27
|
-
},
|
|
28
|
-
schema: [],
|
|
29
|
-
},
|
|
30
|
-
defaultOptions: [],
|
|
31
|
-
create(context) {
|
|
32
|
-
const popularPackages = ['react', 'lodash', 'express', 'axios', 'webpack'];
|
|
33
|
-
function levenshtein(a, b) {
|
|
34
|
-
const matrix = [];
|
|
35
|
-
for (let i = 0; i <= b.length; i++) {
|
|
36
|
-
matrix[i] = [i];
|
|
37
|
-
}
|
|
38
|
-
for (let j = 0; j <= a.length; j++) {
|
|
39
|
-
matrix[0][j] = j;
|
|
40
|
-
}
|
|
41
|
-
for (let i = 1; i <= b.length; i++) {
|
|
42
|
-
for (let j = 1; j <= a.length; j++) {
|
|
43
|
-
if (b.charAt(i - 1) === a.charAt(j - 1)) {
|
|
44
|
-
matrix[i][j] = matrix[i - 1][j - 1];
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return matrix[b.length][a.length];
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
ImportDeclaration(node) {
|
|
55
|
-
const source = node.source.value;
|
|
56
|
-
if (typeof source === 'string' && !source.startsWith('.') && !source.startsWith('@')) {
|
|
57
|
-
for (const popular of popularPackages) {
|
|
58
|
-
const distance = levenshtein(source, popular);
|
|
59
|
-
if (distance > 0 && distance <= 2) {
|
|
60
|
-
context.report({
|
|
61
|
-
node,
|
|
62
|
-
messageId: 'violationDetected',
|
|
63
|
-
data: { name: source, similar: popular },
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
},
|
|
71
|
-
});
|