@critiq/rules 0.0.1 → 0.1.0

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.
Files changed (204) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +256 -140
  3. package/catalog.yaml +985 -19
  4. package/package.json +7 -1
  5. package/rules/go/go.performance.no-regex-construction-in-loop.rule.yaml +33 -0
  6. package/rules/go/go.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
  7. package/rules/go/go.performance.no-unbounded-concurrency.rule.yaml +33 -0
  8. package/rules/go/go.security.echo-sensitive-binding-without-validation.rule.yaml +46 -0
  9. package/rules/go/go.security.echo-unsafe-multipart-upload.rule.yaml +45 -0
  10. package/rules/go/go.security.fiber-sensitive-binding-without-validation.rule.yaml +45 -0
  11. package/rules/go/go.security.fiber-unsafe-multipart-upload.rule.yaml +45 -0
  12. package/rules/go/go.security.gin-sensitive-binding-without-validation.rule.yaml +45 -0
  13. package/rules/go/go.security.gin-trust-all-proxies.rule.yaml +45 -0
  14. package/rules/go/go.security.gin-wildcard-cors-with-credentials.rule.yaml +47 -0
  15. package/rules/go/go.security.net-http-missing-timeouts.rule.yaml +45 -0
  16. package/rules/go/go.security.sensitive-data-egress.rule.yaml +46 -0
  17. package/rules/go/go.security.tar-path-traversal.rule.yaml +45 -0
  18. package/rules/go/go.security.template-unescaped-request-value.rule.yaml +45 -0
  19. package/rules/go/go.testing.real-network-in-unit-test.rule.yaml +33 -0
  20. package/rules/go/go.testing.t-skip-without-ticket-reference.rule.yaml +33 -0
  21. package/rules/go/go.testing.time-sleep-in-unit-test.rule.yaml +33 -0
  22. package/rules/java/java.performance.no-regex-construction-in-loop.rule.yaml +33 -0
  23. package/rules/java/java.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
  24. package/rules/java/java.performance.no-unbounded-concurrency.rule.yaml +33 -0
  25. package/rules/java/java.security.android-screenshot-exposure.rule.yaml +35 -0
  26. package/rules/java/java.security.android-world-readable-mode.rule.yaml +35 -0
  27. package/rules/java/java.security.jpa-concatenated-query.rule.yaml +47 -0
  28. package/rules/java/java.security.reflected-output-from-request.rule.yaml +35 -0
  29. package/rules/java/java.security.servlet-insecure-cookie.rule.yaml +35 -0
  30. package/rules/java/java.security.spring-actuator-health-details-always.rule.yaml +40 -0
  31. package/rules/java/java.security.spring-actuator-sensitive-exposure.rule.yaml +40 -0
  32. package/rules/java/java.security.spring-csrf-globally-disabled.rule.yaml +49 -0
  33. package/rules/java/java.security.spring-debug-exposure.rule.yaml +35 -0
  34. package/rules/java/java.security.spring-permit-all-default.rule.yaml +47 -0
  35. package/rules/java/java.security.spring-webmvc-unrestricted-data-binding.rule.yaml +47 -0
  36. package/rules/java/java.security.template-unescaped-user-output.rule.yaml +49 -0
  37. package/rules/java/java.testing.disabled-without-ticket-reference.rule.yaml +33 -0
  38. package/rules/java/java.testing.http-client-in-unit-test.rule.yaml +33 -0
  39. package/rules/java/java.testing.thread-sleep-in-unit-test.rule.yaml +33 -0
  40. package/rules/php/php.performance.no-regex-construction-in-loop.rule.yaml +33 -0
  41. package/rules/php/php.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
  42. package/rules/php/php.performance.no-unbounded-concurrency.rule.yaml +33 -0
  43. package/rules/php/php.security.insecure-cors-wildcard-with-credentials.rule.yaml +41 -0
  44. package/rules/php/php.security.insecure-mail-or-file-transport.rule.yaml +41 -0
  45. package/rules/php/php.security.insecure-session-or-cookie-config.rule.yaml +42 -0
  46. package/rules/php/php.security.laravel-sensitive-csrf-exclusion.rule.yaml +42 -0
  47. package/rules/php/php.security.laravel-unsafe-blade-output.rule.yaml +42 -0
  48. package/rules/php/php.security.laravel-unsafe-mass-assignment.rule.yaml +45 -0
  49. package/rules/php/php.security.sensitive-data-egress.rule.yaml +42 -0
  50. package/rules/php/php.security.symfony-csrf-disabled.rule.yaml +42 -0
  51. package/rules/php/php.security.symfony-debug-exposure.rule.yaml +44 -0
  52. package/rules/php/php.security.unsafe-file-upload-handling.rule.yaml +41 -0
  53. package/rules/php/php.security.wordpress-missing-nonce-or-capability.rule.yaml +42 -0
  54. package/rules/php/php.security.wordpress-unprepared-sql.rule.yaml +42 -0
  55. package/rules/php/php.testing.curl-in-unit-test.rule.yaml +33 -0
  56. package/rules/php/php.testing.mark-test-skipped-without-ticket-reference.rule.yaml +33 -0
  57. package/rules/php/php.testing.sleep-in-unit-test.rule.yaml +33 -0
  58. package/rules/python/py.performance.no-regex-construction-in-loop.rule.yaml +33 -0
  59. package/rules/python/py.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
  60. package/rules/python/py.performance.no-unbounded-concurrency.rule.yaml +33 -0
  61. package/rules/python/py.security.django-csrf-exempt-state-changing.rule.yaml +46 -0
  62. package/rules/python/py.security.django-missing-csrf-middleware.rule.yaml +47 -0
  63. package/rules/python/py.security.django-unsafe-production-settings.rule.yaml +47 -0
  64. package/rules/python/py.security.drf-allow-any-default.rule.yaml +46 -0
  65. package/rules/python/py.security.drf-allow-any-unsafe-method.rule.yaml +46 -0
  66. package/rules/python/py.security.fastapi-insecure-cors.rule.yaml +43 -0
  67. package/rules/python/py.security.flask-missing-upload-body-limit.rule.yaml +44 -0
  68. package/rules/python/py.security.flask-unsafe-html-output.rule.yaml +44 -0
  69. package/rules/python/py.security.flask-unsafe-upload-filename.rule.yaml +44 -0
  70. package/rules/python/py.testing.pytest-skip-without-ticket-reference.rule.yaml +33 -0
  71. package/rules/python/py.testing.real-network-in-unit-test.rule.yaml +33 -0
  72. package/rules/python/py.testing.time-sleep-in-unit-test.rule.yaml +33 -0
  73. package/rules/ruby/ruby.performance.no-regex-construction-in-loop.rule.yaml +33 -0
  74. package/rules/ruby/ruby.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
  75. package/rules/ruby/ruby.performance.no-unbounded-concurrency.rule.yaml +33 -0
  76. package/rules/ruby/ruby.security.rails-csrf-disabled.rule.yaml +45 -0
  77. package/rules/ruby/ruby.security.rails-detailed-exceptions-enabled.rule.yaml +44 -0
  78. package/rules/ruby/ruby.security.rails-open-redirect.rule.yaml +45 -0
  79. package/rules/ruby/ruby.security.rails-unsafe-html-output.rule.yaml +46 -0
  80. package/rules/ruby/ruby.security.rails-unsafe-render.rule.yaml +45 -0
  81. package/rules/ruby/ruby.security.rails-unsafe-session-or-cookie-store.rule.yaml +45 -0
  82. package/rules/ruby/ruby.security.rails-unsafe-strong-parameters.rule.yaml +46 -0
  83. package/rules/ruby/ruby.security.sensitive-data-egress.rule.yaml +45 -0
  84. package/rules/ruby/ruby.security.sidekiq-web-unauthenticated-mount.rule.yaml +45 -0
  85. package/rules/ruby/ruby.testing.focused-example.rule.yaml +33 -0
  86. package/rules/ruby/ruby.testing.pending-without-ticket-reference.rule.yaml +33 -0
  87. package/rules/ruby/ruby.testing.real-network-in-unit-test.rule.yaml +33 -0
  88. package/rules/ruby/ruby.testing.skip-without-ticket-reference.rule.yaml +33 -0
  89. package/rules/ruby/ruby.testing.sleep-in-unit-test.rule.yaml +33 -0
  90. package/rules/rust/rust.performance.no-regex-construction-in-loop.rule.yaml +33 -0
  91. package/rules/rust/rust.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
  92. package/rules/rust/rust.performance.no-unbounded-concurrency.rule.yaml +33 -0
  93. package/rules/rust/rust.security.actix-wildcard-cors-with-credentials.rule.yaml +47 -0
  94. package/rules/rust/rust.security.axum-body-limit-disabled.rule.yaml +45 -0
  95. package/rules/rust/rust.security.axum-insecure-cors-with-credentials.rule.yaml +47 -0
  96. package/rules/rust/rust.security.rocket-panic-prone-request-handler.rule.yaml +45 -0
  97. package/rules/rust/rust.security.rocket-unsafe-template-output.rule.yaml +47 -0
  98. package/rules/rust/rust.security.sqlx-diesel-raw-interpolated-query.rule.yaml +47 -0
  99. package/rules/rust/rust.security.template-unescaped-request-value.rule.yaml +47 -0
  100. package/rules/rust/rust.security.warp-blocking-or-panic-in-async-handler.rule.yaml +45 -0
  101. package/rules/rust/rust.testing.ignore-without-ticket-reference.rule.yaml +33 -0
  102. package/rules/rust/rust.testing.real-network-in-unit-test.rule.yaml +33 -0
  103. package/rules/rust/rust.testing.thread-sleep-in-unit-test.rule.yaml +33 -0
  104. package/rules/shared/security.archive-path-traversal.rule.yaml +41 -0
  105. package/rules/shared/security.external-file-upload.rule.yaml +40 -0
  106. package/rules/shared/security.permissive-file-permissions.rule.yaml +40 -0
  107. package/rules/shared/security.sensitive-data-egress.rule.yaml +36 -0
  108. package/rules/typescript/ts.correctness.assignment-in-condition.rule.yaml +36 -0
  109. package/rules/typescript/ts.correctness.assignment-to-import-binding.rule.yaml +36 -0
  110. package/rules/typescript/ts.correctness.async-promise-executor.rule.yaml +36 -0
  111. package/rules/typescript/ts.correctness.duplicate-function-parameter.rule.yaml +36 -0
  112. package/rules/typescript/ts.correctness.duplicate-import-source.rule.yaml +36 -0
  113. package/rules/typescript/ts.correctness.duplicate-object-key.rule.yaml +36 -0
  114. package/rules/typescript/ts.correctness.duplicate-switch-case.rule.yaml +36 -0
  115. package/rules/typescript/ts.correctness.empty-block-statement.rule.yaml +35 -0
  116. package/rules/typescript/ts.correctness.identical-comparison-operands.rule.yaml +36 -0
  117. package/rules/typescript/ts.correctness.reassign-catch-binding.rule.yaml +35 -0
  118. package/rules/typescript/ts.correctness.regexp-pattern-unusual-control-character.rule.yaml +35 -0
  119. package/rules/typescript/ts.correctness.self-assignment.rule.yaml +36 -0
  120. package/rules/typescript/ts.next.server-action-missing-local-auth.rule.yaml +35 -0
  121. package/rules/typescript/ts.performance.no-array-spread-in-hot-loop.rule.yaml +32 -0
  122. package/rules/typescript/ts.performance.no-cache-miss-from-unstable-key.rule.yaml +32 -0
  123. package/rules/typescript/ts.performance.no-expensive-sort-in-render-path.rule.yaml +32 -0
  124. package/rules/typescript/ts.performance.no-json-parse-stringify-clone.rule.yaml +32 -0
  125. package/rules/typescript/ts.performance.no-large-object-spread-in-loop.rule.yaml +32 -0
  126. package/rules/typescript/ts.performance.no-n-plus-one-await-in-map.rule.yaml +32 -0
  127. package/rules/typescript/ts.performance.no-redundant-network-fetch.rule.yaml +32 -0
  128. package/rules/typescript/ts.performance.no-regex-construction-in-loop.rule.yaml +32 -0
  129. package/rules/typescript/ts.performance.no-sync-fs-in-request-path.rule.yaml +32 -0
  130. package/rules/typescript/ts.performance.no-unbounded-concurrency.rule.yaml +32 -0
  131. package/rules/typescript/ts.quality.no-ambiguous-abbreviations.rule.yaml +27 -0
  132. package/rules/typescript/ts.quality.no-barrel-file-cycle.rule.yaml +27 -0
  133. package/rules/typescript/ts.quality.no-boolean-parameter-trap.rule.yaml +27 -0
  134. package/rules/typescript/ts.quality.no-dead-export.rule.yaml +27 -0
  135. package/rules/typescript/ts.quality.no-hidden-side-effect-import.rule.yaml +27 -0
  136. package/rules/typescript/ts.quality.no-inconsistent-error-shape.rule.yaml +27 -0
  137. package/rules/typescript/ts.quality.no-mixed-abstraction-level.rule.yaml +27 -0
  138. package/rules/typescript/ts.quality.no-primitive-obsession-in-domain-model.rule.yaml +27 -0
  139. package/rules/typescript/ts.quality.no-temporal-coupling.rule.yaml +27 -0
  140. package/rules/typescript/ts.quality.no-wide-public-surface.rule.yaml +27 -0
  141. package/rules/typescript/ts.react.no-accessibility-label-missing.rule.yaml +36 -0
  142. package/rules/typescript/ts.react.no-activedescendant-on-non-focusable-host.rule.yaml +36 -0
  143. package/rules/typescript/ts.react.no-click-without-keyboard-handler.rule.yaml +36 -0
  144. package/rules/typescript/ts.react.no-deprecated-create-factory.rule.yaml +34 -0
  145. package/rules/typescript/ts.react.no-deprecated-react-dom-root-api.rule.yaml +34 -0
  146. package/rules/typescript/ts.react.no-derived-state-from-props.rule.yaml +34 -0
  147. package/rules/typescript/ts.react.no-effect-fetch-without-cancellation.rule.yaml +35 -0
  148. package/rules/typescript/ts.react.no-find-dom-node.rule.yaml +34 -0
  149. package/rules/typescript/ts.react.no-img-missing-alt-text.rule.yaml +36 -0
  150. package/rules/typescript/ts.react.no-index-as-key-in-dynamic-list.rule.yaml +34 -0
  151. package/rules/typescript/ts.react.no-interactive-role-on-static-semantics.rule.yaml +36 -0
  152. package/rules/typescript/ts.react.no-invalid-anchor-href.rule.yaml +36 -0
  153. package/rules/typescript/ts.react.no-keyboard-interaction-without-widget-role.rule.yaml +36 -0
  154. package/rules/typescript/ts.react.no-legacy-lifecycle.rule.yaml +34 -0
  155. package/rules/typescript/ts.react.no-missing-error-boundary.rule.yaml +36 -0
  156. package/rules/typescript/ts.react.no-positive-tabindex.rule.yaml +36 -0
  157. package/rules/typescript/ts.react.no-static-element-with-synthetic-handlers.rule.yaml +36 -0
  158. package/rules/typescript/ts.react.no-string-ref.rule.yaml +34 -0
  159. package/rules/typescript/ts.react.no-uncontrolled-to-controlled-input.rule.yaml +34 -0
  160. package/rules/typescript/ts.react.no-widget-role-without-tabindex.rule.yaml +36 -0
  161. package/rules/typescript/ts.security.ajv-insecure-configuration.rule.yaml +34 -0
  162. package/rules/typescript/ts.security.angular-dom-sanitizer-bypass-untrusted-input.rule.yaml +35 -0
  163. package/rules/typescript/ts.security.apollo-server-csrf-disabled.rule.yaml +36 -0
  164. package/rules/typescript/ts.security.apollo-server-graphql-dev-tooling-exposure.rule.yaml +36 -0
  165. package/rules/typescript/ts.security.apollo-server-introspection-exposure.rule.yaml +35 -0
  166. package/rules/typescript/ts.security.apollo-server-missing-query-limits.rule.yaml +35 -0
  167. package/rules/typescript/ts.security.astro-vite-public-secret-define.rule.yaml +39 -0
  168. package/rules/typescript/ts.security.debug-statement-in-source.rule.yaml +36 -0
  169. package/rules/typescript/ts.security.electron-dangerous-webpreferences.rule.yaml +35 -0
  170. package/rules/typescript/ts.security.electron-insecure-local-state.rule.yaml +35 -0
  171. package/rules/typescript/ts.security.electron-missing-ipc-origin-check.rule.yaml +35 -0
  172. package/rules/typescript/ts.security.electron-shell-open-external-unvalidated.rule.yaml +35 -0
  173. package/rules/typescript/ts.security.express-error-handler-information-disclosure.rule.yaml +35 -0
  174. package/rules/typescript/ts.security.express-static-dotfiles-allow.rule.yaml +35 -0
  175. package/rules/typescript/ts.security.express-unbounded-body-parser.rule.yaml +34 -0
  176. package/rules/typescript/ts.security.express-user-controlled-static-mount.rule.yaml +35 -0
  177. package/rules/typescript/ts.security.fastify-excessive-body-limit.rule.yaml +34 -0
  178. package/rules/typescript/ts.security.fastify-public-bind-without-trust-proxy.rule.yaml +38 -0
  179. package/rules/typescript/ts.security.graphql-upload-without-csrf-guard.rule.yaml +36 -0
  180. package/rules/typescript/ts.security.iframe-missing-sandbox-attribute.rule.yaml +35 -0
  181. package/rules/typescript/ts.security.insecure-content-security-policy-literal.rule.yaml +35 -0
  182. package/rules/typescript/ts.security.insecure-helmet-hardening-options.rule.yaml +36 -0
  183. package/rules/typescript/ts.security.jwt-insecure-signing-algorithm.rule.yaml +35 -0
  184. package/rules/typescript/ts.security.legacy-buffer-constructor.rule.yaml +35 -0
  185. package/rules/typescript/ts.security.log-injection.rule.yaml +36 -0
  186. package/rules/typescript/ts.security.nestjs-helmet-after-route-mount.rule.yaml +34 -0
  187. package/rules/typescript/ts.security.nestjs-missing-global-validation-pipe.rule.yaml +35 -0
  188. package/rules/typescript/ts.security.nestjs-skip-throttle-sensitive-route.rule.yaml +35 -0
  189. package/rules/typescript/ts.security.nestjs-validation-pipe-without-whitelist.rule.yaml +36 -0
  190. package/rules/typescript/ts.security.nuxt-public-runtime-secret.rule.yaml +38 -0
  191. package/rules/typescript/ts.security.open-redirect.rule.yaml +2 -0
  192. package/rules/typescript/ts.security.request-driven-array-index-access.rule.yaml +33 -0
  193. package/rules/typescript/ts.security.sensitive-data-egress.rule.yaml +1 -0
  194. package/rules/typescript/ts.security.ssrf.rule.yaml +1 -0
  195. package/rules/typescript/ts.security.unsafe-dompurify-version.rule.yaml +36 -0
  196. package/rules/typescript/ts.security.unsafe-marked-version.rule.yaml +36 -0
  197. package/rules/typescript/ts.security.xml-parse-string-with-untrusted-input.rule.yaml +35 -0
  198. package/rules/typescript/ts.testing.no-flaky-timer-test.rule.yaml +38 -0
  199. package/rules/typescript/ts.testing.no-focused-test.rule.yaml +34 -0
  200. package/rules/typescript/ts.testing.no-missing-edge-case-tests.rule.yaml +35 -0
  201. package/rules/typescript/ts.testing.no-network-call-in-unit-test.rule.yaml +38 -0
  202. package/rules/typescript/ts.testing.no-skipped-test-without-ticket.rule.yaml +34 -0
  203. package/rules/typescript/ts.testing.no-snapshot-without-intent.rule.yaml +34 -0
  204. package/rules/typescript/ts.testing.no-test-only-code-in-production.rule.yaml +38 -0
