@sun-asterisk/sunlint 1.3.39 → 1.3.41
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/config/rules/rules-registry-generated.json +134 -108
- package/core/rule-selection-service.js +11 -0
- package/docs/GENERATED_FILES_QUICK_REFERENCE.md +96 -0
- package/docs/GENERATED_FILE_HANDLING_SUMMARY.md +152 -0
- package/docs/skills/CREATE_NEW_DART_RULE.md +161 -14
- package/origin-rules/dart-en.md +151 -163
- package/package.json +2 -1
- package/rules/dart/D002_dispose_resources/config.json +25 -0
- package/rules/dart/D003_prefer_widgets_over_methods/config.json +14 -0
- package/rules/dart/D004_avoid_shrinkwrap_listview/config.json +13 -0
- package/rules/dart/D005_limit_widget_nesting/config.json +13 -0
- package/rules/dart/D006_prefer_extracting_large_callbacks/config.json +25 -0
- package/rules/dart/D007_prefer_init_first_dispose_last/config.json +10 -0
- package/rules/dart/D008_avoid_long_functions/config.json +12 -0
- package/rules/dart/D009_limit_function_parameters/config.json +13 -0
- package/rules/dart/D010_limit_cyclomatic_complexity/config.json +12 -0
- package/rules/dart/D011_prefer_named_parameters/config.json +12 -0
- package/rules/dart/D012_prefer_named_boolean_parameters/config.json +9 -0
- package/rules/dart/D013_single_public_class/config.json +10 -0
- package/rules/dart/D014_unsafe_collection_access/config.json +10 -0
- package/rules/dart/D015_copywith_all_parameters/config.json +9 -0
- package/rules/dart/D016_project_should_have_tests/config.json +24 -0
- package/rules/dart/D017_pubspec_dependencies_review/config.json +23 -0
- package/rules/dart/D018_remove_commented_code/config.json +13 -0
- package/rules/dart/D019_avoid_single_child_multi_child_widget/config.json +21 -0
- package/rules/dart/D020_limit_if_else_branches/config.json +12 -0
- package/rules/dart/D021_avoid_negated_boolean_checks/config.json +14 -0
- package/rules/dart/D022_use_setstate_correctly/config.json +14 -0
- package/rules/dart/D023_avoid_unnecessary_method_overrides/config.json +13 -0
- package/rules/dart/D024_avoid_unnecessary_stateful_widget/config.json +9 -0
- package/rules/dart/D025_avoid_nested_conditional_expressions/config.json +9 -0
- package/skill-assets/sunlint-code-quality/AGENTS.md +80 -0
- package/skill-assets/sunlint-code-quality/SKILL.md +176 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C006-verb-noun-functions.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C013-no-dead-code.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C014-dependency-injection.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C017-no-constructor-logic.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C018-generic-errors.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C019-error-log-level.md +29 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C020-no-unused-imports.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C022-no-unused-variables.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C023-no-duplicate-names.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C024-centralize-constants.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C029-catch-log-root-cause.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C030-custom-error-classes.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C033-separate-data-access.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C035-error-context-logging.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C041-no-hardcoded-secrets.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C042-boolean-naming.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C052-controller-parsing.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C060-superclass-logic.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/C067-no-hardcoded-config.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S003-open-redirect.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S004-no-log-credentials.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S005-server-authorization.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S006-default-credentials.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S007-output-encoding.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S009-approved-crypto.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S010-csprng.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S011-encrypted-client-hello.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S012-secrets-management.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S013-tls-connections.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S016-no-sensitive-query-string.md +39 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S017-parameterized-queries.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S019-email-input-sanitization.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S020-eval-code-execution.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S022-context-escaping.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S023-dynamic-js-encoding.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S025-server-validation.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S026-tls-encryption.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S027-mtls-validation.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S028-upload-limits.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S029-csrf-protection.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S030-directory-browsing.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S031-secure-cookie-flag.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S032-httponly-cookie.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S033-samesite-cookie.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S034-host-prefix-cookie.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S035-app-hostnames.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S036-internal-file-paths.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S037-anti-cache-headers.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S039-tls-certificate-validation.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S041-logout-invalidation.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S042-long-lived-sessions.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S044-critical-changes-reauth.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S045-brute-force-protection.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S047-oauth-csrf-protection.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S048-oauth-redirect-validation.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S049-auth-code-expiry.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S050-token-entropy.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S051-password-length.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S052-otp-entropy.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S053-generic-error-messages.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S054-no-default-admin.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S055-content-type-validation.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S056-log-injection.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S057-synchronized-time.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/csharp/S058-ssrf-protection.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/go/C006-verb-noun-functions.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C013-no-dead-code.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/C014-dependency-injection.md +85 -0
- package/skill-assets/sunlint-code-quality/rules/go/C017-no-constructor-logic.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/go/C018-generic-errors.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/go/C019-error-log-level.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/C020-no-unused-imports.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C022-no-unused-variables.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/go/C023-no-duplicate-names.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/go/C024-centralize-constants.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/C029-catch-log-root-cause.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/go/C030-custom-error-classes.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/go/C033-separate-data-access.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/go/C035-error-context-logging.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/C041-no-hardcoded-secrets.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/go/C042-boolean-naming.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/C052-controller-parsing.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/go/C060-superclass-logic.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/go/C067-no-hardcoded-config.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S003-open-redirect.md +80 -0
- package/skill-assets/sunlint-code-quality/rules/go/S004-no-log-credentials.md +66 -0
- package/skill-assets/sunlint-code-quality/rules/go/S005-server-authorization.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/S006-default-credentials.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/go/S007-output-encoding.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/S009-approved-crypto.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/go/S010-csprng.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S011-encrypted-client-hello.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/go/S012-secrets-management.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S013-tls-connections.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/go/S016-no-sensitive-query-string.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/S017-parameterized-queries.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/go/S019-email-input-sanitization.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/go/S020-eval-code-execution.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/go/S022-context-escaping.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S023-dynamic-js-encoding.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S025-server-validation.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/go/S026-tls-encryption.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/go/S027-mtls-validation.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S028-upload-limits.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S029-csrf-protection.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S030-directory-browsing.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S031-secure-cookie-flag.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/S032-httponly-cookie.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/go/S033-samesite-cookie.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S034-host-prefix-cookie.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/go/S035-app-hostnames.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/go/S036-internal-file-paths.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/go/S037-anti-cache-headers.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/go/S039-tls-certificate-validation.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/go/S041-logout-invalidation.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/go/S042-long-lived-sessions.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S044-critical-changes-reauth.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S045-brute-force-protection.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/go/S047-oauth-csrf-protection.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S048-oauth-redirect-validation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/go/S049-auth-code-expiry.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S050-token-entropy.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/go/S051-password-length.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/go/S052-otp-entropy.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/go/S053-generic-error-messages.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/go/S054-no-default-admin.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/go/S055-content-type-validation.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/go/S056-log-injection.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/go/S057-synchronized-time.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/go/S058-ssrf-protection.md +70 -0
- package/skill-assets/sunlint-code-quality/rules/java/C006-verb-noun-functions.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/C013-no-dead-code.md +175 -0
- package/skill-assets/sunlint-code-quality/rules/java/C014-dependency-injection.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/java/C017-no-constructor-logic.md +39 -0
- package/skill-assets/sunlint-code-quality/rules/java/C018-generic-errors.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/java/C019-error-log-level.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/java/C020-no-unused-imports.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/java/C022-no-unused-variables.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/java/C023-no-duplicate-names.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/java/C024-centralize-constants.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/C029-catch-log-root-cause.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/java/C030-custom-error-classes.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/java/C033-separate-data-access.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/java/C035-error-context-logging.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/java/C041-no-hardcoded-secrets.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/java/C042-boolean-naming.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/java/C052-controller-parsing.md +39 -0
- package/skill-assets/sunlint-code-quality/rules/java/C060-superclass-logic.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/java/C067-no-hardcoded-config.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/java/S003-open-redirect.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/java/S004-no-log-credentials.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/S005-server-authorization.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/java/S006-default-credentials.md +39 -0
- package/skill-assets/sunlint-code-quality/rules/java/S007-output-encoding.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/java/S009-approved-crypto.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/java/S010-csprng.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/S011-encrypted-client-hello.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/java/S012-secrets-management.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/java/S013-tls-connections.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/java/S016-no-sensitive-query-string.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/S017-parameterized-queries.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/java/S019-email-input-sanitization.md +32 -0
- package/skill-assets/sunlint-code-quality/rules/java/S020-eval-code-execution.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/java/S022-context-escaping.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/java/S023-dynamic-js-encoding.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/java/S025-server-validation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/java/S026-tls-encryption.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/java/S027-mtls-validation.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/java/S028-upload-limits.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/java/S029-csrf-protection.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/java/S030-directory-browsing.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/java/S031-secure-cookie-flag.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/java/S032-httponly-cookie.md +31 -0
- package/skill-assets/sunlint-code-quality/rules/java/S033-samesite-cookie.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/java/S034-host-prefix-cookie.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/java/S035-app-hostnames.md +23 -0
- package/skill-assets/sunlint-code-quality/rules/java/S036-internal-file-paths.md +39 -0
- package/skill-assets/sunlint-code-quality/rules/java/S037-anti-cache-headers.md +37 -0
- package/skill-assets/sunlint-code-quality/rules/java/S039-tls-certificate-validation.md +43 -0
- package/skill-assets/sunlint-code-quality/rules/java/S041-logout-invalidation.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/java/S042-long-lived-sessions.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/S044-critical-changes-reauth.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/java/S045-brute-force-protection.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/java/S047-oauth-csrf-protection.md +33 -0
- package/skill-assets/sunlint-code-quality/rules/java/S048-oauth-redirect-validation.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/java/S049-auth-code-expiry.md +23 -0
- package/skill-assets/sunlint-code-quality/rules/java/S050-token-entropy.md +20 -0
- package/skill-assets/sunlint-code-quality/rules/java/S051-password-length.md +20 -0
- package/skill-assets/sunlint-code-quality/rules/java/S052-otp-entropy.md +23 -0
- package/skill-assets/sunlint-code-quality/rules/java/S053-generic-error-messages.md +21 -0
- package/skill-assets/sunlint-code-quality/rules/java/S054-no-default-admin.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/java/S055-content-type-validation.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/java/S056-log-injection.md +38 -0
- package/skill-assets/sunlint-code-quality/rules/java/S057-synchronized-time.md +35 -0
- package/skill-assets/sunlint-code-quality/rules/java/S058-ssrf-protection.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C006-verb-noun-functions.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C013-no-dead-code.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C014-dependency-injection.md +64 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C017-no-constructor-logic.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C018-generic-errors.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C019-error-log-level.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C020-no-unused-imports.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C022-no-unused-variables.md +39 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C023-no-duplicate-names.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C024-centralize-constants.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C029-catch-log-root-cause.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C030-custom-error-classes.md +72 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C033-separate-data-access.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C035-error-context-logging.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C041-no-hardcoded-secrets.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C042-boolean-naming.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C052-controller-parsing.md +71 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C060-superclass-logic.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/C067-no-hardcoded-config.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S003-open-redirect.md +66 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S004-no-log-credentials.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S005-server-authorization.md +75 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S006-default-credentials.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S007-output-encoding.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S009-approved-crypto.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S010-csprng.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S011-encrypted-client-hello.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S012-secrets-management.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S013-tls-connections.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S016-no-sensitive-query-string.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S017-parameterized-queries.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S019-email-input-sanitization.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S020-eval-code-execution.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S022-context-escaping.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S023-dynamic-js-encoding.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S025-server-validation.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S026-tls-encryption.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S027-mtls-validation.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S028-upload-limits.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S029-csrf-protection.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S030-directory-browsing.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S031-secure-cookie-flag.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S032-httponly-cookie.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S033-samesite-cookie.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S034-host-prefix-cookie.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S035-app-hostnames.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S036-internal-file-paths.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S037-anti-cache-headers.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S039-tls-certificate-validation.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S041-logout-invalidation.md +71 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S042-long-lived-sessions.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S044-critical-changes-reauth.md +64 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S045-brute-force-protection.md +64 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S047-oauth-csrf-protection.md +74 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S048-oauth-redirect-validation.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S049-auth-code-expiry.md +70 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S050-token-entropy.md +65 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S051-password-length.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S052-otp-entropy.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S053-generic-error-messages.md +66 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S054-no-default-admin.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S055-content-type-validation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S056-log-injection.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S057-synchronized-time.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/kotlin/S058-ssrf-protection.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/php/C006-verb-noun-functions.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/php/C013-no-dead-code.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/php/C014-dependency-injection.md +71 -0
- package/skill-assets/sunlint-code-quality/rules/php/C017-no-constructor-logic.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/php/C018-generic-errors.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/php/C019-error-log-level.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/C020-no-unused-imports.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/php/C022-no-unused-variables.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/php/C023-no-duplicate-names.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/php/C024-centralize-constants.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/php/C029-catch-log-root-cause.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/php/C030-custom-error-classes.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/php/C033-separate-data-access.md +79 -0
- package/skill-assets/sunlint-code-quality/rules/php/C035-error-context-logging.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/C041-no-hardcoded-secrets.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/php/C042-boolean-naming.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/php/C052-controller-parsing.md +66 -0
- package/skill-assets/sunlint-code-quality/rules/php/C060-superclass-logic.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/C067-no-hardcoded-config.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/php/S003-open-redirect.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/php/S004-no-log-credentials.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/php/S005-server-authorization.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/php/S006-default-credentials.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/php/S007-output-encoding.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/php/S009-approved-crypto.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/php/S010-csprng.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/php/S011-encrypted-client-hello.md +41 -0
- package/skill-assets/sunlint-code-quality/rules/php/S012-secrets-management.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/php/S013-tls-connections.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/php/S016-no-sensitive-query-string.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/php/S017-parameterized-queries.md +44 -0
- package/skill-assets/sunlint-code-quality/rules/php/S019-email-input-sanitization.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/S020-eval-code-execution.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/php/S022-context-escaping.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/php/S023-dynamic-js-encoding.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/php/S025-server-validation.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/php/S026-tls-encryption.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/php/S027-mtls-validation.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/php/S028-upload-limits.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/php/S029-csrf-protection.md +65 -0
- package/skill-assets/sunlint-code-quality/rules/php/S030-directory-browsing.md +40 -0
- package/skill-assets/sunlint-code-quality/rules/php/S031-secure-cookie-flag.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/php/S032-httponly-cookie.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/S033-samesite-cookie.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/php/S034-host-prefix-cookie.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/php/S035-app-hostnames.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/php/S036-internal-file-paths.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/php/S037-anti-cache-headers.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/php/S039-tls-certificate-validation.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/S041-logout-invalidation.md +63 -0
- package/skill-assets/sunlint-code-quality/rules/php/S042-long-lived-sessions.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/php/S044-critical-changes-reauth.md +71 -0
- package/skill-assets/sunlint-code-quality/rules/php/S045-brute-force-protection.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/php/S047-oauth-csrf-protection.md +72 -0
- package/skill-assets/sunlint-code-quality/rules/php/S048-oauth-redirect-validation.md +54 -0
- package/skill-assets/sunlint-code-quality/rules/php/S049-auth-code-expiry.md +71 -0
- package/skill-assets/sunlint-code-quality/rules/php/S050-token-entropy.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/php/S051-password-length.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/php/S052-otp-entropy.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/php/S053-generic-error-messages.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/php/S054-no-default-admin.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/php/S055-content-type-validation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/php/S056-log-injection.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/php/S057-synchronized-time.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/php/S058-ssrf-protection.md +65 -0
- package/skill-assets/sunlint-code-quality/rules/python/C006-verb-noun-functions.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/python/C013-no-dead-code.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/python/C014-dependency-injection.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/python/C017-no-constructor-logic.md +30 -0
- package/skill-assets/sunlint-code-quality/rules/python/C018-generic-errors.md +25 -0
- package/skill-assets/sunlint-code-quality/rules/python/C019-error-log-level.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/python/C020-no-unused-imports.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/python/C022-no-unused-variables.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/python/C023-no-duplicate-names.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/python/C024-centralize-constants.md +27 -0
- package/skill-assets/sunlint-code-quality/rules/python/C029-catch-log-root-cause.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/python/C030-custom-error-classes.md +28 -0
- package/skill-assets/sunlint-code-quality/rules/python/C033-separate-data-access.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/python/C035-error-context-logging.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/python/C041-no-hardcoded-secrets.md +23 -0
- package/skill-assets/sunlint-code-quality/rules/python/C042-boolean-naming.md +24 -0
- package/skill-assets/sunlint-code-quality/rules/python/C052-controller-parsing.md +34 -0
- package/skill-assets/sunlint-code-quality/rules/python/C060-superclass-logic.md +26 -0
- package/skill-assets/sunlint-code-quality/rules/python/C067-no-hardcoded-config.md +22 -0
- package/skill-assets/sunlint-code-quality/rules/python/S003-open-redirect.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S004-no-log-credentials.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S005-server-authorization.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S006-default-credentials.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S007-output-encoding.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S009-approved-crypto.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S010-csprng.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S011-encrypted-client-hello.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S012-secrets-management.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S013-tls-connections.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S016-no-sensitive-query-string.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S017-parameterized-queries.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/python/S019-email-input-sanitization.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S020-eval-code-execution.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/python/S022-context-escaping.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S023-dynamic-js-encoding.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S025-server-validation.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S026-tls-encryption.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S027-mtls-validation.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S028-upload-limits.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S029-csrf-protection.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S030-directory-browsing.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S031-secure-cookie-flag.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S032-httponly-cookie.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S033-samesite-cookie.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S034-host-prefix-cookie.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S035-app-hostnames.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S036-internal-file-paths.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/python/S037-anti-cache-headers.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S039-tls-certificate-validation.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S041-logout-invalidation.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S042-long-lived-sessions.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S044-critical-changes-reauth.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S045-brute-force-protection.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S047-oauth-csrf-protection.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S048-oauth-redirect-validation.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S049-auth-code-expiry.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S050-token-entropy.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S051-password-length.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S052-otp-entropy.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S053-generic-error-messages.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S054-no-default-admin.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S055-content-type-validation.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S056-log-injection.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S057-synchronized-time.md +16 -0
- package/skill-assets/sunlint-code-quality/rules/python/S058-ssrf-protection.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C006-verb-noun-functions.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C013-no-dead-code.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C014-dependency-injection.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C017-no-constructor-logic.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C018-generic-errors.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C019-error-log-level.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C020-no-unused-imports.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C022-no-unused-variables.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C023-no-duplicate-names.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C024-centralize-constants.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C029-catch-log-root-cause.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C030-custom-error-classes.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C033-separate-data-access.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C035-error-context-logging.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C041-no-hardcoded-secrets.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C042-boolean-naming.md +42 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C052-controller-parsing.md +64 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C060-superclass-logic.md +67 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/C067-no-hardcoded-config.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S003-open-redirect.md +76 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S004-no-log-credentials.md +71 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S005-server-authorization.md +68 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S006-default-credentials.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S007-output-encoding.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S009-approved-crypto.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S010-csprng.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S011-encrypted-client-hello.md +45 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S012-secrets-management.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S013-tls-connections.md +70 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S016-no-sensitive-query-string.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S017-parameterized-queries.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S019-email-input-sanitization.md +56 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S020-eval-code-execution.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S022-context-escaping.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S023-dynamic-js-encoding.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S025-server-validation.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S026-tls-encryption.md +47 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S027-mtls-validation.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S028-upload-limits.md +65 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S029-csrf-protection.md +62 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S030-directory-browsing.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S031-secure-cookie-flag.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S032-httponly-cookie.md +36 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S033-samesite-cookie.md +46 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S034-host-prefix-cookie.md +50 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S035-app-hostnames.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S036-internal-file-paths.md +53 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S037-anti-cache-headers.md +52 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S039-tls-certificate-validation.md +51 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S041-logout-invalidation.md +58 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S042-long-lived-sessions.md +55 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S044-critical-changes-reauth.md +69 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S045-brute-force-protection.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S047-oauth-csrf-protection.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S048-oauth-redirect-validation.md +59 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S049-auth-code-expiry.md +73 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S050-token-entropy.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S051-password-length.md +60 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S052-otp-entropy.md +49 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S053-generic-error-messages.md +61 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S054-no-default-admin.md +64 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S055-content-type-validation.md +64 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S056-log-injection.md +48 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S057-synchronized-time.md +57 -0
- package/skill-assets/sunlint-code-quality/rules/typescript/S058-ssrf-protection.md +63 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use __Host- Prefix For Cookies
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: locks the cookie to the specific domain and path, preventing subdomain cookie tossing attacks
|
|
5
|
+
tags: cookies, prefix, domain, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use __Host- Prefix For Cookies
|
|
9
|
+
|
|
10
|
+
The `__Host-` prefix is a browser-enforced security mechanism. When a cookie name starts with `__Host-`, the browser will only accept it if it meets strict criteria, making it much harder for an attacker on a subdomain (e.g., `attacker.example.com`) to overwrite or spoof cookies for the main domain (`example.com`).
|
|
11
|
+
|
|
12
|
+
**Incorrect (standard session cookie):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// VULNERABLE to subdomain shadowing/tossing
|
|
16
|
+
val cookie = Cookie("session_id", token).apply {
|
|
17
|
+
isHttpOnly = true
|
|
18
|
+
isSecure = true
|
|
19
|
+
path = "/"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (__Host- prefixed cookie):**
|
|
24
|
+
|
|
25
|
+
```kotlin
|
|
26
|
+
// STRONGLY SECURE
|
|
27
|
+
val cookie = Cookie("__Host-session_id", token).apply {
|
|
28
|
+
isHttpOnly = true
|
|
29
|
+
isSecure = true // REQ: Must be secure
|
|
30
|
+
path = "/" // REQ: Must be /
|
|
31
|
+
// REQ: Must NOT call setDomain().
|
|
32
|
+
// This locks it to the EXACT host that sent it.
|
|
33
|
+
}
|
|
34
|
+
response.addCookie(cookie)
|
|
35
|
+
|
|
36
|
+
// Ktor:
|
|
37
|
+
call.sessions.set("__Host-session", MySession(token))
|
|
38
|
+
// Ensure the session cookie configuration has path = "/" and secure = true
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**__Host- Prefix Requirements:**
|
|
42
|
+
1. Must have the `Secure` flag.
|
|
43
|
+
2. Must be sent from a secure origin (HTTPS).
|
|
44
|
+
3. Must have `Path=/`.
|
|
45
|
+
4. Must **NOT** have a `Domain` attribute (this ensures it's only sent to the host that set it, not subdomains).
|
|
46
|
+
|
|
47
|
+
**Why use it?**
|
|
48
|
+
It prevents "Cookie Tossing" attacks where an attacker controlling a subdomain (like `blog.company.com`) sets a cookie for the parent domain (`company.com`), potentially hijacking its sessions or triggering CSRF.
|
|
49
|
+
|
|
50
|
+
**Tools:** OWASP ZAP, Browser DevTools, Snyk, Manual Review
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Host Apps On Different Hostnames
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: enforces origin isolation to prevent cross-app data and session leakage
|
|
5
|
+
tags: hostname, isolation, same-origin, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Host Apps On Different Hostnames
|
|
9
|
+
|
|
10
|
+
Hosting multiple separate applications (e.g., a customer portal and an admin dashboard) on the same hostname but different paths (e.g., `/app` and `/admin`) is risky. Because they share the same origin, they also share cookies, `localStorage`, `sessionStorage`, and `IndexedDB`.
|
|
11
|
+
|
|
12
|
+
**Incorrect (Shared Hostname):**
|
|
13
|
+
```text
|
|
14
|
+
https://company.com/portal <-- Shared cookies/storage
|
|
15
|
+
https://company.com/admin <-- Shared cookies/storage
|
|
16
|
+
https://company.com/blog <-- A vulnerability in the blog can steal admin cookies!
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (Separate Hostnames):**
|
|
20
|
+
```text
|
|
21
|
+
https://portal.company.com <-- Isolated
|
|
22
|
+
https://admin.company.com <-- Isolated
|
|
23
|
+
https://blog.company.com <-- Isolated
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Implementation in Kotlin (CORS):**
|
|
27
|
+
When applications are on different hostnames, you must configure Cross-Origin Resource Sharing (CORS) to allow them to communicate safely.
|
|
28
|
+
|
|
29
|
+
```kotlin
|
|
30
|
+
// Ktor CORS configuration for separate origins
|
|
31
|
+
install(CORS) {
|
|
32
|
+
allowHost("portal.company.com", schemas = listOf("https"))
|
|
33
|
+
allowHost("admin.company.com", schemas = listOf("https"))
|
|
34
|
+
allowCredentials = true
|
|
35
|
+
allowHeader(HttpHeaders.Authorization)
|
|
36
|
+
allowMethod(HttpMethod.Options)
|
|
37
|
+
allowMethod(HttpMethod.Post)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Spring Security
|
|
41
|
+
@Bean
|
|
42
|
+
fun corsConfigurationSource(): CorsConfigurationSource {
|
|
43
|
+
val configuration = CorsConfiguration()
|
|
44
|
+
configuration.allowedOrigins = listOf("https://portal.company.com")
|
|
45
|
+
configuration.allowedMethods = listOf("GET", "POST", "PUT", "DELETE")
|
|
46
|
+
configuration.allowCredentials = true
|
|
47
|
+
val source = UrlBasedCorsConfigurationSource()
|
|
48
|
+
source.registerCorsConfiguration("/**", configuration)
|
|
49
|
+
return source
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Benefits of Isolation:**
|
|
54
|
+
- **Cookie Security:** Admin session cookies cannot be read or overwritten by logic in the user portal.
|
|
55
|
+
- **Storage Security:** Sensitive data in `localStorage` is scoped only to the specific application.
|
|
56
|
+
- **CSRF Mitigation:** Attacking one app from another becomes much harder as they are seen as different origins.
|
|
57
|
+
- **Blast Radius:** A XSS vulnerability in a less-secure part of the site (like a blog or forum) cannot easily pivot to the highly-sensitive admin panel.
|
|
58
|
+
|
|
59
|
+
**Tools:** DNS Configuration, Load Balancer (NGINX/Cloudfront), Browser DevTools
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Internal Data For File Paths
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: prevents Path Traversal (LFI) attacks that allow reading sensitive system files
|
|
5
|
+
tags: file-path, path-traversal, lfi, input-validation, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Use Internal Data For File Paths
|
|
9
|
+
|
|
10
|
+
User-provided input should never be used to construct file paths directly. An attacker can use sequences like `../` to escape the intended directory and access sensitive files on the server (e.g., `/etc/passwd`, database credentials, or source code).
|
|
11
|
+
|
|
12
|
+
**Incorrect (user-controlled path construction):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// VULNERABLE: Direct use of filename from query
|
|
16
|
+
@GetMapping("/download")
|
|
17
|
+
fun download(@RequestParam filename: String, response: HttpServletResponse) {
|
|
18
|
+
val file = File("/opt/app/uploads/$filename")
|
|
19
|
+
// Attacker: ?filename=../../../../etc/passwd
|
|
20
|
+
file.inputStream().use { it.copyTo(response.outputStream) }
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (validation and sanitization):**
|
|
25
|
+
|
|
26
|
+
```kotlin
|
|
27
|
+
import java.nio.file.Paths
|
|
28
|
+
import kotlin.io.path.name
|
|
29
|
+
|
|
30
|
+
@GetMapping("/download")
|
|
31
|
+
fun safeDownload(@RequestParam filename: String): ResponseEntity<Resource> {
|
|
32
|
+
// 1. Sanitize: Extract ONLY the filename, ignore any path components
|
|
33
|
+
val safeName = Paths.get(filename).fileName.toString()
|
|
34
|
+
|
|
35
|
+
// 2. Ideally: Map the filename to an internal ID or record in the DB
|
|
36
|
+
val fileRecord = fileRepository.findByOriginalNameAndUserId(safeName, currentUserId)
|
|
37
|
+
?: throw NotFoundException("File not found")
|
|
38
|
+
|
|
39
|
+
// 3. Use a static base directory and the SANITIZED name
|
|
40
|
+
val baseDir = Paths.get("/opt/app/uploads").toAbsolutePath()
|
|
41
|
+
val filePath = baseDir.resolve(safeName).normalize()
|
|
42
|
+
|
|
43
|
+
// 4. Verify the resulting path is still inside the base directory
|
|
44
|
+
if (!filePath.startsWith(baseDir)) {
|
|
45
|
+
throw SecurityException("Invalid file path attempt")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
val resource = FileUrlResource(filePath.toUri().toURL())
|
|
49
|
+
return ResponseEntity.ok()
|
|
50
|
+
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"$safeName\"")
|
|
51
|
+
.body(resource)
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Security Principles:**
|
|
56
|
+
- **Whitelisting:** Store files with generated IDs (UUIDs) and look them up in a database.
|
|
57
|
+
- **Sanitization:** Use `Paths.get(name).fileName` to strip directory components.
|
|
58
|
+
- **Normalization:** Always call `.normalize()` and `.toAbsolutePath()` before checking if a path starts with your root directory.
|
|
59
|
+
- **Isolation:** Run the application with a dedicated user that has minimal filesystem permissions.
|
|
60
|
+
|
|
61
|
+
**Tools:** SonarQube (S2083), Semgrep, OWASP Path Traversal Cheat Sheet, Manual Review
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Set Anti-cache Headers
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: prevents sensitive data from being cached in shared proxies or local browser caches
|
|
5
|
+
tags: headers, cache, sensitive-data, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Set Anti-cache Headers
|
|
9
|
+
|
|
10
|
+
Sensitive information (like banking details, health records, or private profile info) cached in a browser or by a proxy can be retrieved by an attacker with access to the same machine or network. You must tell the browser strictly not to store this data.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no cache control for sensitive data):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// Data returned without instructions to the browser
|
|
16
|
+
@GetMapping("/api/bank-details")
|
|
17
|
+
fun getDetails(): List<Transaction> {
|
|
18
|
+
return transactionService.findAll() // Might be cached by browser or CDN
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (explicit anti-cache headers):**
|
|
23
|
+
|
|
24
|
+
```kotlin
|
|
25
|
+
// Spring Boot (Manual in Controller)
|
|
26
|
+
@GetMapping("/api/bank-details")
|
|
27
|
+
fun getDetails(response: HttpServletResponse): List<Transaction> {
|
|
28
|
+
response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, private")
|
|
29
|
+
response.setHeader("Pragma", "no-cache")
|
|
30
|
+
response.setHeader("Expires", "0")
|
|
31
|
+
return transactionService.findAll()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Ktor: Using CachingHeaders plugin
|
|
35
|
+
install(CachingHeaders) {
|
|
36
|
+
options { _, outgoingContent ->
|
|
37
|
+
if (outgoingContent.contentType?.withoutParameters() == ContentType.Application.Json) {
|
|
38
|
+
CachingOptions(CacheControl.NoStore(CacheControl.Visibility.Private))
|
|
39
|
+
} else null
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Global Spring Security configuration (Applied by default)
|
|
44
|
+
// http.headers().cacheControl().disable() // DO NOT DO THIS!
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Recommended Headers:**
|
|
48
|
+
- `Cache-Control: no-store, no-cache, must-revalidate, private`
|
|
49
|
+
- `Pragma: no-cache` (For compatibility with old HTTP/1.0 clients)
|
|
50
|
+
- `Expires: 0` (Marking the content as immediately expired)
|
|
51
|
+
|
|
52
|
+
**Critical areas to protect:**
|
|
53
|
+
- User account and profile pages.
|
|
54
|
+
- Authentication tokens or state.
|
|
55
|
+
- Personalized dashboards or reports.
|
|
56
|
+
- Administrative consoles.
|
|
57
|
+
|
|
58
|
+
**Tools:** OWASP ZAP, Browser DevTools (Network tab), Qualys SSL Labs
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TLS Clients Must Validate Server Certificates
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: prevents Man-in-the-Middle (MitM) attacks by ensuring the server identity is authentic
|
|
5
|
+
tags: tls, certificates, validation, mitm, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## TLS Clients Must Validate Server Certificates
|
|
9
|
+
|
|
10
|
+
Disabling TLS certificate validation or trusting all certificates allows an attacker to intercept, read, and modify your traffic by presenting a self-signed or forged certificate. This completely bypasses the security provided by TLS.
|
|
11
|
+
|
|
12
|
+
**Incorrect (disabled validation / trust-all):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// DANGEROUS: Trusting all certificates in OkHttp
|
|
16
|
+
val trustAllCerts = arrayOf<X509TrustManager>(object : X509TrustManager {
|
|
17
|
+
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
|
|
18
|
+
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {}
|
|
19
|
+
override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
// DANGEROUS: Trust-all SSL context
|
|
23
|
+
val sslContext = SSLContext.getInstance("SSL").apply {
|
|
24
|
+
init(null, trustAllCerts, SecureRandom())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// DANGEROUS: Ignoring Hostname verification
|
|
28
|
+
val hostnameVerifier = HostnameVerifier { _, _ -> true }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Correct (proper validation):**
|
|
32
|
+
|
|
33
|
+
```kotlin
|
|
34
|
+
// 1. Default Behavior (Uses System Trust Store) - Safe
|
|
35
|
+
val client = OkHttpClient() // Validates against trusted root CAs
|
|
36
|
+
|
|
37
|
+
// 2. Custom CA for internal/private services
|
|
38
|
+
val caInputStream: InputStream = File("internal-ca.pem").inputStream()
|
|
39
|
+
val certificateFactory = CertificateFactory.getInstance("X.509")
|
|
40
|
+
val ca = certificateFactory.generateCertificate(caInputStream)
|
|
41
|
+
|
|
42
|
+
val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
|
|
43
|
+
load(null, null)
|
|
44
|
+
setCertificateEntry("ca", ca)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
|
|
48
|
+
init(keyStore)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
val client = OkHttpClient.Builder()
|
|
52
|
+
.sslSocketFactory(sslContext.socketFactory, trustManagerFactory.trustManagers[0] as X509TrustManager)
|
|
53
|
+
.build()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Security Checklist:**
|
|
57
|
+
- Never use code that explicitly bypasses `checkServerTrusted`.
|
|
58
|
+
- Do not return `true` from a custom `HostnameVerifier` without validation.
|
|
59
|
+
- In production, ensure no "trust-all" SSL factories are instantiated.
|
|
60
|
+
- For mobile apps, consider **Certificate Pinning** for high-security endpoints.
|
|
61
|
+
|
|
62
|
+
**Tools:** SSLyze, Qualys SSL Labs, OWASP ZAP, Manual Review
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Invalidate Session On Logout
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: ensures logout actually terminates access and prevents session reuse
|
|
5
|
+
tags: session, logout, invalidation, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Invalidate Session On Logout
|
|
9
|
+
|
|
10
|
+
If the server does not explicitly invalidate the session on logout, the session token remains valid. An attacker who has stolen the session token (e.g., via XSS or physical access) can continue using it even after the user thinks they have logged out.
|
|
11
|
+
|
|
12
|
+
**Incorrect (client-only logout):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// Frontend-only logout (token still valid on server!)
|
|
16
|
+
fun logout() {
|
|
17
|
+
localStorage.removeItem("token")
|
|
18
|
+
navigateToLogin()
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Server doesn't invalidate session
|
|
22
|
+
@PostMapping("/logout")
|
|
23
|
+
fun logout(): ResponseEntity<Any> {
|
|
24
|
+
return ResponseEntity.ok("Success") // Session still active in Redis/DB!
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (server-side invalidation):**
|
|
29
|
+
|
|
30
|
+
```kotlin
|
|
31
|
+
// Spring Security (Handles most of this automatically)
|
|
32
|
+
// http.logout().logoutUrl("/logout").invalidateHttpSession(true).deleteCookies("JSESSIONID")
|
|
33
|
+
|
|
34
|
+
@PostMapping("/api/logout")
|
|
35
|
+
fun logout(request: HttpServletRequest, response: HttpServletResponse): ResponseEntity<Any> {
|
|
36
|
+
// 1. Invalidate Session
|
|
37
|
+
request.session?.invalidate()
|
|
38
|
+
|
|
39
|
+
// 2. If using JWT - add to a blacklist (Redis) until expiry
|
|
40
|
+
val token = extractToken(request)
|
|
41
|
+
tokenBlacklist.add(token)
|
|
42
|
+
|
|
43
|
+
// 3. Clear cookies explicitly
|
|
44
|
+
val cookie = Cookie("session", null).apply {
|
|
45
|
+
maxAge = 0
|
|
46
|
+
path = "/"
|
|
47
|
+
isHttpOnly = true
|
|
48
|
+
isSecure = true
|
|
49
|
+
}
|
|
50
|
+
response.addCookie(cookie)
|
|
51
|
+
|
|
52
|
+
// 4. Prevent Caching of sensitive data
|
|
53
|
+
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate")
|
|
54
|
+
|
|
55
|
+
return ResponseEntity.ok("Logged out")
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Ktor
|
|
59
|
+
post("/logout") {
|
|
60
|
+
call.sessions.clear<UserSession>()
|
|
61
|
+
call.respond(HttpStatusCode.OK)
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Best Practices:**
|
|
66
|
+
- Always invalidate the session on the server side.
|
|
67
|
+
- Clear authentication cookies with appropriate flags (`HttpOnly`, `Secure`).
|
|
68
|
+
- If using stateless JWTs, maintain a short-lived blacklist for logged-out tokens.
|
|
69
|
+
- Clear all sensitive data from client-side storage (`localStorage`, `sessionStorage`).
|
|
70
|
+
|
|
71
|
+
**Tools:** Spring Security Logout, Ktor Sessions, Manual Audit
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Re-authenticate For Long-lived Sessions
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: ensures continuous user identity verification and reduces the window for session hijacking
|
|
5
|
+
tags: session, authentication, timeout, reauthentication, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Re-authenticate For Long-lived Sessions
|
|
9
|
+
|
|
10
|
+
Long-lived sessions (e.g., "Remember Me" for 30 days) are convenient but increase the risk that a stolen session token remains useful to an attacker for a long time. Periodic re-authentication for the entire session or specific sensitive actions ensures the original user is still in control.
|
|
11
|
+
|
|
12
|
+
**Incorrect (sessions never expire or are too long without checks):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// Infinite session age
|
|
16
|
+
sessionConfig.cookie.maxAge = -1
|
|
17
|
+
|
|
18
|
+
// No re-authentication for critical tasks
|
|
19
|
+
@PostMapping("/user/change-password")
|
|
20
|
+
fun changePassword(@RequestBody req: NewPasswordReq) {
|
|
21
|
+
// Only checks if session is valid, doesn't ask for old password again
|
|
22
|
+
userService.updatePassword(currentUserId, req.newPassword)
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Correct (periodic re-authentication and step-up auth):**
|
|
27
|
+
|
|
28
|
+
```kotlin
|
|
29
|
+
val SESSION_MAX_AGE_MS = 24 * 60 * 60 * 1000L // 1 day
|
|
30
|
+
val REAUTH_INTERVAL_MS = 4 * 60 * 60 * 1000L // 4 hours
|
|
31
|
+
|
|
32
|
+
// Middleware/Interceptor for checking last auth time
|
|
33
|
+
fun checkReauthNeeded(session: UserSession): Boolean {
|
|
34
|
+
val lastAuth = session.lastAuthenticatedAt ?: 0L
|
|
35
|
+
val now = System.currentTimeMillis()
|
|
36
|
+
|
|
37
|
+
return (now - lastAuth) > REAUTH_INTERVAL_MS
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// For sensitive operations (Step-up Authentication)
|
|
41
|
+
@PostMapping("/user/delete-account")
|
|
42
|
+
fun deleteAccount(@RequestBody request: DeleteAccountRequest) {
|
|
43
|
+
// REQUIRE the current password again, even if the session is valid
|
|
44
|
+
if (!authService.verifyPassword(currentUserId, request.currentPassword)) {
|
|
45
|
+
throw AccessDeniedException("Recent password verification required")
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
userService.delete(currentUserId)
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Best Practices:**
|
|
53
|
+
- **Inactivity Timeout:** Invalidate sessions after an idle period (e.g., 30 minutes).
|
|
54
|
+
- **Absolute Timeout:** Force a full logout after a fixed period (e.g., 12 or 24 hours), regardless of activity.
|
|
55
|
+
- **Step-up Auth:** Require re-authentication (Password, OTP, or Biometric) for highly sensitive actions like changing security settings, financial transfers, or accessing personal info.
|
|
56
|
+
|
|
57
|
+
**Tools:** Spring Security (ConcurrentSessionFilter, RememberMe), Ktor Sessions, Manual Audit
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Re-authenticate Before Critical Changes
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents unauthorized sensitive operations if a session is left unattended or hijacked
|
|
5
|
+
tags: authentication, critical, reauthentication, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Re-authenticate Before Critical Changes
|
|
9
|
+
|
|
10
|
+
Even if a user has an active session, critical identity or financial changes must require "fresh" authentication (typically the current password, an OTP, or a biometric check). This prevents an attacker who has hijacked a session or gained physical access to an unlocked device from taking full control of the account.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no confirmation for critical actions):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// DANGEROUS: Deleting an account without confirming credentials
|
|
16
|
+
@PostMapping("/account/delete")
|
|
17
|
+
fun delete() {
|
|
18
|
+
userService.delete(currentUserId)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// DANGEROUS: Changing email without verification
|
|
22
|
+
@PostMapping("/account/change-email")
|
|
23
|
+
fun changeEmail(@RequestBody req: EmailChangeRequest) {
|
|
24
|
+
userService.updateEmail(currentUserId, req.newEmail)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (require current password or 2FA):**
|
|
29
|
+
|
|
30
|
+
```kotlin
|
|
31
|
+
@PostMapping("/account/delete")
|
|
32
|
+
fun delete(@RequestBody req: ConfirmationRequest) {
|
|
33
|
+
// 1. Confirm current password
|
|
34
|
+
val isValid = authService.verifyPassword(currentUserId, req.currentPassword)
|
|
35
|
+
if (!isValid) {
|
|
36
|
+
throw BadCredentialsException("Invalid password for confirmation")
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// 2. Log exactly who and when initiated this
|
|
40
|
+
logger.security("Account deletion initiated", "userId" to currentUserId)
|
|
41
|
+
|
|
42
|
+
userService.delete(currentUserId)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// For systems with 2FA
|
|
46
|
+
@PostMapping("/account/change-email")
|
|
47
|
+
fun changeEmail(@RequestBody req: EmailChangeRequest) {
|
|
48
|
+
// Require TOTP/SMS code for sensitive changes
|
|
49
|
+
if (!mfaService.verifyCode(currentUserId, req.totpCode)) {
|
|
50
|
+
throw AccessDeniedException("Valid multi-factor authentication code required")
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
userService.updateEmail(currentUserId, req.newEmail)
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Actions requiring re-authentication:**
|
|
58
|
+
- Changing passwords or security questions.
|
|
59
|
+
- Updating email addresses or MFA settings.
|
|
60
|
+
- Account deletion or deactivation.
|
|
61
|
+
- Modifying linked bank accounts or credit cards.
|
|
62
|
+
- Transferring large sums of money.
|
|
63
|
+
|
|
64
|
+
**Tools:** Spring Security (Step-up Auth), Ktor Auth, Manual Review, OWASP ASVS
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Implement Brute-force Protection
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents automated password guessing and account harvesting attacks
|
|
5
|
+
tags: brute-force, rate-limiting, authentication, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Implement Brute-force Protection
|
|
9
|
+
|
|
10
|
+
Authentication endpoints without rate limiting or lockout mechanisms are vulnerable to brute-force attacks, where attackers try thousands of common passwords or perform "credential stuffing" attacks using stolen credentials.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no protection):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
@PostMapping("/login")
|
|
16
|
+
fun login(@RequestBody data: LoginRequest): ResponseEntity<Any> {
|
|
17
|
+
val result = authService.authenticate(data.username, data.password)
|
|
18
|
+
// No limit on attempts. Attacker can call this 10,000 times a minute.
|
|
19
|
+
return ResponseEntity.ok(result)
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (rate limiting and account lockout):**
|
|
24
|
+
|
|
25
|
+
```kotlin
|
|
26
|
+
// Using Ktor RateLimiting
|
|
27
|
+
install(RateLimit) {
|
|
28
|
+
register(RateLimitName("login")) {
|
|
29
|
+
rateLimiter(limit = 5, refillPeriod = 15.minutes)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// In-code tracking and exponential backoff
|
|
34
|
+
class LoginService(private val redisTemplate: RedisTemplate<String, Int>) {
|
|
35
|
+
fun handleLogin(username: String) {
|
|
36
|
+
val attempts = redisTemplate.get("login_attempts:$username") ?: 0
|
|
37
|
+
|
|
38
|
+
if (attempts >= 5) {
|
|
39
|
+
val lockoutMinutes = Math.pow(2.0, (attempts - 5).toDouble()).toLong()
|
|
40
|
+
throw LockedException("Account locked for $lockoutMinutes minutes")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
authenticate(username)
|
|
45
|
+
redisTemplate.delete("login_attempts:$username")
|
|
46
|
+
} catch (e: Exception) {
|
|
47
|
+
redisTemplate.increment("login_attempts:$username")
|
|
48
|
+
throw e
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Spring Security Configuration
|
|
54
|
+
// Use standard LoginFailureHandler to increment counters.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Brute-Force Protection Strategies:**
|
|
58
|
+
- **Rate Limiting:** Limit requests by IP and by username.
|
|
59
|
+
- **Account Lockout:** Temporarily disable accounts after X failed attempts.
|
|
60
|
+
- **Exponential Backoff:** Increase the wait time between successive login attempts.
|
|
61
|
+
- **CAPTCHA:** Use CAPTCHA challenges after a few failed attempts.
|
|
62
|
+
- **WAF:** Use a Web Application Firewall to block high-frequency attacks.
|
|
63
|
+
|
|
64
|
+
**Tools:** Spring Security (LoginFailureHandler), Redis, Ktor RateLimit, Cloudflare WAF, reCAPTCHA
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Protect OAuth Code Flow Vs CSRF
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: prevents attackers from stealing authorization codes or linking victim accounts to attacker credentials
|
|
5
|
+
tags: oauth, csrf, state, authorization, security, kotlin
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Protect OAuth Code Flow Vs CSRF
|
|
9
|
+
|
|
10
|
+
During an OAuth 2.0 Authorization Code flow, an attacker can perform a CSRF attack to force a user to link their session with the attacker's account, or to intercept the victim's authorization code. Using a `state` parameter is the standard defense.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no state parameter):**
|
|
13
|
+
|
|
14
|
+
```kotlin
|
|
15
|
+
// VULNERABLE: Initiating OAuth without a unique state
|
|
16
|
+
get("/auth/google") {
|
|
17
|
+
val googleAuthUrl = "https://accounts.google.com/oauth/authorize?" +
|
|
18
|
+
"client_id=$clientId&" +
|
|
19
|
+
"redirect_uri=$redirectUri&" +
|
|
20
|
+
"response_type=code&" +
|
|
21
|
+
"scope=email"
|
|
22
|
+
call.respondRedirect(googleAuthUrl)
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Correct (state parameter validation):**
|
|
27
|
+
|
|
28
|
+
```kotlin
|
|
29
|
+
import java.security.SecureRandom
|
|
30
|
+
import java.util.Base64
|
|
31
|
+
|
|
32
|
+
@GetMapping("/auth/google")
|
|
33
|
+
fun initiateGoogleAuth(session: HttpSession, response: HttpServletResponse) {
|
|
34
|
+
// 1. Generate a random, unpredictable state
|
|
35
|
+
val state = ByteArray(32).let {
|
|
36
|
+
SecureRandom().nextBytes(it)
|
|
37
|
+
Base64.getUrlEncoder().withoutPadding().encodeToString(it)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// 2. Store it in the user's session
|
|
41
|
+
session.setAttribute("oauth_state", state)
|
|
42
|
+
|
|
43
|
+
// 3. Include it in the authorization request
|
|
44
|
+
val authUrl = "https://accounts.google.com/oauth/authorize?" +
|
|
45
|
+
"client_id=$clientId&" +
|
|
46
|
+
"redirect_uri=$redirectUri&" +
|
|
47
|
+
"response_type=code&" +
|
|
48
|
+
"state=$state"
|
|
49
|
+
|
|
50
|
+
response.sendRedirect(authUrl)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@GetMapping("/auth/google/callback")
|
|
54
|
+
fun handleGoogleCallback(@RequestParam code: String, @RequestParam state: String, session: HttpSession) {
|
|
55
|
+
// 4. Validate the state returned by the provider
|
|
56
|
+
val savedState = session.getAttribute("oauth_state") as? String
|
|
57
|
+
|
|
58
|
+
if (savedState == null || savedState != state) {
|
|
59
|
+
throw AccessDeniedException("Invalid OAuth state parameter. Potential CSRF attack.")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 5. Clear the state once used
|
|
63
|
+
session.removeAttribute("oauth_state")
|
|
64
|
+
|
|
65
|
+
// Proceed to exchange code for tokens...
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Best Practices:**
|
|
70
|
+
- Always use a random, high-entropy `state` value.
|
|
71
|
+
- Store the state in a secure, server-side session or an encrypted, `HttpOnly` cookie.
|
|
72
|
+
- Alternatively, use **PKCE (Proof Key for Code Exchange)** for public clients (like mobile apps), which provides even stronger protection against code interception.
|
|
73
|
+
|
|
74
|
+
**Tools:** Spring Security OAuth2 (handles state automatically), Ktor Authentication, Manual Review
|