@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,42 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: php.security.wordpress-unprepared-sql
5
+ title: Use `$wpdb->prepare` for dynamic WordPress SQL
6
+ summary: >-
7
+ WordPress SQL calls should not interpolate request values directly into query strings.
8
+ rationale: >-
9
+ Dynamic SQL without `$wpdb->prepare` enables injection and unauthorized data access/manipulation.
10
+ tags:
11
+ - security
12
+ - php
13
+ - wordpress
14
+ - sql-injection
15
+ - rules-catalog
16
+ stability: stable
17
+ appliesTo: block
18
+ scope:
19
+ languages:
20
+ - php
21
+ paths:
22
+ include:
23
+ - "**/*.php"
24
+ match:
25
+ fact:
26
+ kind: php.security.wordpress-unprepared-sql
27
+ bind: issue
28
+ emit:
29
+ finding:
30
+ category: security.input-validation
31
+ severity: high
32
+ confidence: 0.9
33
+ tags:
34
+ - security
35
+ - php
36
+ - wordpress
37
+ message:
38
+ title: Parameterize SQL near `${captures.issue.text}`
39
+ summary: "`${captures.issue.text}` concatenates request data into a WordPress SQL call without `$wpdb->prepare`."
40
+ remediation:
41
+ summary: >-
42
+ Build SQL through `$wpdb->prepare` placeholders and sanitize scalar inputs before passing them to query execution calls.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: php.testing.curl-in-unit-test
5
+ title: Avoid raw curl calls in PHP unit tests
6
+ summary: curl_exec in tests should target doubles or local fixtures.
7
+ rationale: Live HTTP couples CI to the network.
8
+ tags:
9
+ - testing
10
+ - php
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - php
17
+ match:
18
+ fact:
19
+ kind: php.testing.curl-in-unit-test
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: quality.testing
24
+ severity: medium
25
+ confidence: 0.62
26
+ tags:
27
+ - testing
28
+ - php
29
+ message:
30
+ title: Stub outbound HTTP in `${captures.issue.text}`
31
+ summary: "`${captures.issue.text}` uses curl primitives inside a test-like path."
32
+ remediation:
33
+ summary: Wrap HTTP behind an injectable client and replace curl usage with doubles in unit tests.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: php.testing.mark-test-skipped-without-ticket-reference
5
+ title: markTestSkipped should cite a ticket
6
+ summary: Empty markTestSkipped() calls without a tracker note are hard to triage.
7
+ rationale: Skips should carry reviewable intent.
8
+ tags:
9
+ - testing
10
+ - php
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - php
17
+ match:
18
+ fact:
19
+ kind: php.testing.mark-test-skipped-without-ticket-reference
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: quality.testing
24
+ severity: medium
25
+ confidence: 0.64
26
+ tags:
27
+ - testing
28
+ - php
29
+ message:
30
+ title: Add a ticket reference to `${captures.issue.text}`
31
+ summary: "`markTestSkipped()` is used without arguments and without a nearby issue reference."
32
+ remediation:
33
+ summary: Pass a reason string with a tracker id or document the suppression inline.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: php.testing.sleep-in-unit-test
5
+ title: Avoid sleep in PHP unit tests
6
+ summary: sleep() in tests slows CI and hides synchronization bugs.
7
+ rationale: Prefer deterministic waits or clock injection.
8
+ tags:
9
+ - testing
10
+ - php
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - php
17
+ match:
18
+ fact:
19
+ kind: php.testing.sleep-in-unit-test
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: quality.testing
24
+ severity: low
25
+ confidence: 0.58
26
+ tags:
27
+ - testing
28
+ - php
29
+ message:
30
+ title: Replace `sleep` in unit tests
31
+ summary: "`${captures.issue.text}` blocks on real wall-clock time inside a test-like path."
32
+ remediation:
33
+ summary: Inject a clock, shorten waits, or move timing coverage to integration suites.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.performance.no-regex-construction-in-loop
5
+ title: Avoid no regex construction in loop
6
+ summary: Performance hygiene signal for python sources.
7
+ rationale: Performance hygiene signal for python sources.
8
+ tags:
9
+ - performance
10
+ - python
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - python
17
+ match:
18
+ fact:
19
+ kind: py.performance.no-regex-construction-in-loop
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: performance.allocation
24
+ severity: medium
25
+ confidence: 0.66
26
+ tags:
27
+ - performance
28
+ - python
29
+ message:
30
+ title: Avoid no regex construction in loop in `python` code
31
+ summary: "`${captures.issue.text}` matches py.performance.no-regex-construction-in-loop."
32
+ remediation:
33
+ summary: Refactor this path to reduce avoidable runtime overhead.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.performance.no-sync-fs-in-request-path
5
+ title: Avoid no sync fs in request path
6
+ summary: Performance hygiene signal for python sources.
7
+ rationale: Performance hygiene signal for python sources.
8
+ tags:
9
+ - performance
10
+ - python
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - python
17
+ match:
18
+ fact:
19
+ kind: py.performance.no-sync-fs-in-request-path
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: performance.io
24
+ severity: high
25
+ confidence: 0.66
26
+ tags:
27
+ - performance
28
+ - python
29
+ message:
30
+ title: Avoid no sync fs in request path in `python` code
31
+ summary: "`${captures.issue.text}` matches py.performance.no-sync-fs-in-request-path."
32
+ remediation:
33
+ summary: Refactor this path to reduce avoidable runtime overhead.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.performance.no-unbounded-concurrency
5
+ title: Avoid no unbounded concurrency
6
+ summary: Performance hygiene signal for python sources.
7
+ rationale: Performance hygiene signal for python sources.
8
+ tags:
9
+ - performance
10
+ - python
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - python
17
+ match:
18
+ fact:
19
+ kind: py.performance.no-unbounded-concurrency
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: performance.async
24
+ severity: medium
25
+ confidence: 0.66
26
+ tags:
27
+ - performance
28
+ - python
29
+ message:
30
+ title: Avoid no unbounded concurrency in `python` code
31
+ summary: "`${captures.issue.text}` matches py.performance.no-unbounded-concurrency."
32
+ remediation:
33
+ summary: Refactor this path to reduce avoidable runtime overhead.
@@ -0,0 +1,46 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.django-csrf-exempt-state-changing
5
+ title: Avoid CSRF exemptions on state-changing Django views
6
+ summary: Browser-facing Django views that change state should remain CSRF-protected unless they are explicitly token-authenticated APIs.
7
+ rationale: >-
8
+ Using django.decorators.csrf.csrf_exempt removes CSRF defenses for session-backed browsers,
9
+ enabling cross-site request forgery against unsafe methods.
10
+ tags:
11
+ - security
12
+ - python
13
+ - django
14
+ - csrf
15
+ - rules-catalog
16
+ stability: stable
17
+ appliesTo: block
18
+ scope:
19
+ languages:
20
+ - python
21
+ paths:
22
+ include:
23
+ - "**/*.py"
24
+ exclude:
25
+ - "**/tests/**"
26
+ - "**/test_*.py"
27
+ - "**/*_test.py"
28
+ - "**/migrations/**"
29
+ match:
30
+ fact:
31
+ kind: python.security.django-csrf-exempt-state-changing
32
+ bind: issue
33
+ emit:
34
+ finding:
35
+ category: security.authentication
36
+ severity: high
37
+ confidence: 0.82
38
+ tags:
39
+ - security
40
+ - django
41
+ - csrf
42
+ message:
43
+ title: Review CSRF exemption `${captures.issue.text}`
44
+ summary: "`${captures.issue.text}` is applied near code that handles POST/PUT/PATCH/DELETE or `request.POST`, which is risky for browser sessions."
45
+ remediation:
46
+ summary: Remove `@csrf_exempt`, enforce CSRF tokens for browser views, or constrain the endpoint to non-session authentication with explicit CSRF policy.
@@ -0,0 +1,47 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.django-missing-csrf-middleware
5
+ title: Enable Django CSRF middleware for browser apps
6
+ summary: Django projects using cookie-backed sessions should include `CsrfViewMiddleware` in `MIDDLEWARE`.
7
+ rationale: Without CSRF middleware, Django cannot enforce CSRF tokens on unsafe HTTP methods for browser clients.
8
+ tags:
9
+ - security
10
+ - python
11
+ - django
12
+ - csrf
13
+ - rules-catalog
14
+ stability: stable
15
+ appliesTo: block
16
+ scope:
17
+ languages:
18
+ - python
19
+ paths:
20
+ include:
21
+ - "**/settings/**/*.py"
22
+ - "**/*settings*.py"
23
+ exclude:
24
+ - "**/settings/local.py"
25
+ - "**/settings/dev.py"
26
+ - "**/tests/**"
27
+ - "**/test_*.py"
28
+ - "**/*_test.py"
29
+ - "**/migrations/**"
30
+ match:
31
+ fact:
32
+ kind: python.security.django-missing-csrf-middleware
33
+ bind: issue
34
+ emit:
35
+ finding:
36
+ category: security.misconfiguration
37
+ severity: medium
38
+ confidence: 0.78
39
+ tags:
40
+ - security
41
+ - django
42
+ - csrf
43
+ message:
44
+ title: Add CSRF middleware to Django `${captures.issue.text}`
45
+ summary: "`MIDDLEWARE` is declared without `django.middleware.csrf.CsrfViewMiddleware`, which disables framework CSRF checks."
46
+ remediation:
47
+ summary: Insert `django.middleware.csrf.CsrfViewMiddleware` into `MIDDLEWARE` according to the Django deployment checklist ordering guidance.
@@ -0,0 +1,47 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.django-unsafe-production-settings
5
+ title: Avoid unsafe Django production settings
6
+ summary: Production Django settings should disable debug mode, restrict hosts, protect secrets, and enable HTTPS-aligned cookie flags.
7
+ rationale: Misconfigured Django defaults expose debug traces, enable host header attacks, leak secrets, and weaken cookie transport protections.
8
+ tags:
9
+ - security
10
+ - python
11
+ - django
12
+ - configuration
13
+ - rules-catalog
14
+ stability: stable
15
+ appliesTo: block
16
+ scope:
17
+ languages:
18
+ - python
19
+ paths:
20
+ include:
21
+ - "**/settings/**/*.py"
22
+ - "**/*settings*.py"
23
+ exclude:
24
+ - "**/settings/local.py"
25
+ - "**/settings/dev.py"
26
+ - "**/tests/**"
27
+ - "**/test_*.py"
28
+ - "**/*_test.py"
29
+ - "**/migrations/**"
30
+ match:
31
+ fact:
32
+ kind: python.security.django-unsafe-production-settings
33
+ bind: issue
34
+ emit:
35
+ finding:
36
+ category: security.misconfiguration
37
+ severity: high
38
+ confidence: 0.88
39
+ tags:
40
+ - security
41
+ - django
42
+ - configuration
43
+ message:
44
+ title: Fix risky Django setting `${captures.issue.text}`
45
+ summary: "`${captures.issue.text}` weakens production security posture for Django deployment."
46
+ remediation:
47
+ summary: Align settings with your deployment checklist—disable DEBUG, pin ALLOWED_HOSTS, load secrets from the environment, and enable secure cookie and HTTPS flags.
@@ -0,0 +1,46 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.drf-allow-any-default
5
+ title: Avoid AllowAny as DRF default permission
6
+ summary: Django REST Framework APIs should default to authenticated permission classes instead of `AllowAny`.
7
+ rationale: Default `AllowAny` exposes mutation-heavy APIs unless every view overrides permissions explicitly.
8
+ tags:
9
+ - security
10
+ - python
11
+ - django
12
+ - drf
13
+ - authorization
14
+ - rules-catalog
15
+ stability: stable
16
+ appliesTo: block
17
+ scope:
18
+ languages:
19
+ - python
20
+ paths:
21
+ include:
22
+ - "**/*.py"
23
+ exclude:
24
+ - "**/tests/**"
25
+ - "**/test_*.py"
26
+ - "**/*_test.py"
27
+ - "**/migrations/**"
28
+ match:
29
+ fact:
30
+ kind: python.security.drf-allow-any-default
31
+ bind: issue
32
+ emit:
33
+ finding:
34
+ category: security.authorization
35
+ severity: high
36
+ confidence: 0.85
37
+ tags:
38
+ - security
39
+ - django
40
+ - drf
41
+ - authorization
42
+ message:
43
+ title: Replace permissive DRF defaults `${captures.issue.text}`
44
+ summary: "`REST_FRAMEWORK` enables `AllowAny` via `DEFAULT_PERMISSION_CLASSES`, which is unsafe for default API posture."
45
+ remediation:
46
+ summary: Prefer `IsAuthenticated` or another restrictive default, then opt-in public access only where documented.
@@ -0,0 +1,46 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.drf-allow-any-unsafe-method
5
+ title: Avoid AllowAny on unsafe DRF methods
6
+ summary: DRF views that accept POST, PUT, PATCH, or DELETE should not declare `AllowAny` unless the endpoint is intentionally public.
7
+ rationale: Open unsafe methods allow unauthenticated clients to mutate data and violate least-privilege API access.
8
+ tags:
9
+ - security
10
+ - python
11
+ - django
12
+ - drf
13
+ - authorization
14
+ - rules-catalog
15
+ stability: stable
16
+ appliesTo: block
17
+ scope:
18
+ languages:
19
+ - python
20
+ paths:
21
+ include:
22
+ - "**/*.py"
23
+ exclude:
24
+ - "**/tests/**"
25
+ - "**/test_*.py"
26
+ - "**/*_test.py"
27
+ - "**/migrations/**"
28
+ match:
29
+ fact:
30
+ kind: python.security.drf-allow-any-unsafe-method
31
+ bind: issue
32
+ emit:
33
+ finding:
34
+ category: security.authorization
35
+ severity: high
36
+ confidence: 0.8
37
+ tags:
38
+ - security
39
+ - django
40
+ - drf
41
+ - authorization
42
+ message:
43
+ title: Tighten permissions around `${captures.issue.text}`
44
+ summary: "`${captures.issue.text}` combines `AllowAny` with an unsafe HTTP method declaration."
45
+ remediation:
46
+ summary: Require authentication or scoped permissions for unsafe verbs unless the handler is explicitly public and documented.
@@ -0,0 +1,43 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.fastapi-insecure-cors
5
+ title: Avoid permissive FastAPI CORS with credentials
6
+ summary: FastAPI `CORSMiddleware` should not combine wildcard origins, methods, or headers with `allow_credentials=True`.
7
+ rationale: Wildcard CORS policies plus credentials mirror insecure browser CORS combinations that attackers can abuse from malicious origins.
8
+ tags:
9
+ - security
10
+ - python
11
+ - fastapi
12
+ - cors
13
+ - rules-catalog
14
+ stability: stable
15
+ appliesTo: block
16
+ scope:
17
+ languages:
18
+ - python
19
+ paths:
20
+ include:
21
+ - "**/*.py"
22
+ exclude:
23
+ - "**/tests/**"
24
+ - "**/test_*.py"
25
+ - "**/*_test.py"
26
+ match:
27
+ fact:
28
+ kind: python.security.fastapi-insecure-cors
29
+ bind: issue
30
+ emit:
31
+ finding:
32
+ category: security.misconfiguration
33
+ severity: high
34
+ confidence: 0.87
35
+ tags:
36
+ - security
37
+ - fastapi
38
+ - cors
39
+ message:
40
+ title: Tighten FastAPI CORS `${captures.issue.text}`
41
+ summary: "`${captures.issue.text}` configures `CORSMiddleware` with wildcards while credentials are enabled."
42
+ remediation:
43
+ summary: Replace wildcard origins, methods, and headers with explicit allowlists when credentials are required.
@@ -0,0 +1,44 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.flask-missing-upload-body-limit
5
+ title: Set Flask MAX_CONTENT_LENGTH for uploads
6
+ summary: Flask apps handling uploads should configure `MAX_CONTENT_LENGTH` to bound request bodies.
7
+ rationale: Missing upload limits enables trivial denial-of-service via oversized multipart payloads.
8
+ tags:
9
+ - security
10
+ - python
11
+ - flask
12
+ - upload
13
+ - dos
14
+ - rules-catalog
15
+ stability: stable
16
+ appliesTo: file
17
+ scope:
18
+ languages:
19
+ - python
20
+ paths:
21
+ include:
22
+ - "**/*.py"
23
+ exclude:
24
+ - "**/tests/**"
25
+ - "**/test_*.py"
26
+ - "**/*_test.py"
27
+ match:
28
+ fact:
29
+ kind: python.security.flask-missing-upload-body-limit
30
+ bind: issue
31
+ emit:
32
+ finding:
33
+ category: security.filesystem
34
+ severity: medium
35
+ confidence: 0.72
36
+ tags:
37
+ - security
38
+ - flask
39
+ - upload
40
+ message:
41
+ title: Add upload size limits near `${captures.issue.text}`
42
+ summary: "Upload handling references `${captures.issue.text}` but no `MAX_CONTENT_LENGTH` configuration was detected in this file."
43
+ remediation:
44
+ summary: Set `app.config["MAX_CONTENT_LENGTH"]` (or equivalent) to a bounded maximum aligned with product limits.
@@ -0,0 +1,44 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.flask-unsafe-html-output
5
+ title: Avoid Flask markup helpers fed by request data
6
+ summary: Flask responses should not bypass escaping when interpolating `request` input into HTML helpers or template strings.
7
+ rationale: >-
8
+ Markup helpers, render_template_string, and Jinja safe filters bypass escaping and commonly become XSS sinks.
9
+ tags:
10
+ - security
11
+ - python
12
+ - flask
13
+ - xss
14
+ - rules-catalog
15
+ stability: stable
16
+ appliesTo: block
17
+ scope:
18
+ languages:
19
+ - python
20
+ paths:
21
+ include:
22
+ - "**/*.py"
23
+ exclude:
24
+ - "**/tests/**"
25
+ - "**/test_*.py"
26
+ - "**/*_test.py"
27
+ match:
28
+ fact:
29
+ kind: python.security.flask-unsafe-html-output
30
+ bind: issue
31
+ emit:
32
+ finding:
33
+ category: security.output-encoding
34
+ severity: high
35
+ confidence: 0.86
36
+ tags:
37
+ - security
38
+ - flask
39
+ - xss
40
+ message:
41
+ title: Remove unsafe HTML composition `${captures.issue.text}`
42
+ summary: "`${captures.issue.text}` mixes request-controlled values with markup helpers or unescaped template paths."
43
+ remediation:
44
+ summary: Use automatic escaping, `render_template` with trusted contexts, or a vetted sanitizer instead of raw markup shortcuts.
@@ -0,0 +1,44 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.security.flask-unsafe-upload-filename
5
+ title: Sanitize Flask upload filenames before saving
6
+ summary: Flask upload handlers should pass filenames through `secure_filename` (or equivalent) before persisting to disk.
7
+ rationale: Attacker-controlled filenames enable traversal sequences, extension spoofing, and collisions when saved verbatim.
8
+ tags:
9
+ - security
10
+ - python
11
+ - flask
12
+ - filesystem
13
+ - upload
14
+ - rules-catalog
15
+ stability: stable
16
+ appliesTo: block
17
+ scope:
18
+ languages:
19
+ - python
20
+ paths:
21
+ include:
22
+ - "**/*.py"
23
+ exclude:
24
+ - "**/tests/**"
25
+ - "**/test_*.py"
26
+ - "**/*_test.py"
27
+ match:
28
+ fact:
29
+ kind: python.security.flask-unsafe-upload-filename
30
+ bind: issue
31
+ emit:
32
+ finding:
33
+ category: security.filesystem
34
+ severity: high
35
+ confidence: 0.9
36
+ tags:
37
+ - security
38
+ - flask
39
+ - upload
40
+ message:
41
+ title: Harden upload save `${captures.issue.text}`
42
+ summary: "`${captures.issue.text}` persists uploads using an unsanitized client-provided filename."
43
+ remediation:
44
+ summary: Generate trusted server-side names or wrap uploads with `werkzeug.utils.secure_filename` before calling `save`.
@@ -0,0 +1,33 @@
1
+ apiVersion: critiq.dev/v1alpha1
2
+ kind: Rule
3
+ metadata:
4
+ id: py.testing.pytest-skip-without-ticket-reference
5
+ title: pytest.mark.skip should include a reason or ticket
6
+ summary: Skips without `reason=` or a nearby tracker reference are hard to triage.
7
+ rationale: Silent pytest skips accumulate unless they carry reviewable intent.
8
+ tags:
9
+ - testing
10
+ - python
11
+ - rules-catalog
12
+ stability: experimental
13
+ appliesTo: block
14
+ scope:
15
+ languages:
16
+ - python
17
+ match:
18
+ fact:
19
+ kind: py.testing.pytest-skip-without-ticket-reference
20
+ bind: issue
21
+ emit:
22
+ finding:
23
+ category: quality.testing
24
+ severity: medium
25
+ confidence: 0.68
26
+ tags:
27
+ - testing
28
+ - python
29
+ message:
30
+ title: Document `@pytest.mark.skip` with reason or ticket
31
+ summary: "`${captures.issue.text}` marks a skip without `reason=` and without a nearby issue reference."
32
+ remediation:
33
+ summary: Add `reason=` with a tracker id or move the skip behind a feature flag with expiry notes.