@@ -0,0 +1,40 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: security.external-file-upload
5
+ title: Do not persist upload filenames directly
6
+ summary: Upload handlers should not store attacker-controlled filenames without generating or validating a safe local name.
7
+ rationale: Upload filenames can carry traversal payloads, collisions, or misleading extensions that break local containment.
8
+ tags:
9
+ - security
10
+ - filesystem
11
+ - upload
12
+ - rules-catalog
13
+ stability: experimental
14
+ appliesTo: block
15
+ scope:
16
+ languages:
17
+ - go
18
+ - java
19
+ - php
20
+ - python
21
+ - ruby
22
+ - rust
23
+ match:
24
+ fact:
25
+ kind: security.external-file-upload
26
+ bind: issue
27
+ emit:
28
+ finding:
29
+ category: security.filesystem
30
+ severity: high
31
+ confidence: 0.82
32
+ tags:
33
+ - security
34
+ - filesystem
35
+ - upload
36
+ message:
37
+ title: Generate a trusted local filename for `${captures.issue.text}`
38
+ summary: "`${captures.issue.text}` persists an upload filename derived from attacker-controlled input."
39
+ remediation:
40
+ summary: Generate a server-side filename or apply a strict allowlist before storing uploaded content.
@@ -0,0 +1,40 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: security.permissive-file-permissions
5
+ title: Avoid world-readable or world-writable file permissions
6
+ summary: File creation and permission changes should not grant broad local access.
7
+ rationale: Broad permissions expose application data to local users or processes that should not read or modify it.
8
+ tags:
9
+ - security
10
+ - filesystem
11
+ - permissions
12
+ - rules-catalog
13
+ stability: experimental
14
+ appliesTo: block
15
+ scope:
16
+ languages:
17
+ - go
18
+ - java
19
+ - php
20
+ - python
21
+ - ruby
22
+ - rust
23
+ match:
24
+ fact:
25
+ kind: security.permissive-file-permissions
26
+ bind: issue
27
+ emit:
28
+ finding:
29
+ category: security.filesystem
30
+ severity: medium
31
+ confidence: 0.8
32
+ tags:
33
+ - security
34
+ - filesystem
35
+ - permissions
36
+ message:
37
+ title: Tighten file permissions for `${captures.issue.text}`
38
+ summary: "`${captures.issue.text}` grants world-readable or world-writable filesystem access."
39
+ remediation:
40
+ summary: Use least-privilege file modes and avoid world-readable or world-writable permissions.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: security.sensitive-data-egress
5
+ title: Sensitive data egress to third-party processors
6
+ summary: Sensitive values should not be sent to external processors or outbound SDKs without minimization or redaction.
7
+ rationale: Sending regulated or secret data to third-party services increases privacy exposure and creates downstream processor risk.
8
+ tags:
9
+ - security
10
+ - privacy
11
+ - data-exposure
12
+ - rules-catalog
13
+ stability: experimental
14
+ appliesTo: block
15
+ scope:
16
+ languages:
17
+ - python
18
+ - rust
19
+ match:
20
+ fact:
21
+ kind: security.sensitive-data-egress
22
+ bind: issue
23
+ emit:
24
+ finding:
25
+ category: security.privacy
26
+ severity: high
27
+ confidence: 0.8
28
+ tags:
29
+ - security
30
+ - privacy
31
+ - data-exposure
32
+ message:
33
+ title: Avoid sending sensitive data through `${captures.issue.text}`
34
+ summary: "`${captures.issue.text}` sends request or identity data to an outbound processor."
35
+ remediation:
36
+ summary: Minimize the payload, redact sensitive fields, or route the data only to approved processors.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.assignment-in-condition
5
+ title: Assignment used as a conditional test
6
+ summary: Control-flow conditions should compare values, not perform assignments.
7
+ rationale: Using `=` where `===` was intended is a common defect; assignments in conditions also obscure data flow.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-016
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.assignment-in-condition
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.language
27
+ severity: medium
28
+ confidence: 0.9
29
+ tags:
30
+ - correctness
31
+ - language
32
+ message:
33
+ title: Replace assignment in condition
34
+ summary: "`${captures.issue.text}` performs assignment where a boolean predicate is expected."
35
+ remediation:
36
+ summary: Use a comparison operator or move the assignment before the condition. Note that the parser may not preserve extra grouping parentheses around the assignment.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.assignment-to-import-binding
5
+ title: Assignment to an imported binding
6
+ summary: Code assigns to or updates a symbol declared by an import.
7
+ rationale: ES module imports are read-only bindings; reassignment fails at runtime and signals a mistaken refactor.
8
+ tags:
9
+ - correctness
10
+ - modules
11
+ - rules-catalog
12
+ - crq-cor-021
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.assignment-to-import-binding
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.modules
27
+ severity: medium
28
+ confidence: 0.95
29
+ tags:
30
+ - correctness
31
+ - modules
32
+ message:
33
+ title: Do not assign to imported bindings
34
+ summary: "`${captures.issue.text}` mutates a symbol declared by an import."
35
+ remediation:
36
+ summary: Use a local variable, change the exporting module, or refactor so imports remain immutable.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.async-promise-executor
5
+ title: Async Promise executor function
6
+ summary: The executor passed to `new Promise` is declared `async`.
7
+ rationale: Async executors defer errors and can swallow rejections; prefer a synchronous executor that calls `resolve`/`reject`.
8
+ tags:
9
+ - correctness
10
+ - async
11
+ - rules-catalog
12
+ - crq-cor-020
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.async-promise-executor
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.async
27
+ severity: medium
28
+ confidence: 0.92
29
+ tags:
30
+ - correctness
31
+ - async
32
+ message:
33
+ title: Avoid async Promise executors
34
+ summary: "`${captures.issue.text}` is an async Promise executor, which can hide thrown errors."
35
+ remediation:
36
+ summary: Remove `async` from the executor and use `resolve`/`reject`, or wrap the async work without making the executor itself async.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.duplicate-function-parameter
5
+ title: Duplicate function parameter names
6
+ summary: A function declares the same parameter name more than once.
7
+ rationale: Duplicate parameters are confusing and usually indicate a copy-paste or merge mistake.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-017
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.duplicate-function-parameter
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.language
27
+ severity: medium
28
+ confidence: 0.95
29
+ tags:
30
+ - correctness
31
+ - language
32
+ message:
33
+ title: Remove duplicate parameter
34
+ summary: "Duplicate parameter name `${captures.issue.text}` in the same parameter list."
35
+ remediation:
36
+ summary: Rename or remove the duplicate parameter so each binding is unique.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.duplicate-import-source
5
+ title: Duplicate imports from the same module
6
+ summary: The file imports from the same module path more than once.
7
+ rationale: Multiple import declarations for one module increase bundle noise and can diverge over time.
8
+ tags:
9
+ - correctness
10
+ - modules
11
+ - rules-catalog
12
+ - crq-cor-024
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.duplicate-import-source
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.modules
27
+ severity: low
28
+ confidence: 0.9
29
+ tags:
30
+ - correctness
31
+ - modules
32
+ message:
33
+ title: Consolidate duplicate imports
34
+ summary: "`${captures.issue.text}` imports from a module path already imported above."
35
+ remediation:
36
+ summary: Merge named imports into a single `import` declaration from that module.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.duplicate-object-key
5
+ title: Duplicate keys in object literal
6
+ summary: An object literal repeats the same static property name.
7
+ rationale: Later entries silently override earlier ones, hiding bugs during refactors.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-018
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.duplicate-object-key
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.language
27
+ severity: medium
28
+ confidence: 0.95
29
+ tags:
30
+ - correctness
31
+ - language
32
+ message:
33
+ title: Resolve duplicate object key
34
+ summary: "This object literal repeats a static property key; later entries override earlier ones."
35
+ remediation:
36
+ summary: Merge the values or delete the redundant property so each key is declared once.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.duplicate-switch-case
5
+ title: Duplicate switch case labels
6
+ summary: A switch repeats the same case discriminant.
7
+ rationale: Unreachable duplicate cases usually mean a merge error or incomplete refactor.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-019
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.duplicate-switch-case
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.language
27
+ severity: medium
28
+ confidence: 0.9
29
+ tags:
30
+ - correctness
31
+ - language
32
+ message:
33
+ title: Remove duplicate switch case
34
+ summary: "This switch repeats an earlier case discriminant, so the branch is unreachable."
35
+ remediation:
36
+ summary: Delete the unreachable duplicate case or change the discriminant so each branch is distinct.
@@ -0,0 +1,35 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.empty-block-statement
5
+ title: Empty block statement
6
+ summary: A control-flow or try/catch branch uses an empty `{}` block.
7
+ rationale: Empty blocks hide missing logic, swallowed errors, or incomplete refactors and often mask bugs.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-025
13
+ stability: stable
14
+ appliesTo: file
15
+ scope:
16
+ languages:
17
+ - typescript
18
+ - javascript
19
+ match:
20
+ fact:
21
+ kind: language.empty-block-statement
22
+ bind: issue
23
+ emit:
24
+ finding:
25
+ category: correctness.language
26
+ severity: low
27
+ confidence: 0.85
28
+ tags:
29
+ - correctness
30
+ - language
31
+ message:
32
+ title: Replace or remove empty block
33
+ summary: "This block has no statements; add behavior, a comment explaining intent, or delete the branch."
34
+ remediation:
35
+ summary: Add the intended statements, throw or log in error paths, or remove the branch if it is dead code.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.identical-comparison-operands
5
+ title: Identical comparison operands
6
+ summary: Both sides of a comparison use the same source text.
7
+ rationale: Comparing an expression to itself is either always true or always false and usually indicates a copy-paste defect.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-023
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.identical-comparison-operands
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.language
27
+ severity: low
28
+ confidence: 0.85
29
+ tags:
30
+ - correctness
31
+ - language
32
+ message:
33
+ title: Fix identical comparison operands
34
+ summary: "`${captures.issue.text}` compares an expression to itself."
35
+ remediation:
36
+ summary: Replace one operand with the value you meant to compare against.
@@ -0,0 +1,35 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.reassign-catch-binding
5
+ title: Reassignment of catch binding
6
+ summary: The catch clause parameter is assigned or updated after it is bound.
7
+ rationale: Catch bindings are immutable in strict mode and confusing in sloppy mode; reassignment usually indicates a mistaken mutation of the caught error.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-026
13
+ stability: stable
14
+ appliesTo: file
15
+ scope:
16
+ languages:
17
+ - typescript
18
+ - javascript
19
+ match:
20
+ fact:
21
+ kind: language.reassign-catch-binding
22
+ bind: issue
23
+ emit:
24
+ finding:
25
+ category: correctness.language
26
+ severity: medium
27
+ confidence: 0.9
28
+ tags:
29
+ - correctness
30
+ - language
31
+ message:
32
+ title: Avoid reassigning the catch parameter
33
+ summary: "Use a new local variable instead of mutating the catch binding (for example `const err = e` then work with `err`)."
34
+ remediation:
35
+ summary: Introduce a separate variable for any transformed error value and leave the catch parameter read-only.
@@ -0,0 +1,35 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.regexp-pattern-unusual-control-character
5
+ title: Unusual ASCII control characters in regexp pattern
6
+ summary: The regular expression pattern embeds low ASCII control characters outside common whitespace.
7
+ rationale: Literal control characters in patterns are hard to read, easy to corrupt in editors, and often indicate copy-paste or encoding mistakes.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-027
13
+ stability: stable
14
+ appliesTo: file
15
+ scope:
16
+ languages:
17
+ - typescript
18
+ - javascript
19
+ match:
20
+ fact:
21
+ kind: language.regexp-pattern-unusual-control-character
22
+ bind: issue
23
+ emit:
24
+ finding:
25
+ category: correctness.language
26
+ severity: low
27
+ confidence: 0.8
28
+ tags:
29
+ - correctness
30
+ - language
31
+ message:
32
+ title: Prefer escapes instead of raw control characters in regex patterns
33
+ summary: "Replace embedded control characters with explicit escapes (for example `\\x01` or `\\u0001`) so the pattern stays visible and stable."
34
+ remediation:
35
+ summary: Rewrite the pattern using visible escape sequences or character class escapes instead of raw C0 control bytes.
@@ -0,0 +1,36 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.correctness.self-assignment
5
+ title: Self assignment
6
+ summary: An assignment uses the same expression on the left and right side.
7
+ rationale: Self-assignments are almost always dead code or a typo where a different value was intended.
8
+ tags:
9
+ - correctness
10
+ - language
11
+ - rules-catalog
12
+ - crq-cor-022
13
+ - public-directory-parity
14
+ stability: stable
15
+ appliesTo: file
16
+ scope:
17
+ languages:
18
+ - typescript
19
+ - javascript
20
+ match:
21
+ fact:
22
+ kind: language.self-assignment
23
+ bind: issue
24
+ emit:
25
+ finding:
26
+ category: correctness.language
27
+ severity: low
28
+ confidence: 0.88
29
+ tags:
30
+ - correctness
31
+ - language
32
+ message:
33
+ title: Remove self assignment
34
+ summary: "`${captures.issue.text}` assigns a variable to itself."
35
+ remediation:
36
+ summary: Delete the statement or fix the right-hand side so it references the intended value.
@@ -0,0 +1,35 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.next.server-action-missing-local-auth
5
+ title: Authenticate Next.js Server Actions before mutations
6
+ summary: Server Actions that mutate state must validate sessions locally before reaching privileged sinks.
7
+ rationale: Server Actions behave like public POST endpoints and inherit the same authentication obligations as route handlers.
8
+ tags:
9
+ - security
10
+ - next
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: function
14
+ scope:
15
+ languages:
16
+ - typescript
17
+ - javascript
18
+ match:
19
+ fact:
20
+ kind: security.next-server-action-missing-local-auth
21
+ bind: issue
22
+ emit:
23
+ finding:
24
+ category: security.authentication
25
+ severity: high
26
+ confidence: 0.77
27
+ tags:
28
+ - security
29
+ - next
30
+ message:
31
+ title: Gate Server Actions with explicit authentication checks
32
+ summary: This Server Action performs privileged work without any preceding auth helpers.
33
+ remediation:
34
+ summary: >-
35
+ Call your auth/session helper before mutations and enforce ownership inside database predicates.
@@ -0,0 +1,32 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.performance.no-array-spread-in-hot-loop
5
+ title: Avoid array spread inside hot loops
6
+ summary: Array spread or repeated concat in loops allocates per iteration and scales poorly.
7
+ rationale: Array spread or repeated concat in loops allocates per iteration and scales poorly.
8
+ tags:
9
+ - performance
10
+ - rules-catalog
11
+ stability: stable
12
+ appliesTo: block
13
+ scope:
14
+ languages:
15
+ - typescript
16
+ - javascript
17
+ match:
18
+ fact:
19
+ kind: performance.no-array-spread-in-hot-loop
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: performance.allocation
24
+ severity: high
25
+ confidence: 0.8
26
+ tags:
27
+ - performance
28
+ message:
29
+ title: Avoid array spread inside hot loops
30
+ summary: "`${captures.issue.text}` matches ts.performance.no-array-spread-in-hot-loop."
31
+ remediation:
32
+ summary: Refactor this path to avoid repeated work in hot execution paths.
@@ -0,0 +1,32 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: ts.performance.no-cache-miss-from-unstable-key
5
+ title: Avoid unstable cache-key construction
6
+ summary: Cache keys built from unstable values cause low hit rates and repeated recomputation.
7
+ rationale: Cache keys built from unstable values cause low hit rates and repeated recomputation.
8
+ tags:
9
+ - performance
10
+ - rules-catalog
11
+ stability: stable
12
+ appliesTo: block
13
+ scope:
14
+ languages:
15
+ - typescript
16
+ - javascript
17
+ match:
18
+ fact:
19
+ kind: performance.no-cache-miss-from-unstable-key
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: performance.cache
24
+ severity: medium
25
+ confidence: 0.8
26
+ tags:
27
+ - performance
28
+ message:
29
+ title: Avoid unstable cache-key construction
30
+ summary: "`${captures.issue.text}` matches ts.performance.no-cache-miss-from-unstable-key."
31
+ remediation:
32
+ summary: Refactor this path to avoid repeated work in hot execution paths.