@critiq/rules 0.0.2 → 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.
- package/README.md +52 -4
- package/catalog.yaml +985 -19
- package/package.json +6 -1
- package/rules/go/go.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/go/go.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/go/go.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/go/go.security.echo-sensitive-binding-without-validation.rule.yaml +46 -0
- package/rules/go/go.security.echo-unsafe-multipart-upload.rule.yaml +45 -0
- package/rules/go/go.security.fiber-sensitive-binding-without-validation.rule.yaml +45 -0
- package/rules/go/go.security.fiber-unsafe-multipart-upload.rule.yaml +45 -0
- package/rules/go/go.security.gin-sensitive-binding-without-validation.rule.yaml +45 -0
- package/rules/go/go.security.gin-trust-all-proxies.rule.yaml +45 -0
- package/rules/go/go.security.gin-wildcard-cors-with-credentials.rule.yaml +47 -0
- package/rules/go/go.security.net-http-missing-timeouts.rule.yaml +45 -0
- package/rules/go/go.security.sensitive-data-egress.rule.yaml +46 -0
- package/rules/go/go.security.tar-path-traversal.rule.yaml +45 -0
- package/rules/go/go.security.template-unescaped-request-value.rule.yaml +45 -0
- package/rules/go/go.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/go/go.testing.t-skip-without-ticket-reference.rule.yaml +33 -0
- package/rules/go/go.testing.time-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/java/java.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/java/java.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/java/java.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/java/java.security.android-screenshot-exposure.rule.yaml +35 -0
- package/rules/java/java.security.android-world-readable-mode.rule.yaml +35 -0
- package/rules/java/java.security.jpa-concatenated-query.rule.yaml +47 -0
- package/rules/java/java.security.reflected-output-from-request.rule.yaml +35 -0
- package/rules/java/java.security.servlet-insecure-cookie.rule.yaml +35 -0
- package/rules/java/java.security.spring-actuator-health-details-always.rule.yaml +40 -0
- package/rules/java/java.security.spring-actuator-sensitive-exposure.rule.yaml +40 -0
- package/rules/java/java.security.spring-csrf-globally-disabled.rule.yaml +49 -0
- package/rules/java/java.security.spring-debug-exposure.rule.yaml +35 -0
- package/rules/java/java.security.spring-permit-all-default.rule.yaml +47 -0
- package/rules/java/java.security.spring-webmvc-unrestricted-data-binding.rule.yaml +47 -0
- package/rules/java/java.security.template-unescaped-user-output.rule.yaml +49 -0
- package/rules/java/java.testing.disabled-without-ticket-reference.rule.yaml +33 -0
- package/rules/java/java.testing.http-client-in-unit-test.rule.yaml +33 -0
- package/rules/java/java.testing.thread-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/php/php.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/php/php.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/php/php.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/php/php.security.insecure-cors-wildcard-with-credentials.rule.yaml +41 -0
- package/rules/php/php.security.insecure-mail-or-file-transport.rule.yaml +41 -0
- package/rules/php/php.security.insecure-session-or-cookie-config.rule.yaml +42 -0
- package/rules/php/php.security.laravel-sensitive-csrf-exclusion.rule.yaml +42 -0
- package/rules/php/php.security.laravel-unsafe-blade-output.rule.yaml +42 -0
- package/rules/php/php.security.laravel-unsafe-mass-assignment.rule.yaml +45 -0
- package/rules/php/php.security.sensitive-data-egress.rule.yaml +42 -0
- package/rules/php/php.security.symfony-csrf-disabled.rule.yaml +42 -0
- package/rules/php/php.security.symfony-debug-exposure.rule.yaml +44 -0
- package/rules/php/php.security.unsafe-file-upload-handling.rule.yaml +41 -0
- package/rules/php/php.security.wordpress-missing-nonce-or-capability.rule.yaml +42 -0
- package/rules/php/php.security.wordpress-unprepared-sql.rule.yaml +42 -0
- package/rules/php/php.testing.curl-in-unit-test.rule.yaml +33 -0
- package/rules/php/php.testing.mark-test-skipped-without-ticket-reference.rule.yaml +33 -0
- package/rules/php/php.testing.sleep-in-unit-test.rule.yaml +33 -0
- package/rules/python/py.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/python/py.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/python/py.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/python/py.security.django-csrf-exempt-state-changing.rule.yaml +46 -0
- package/rules/python/py.security.django-missing-csrf-middleware.rule.yaml +47 -0
- package/rules/python/py.security.django-unsafe-production-settings.rule.yaml +47 -0
- package/rules/python/py.security.drf-allow-any-default.rule.yaml +46 -0
- package/rules/python/py.security.drf-allow-any-unsafe-method.rule.yaml +46 -0
- package/rules/python/py.security.fastapi-insecure-cors.rule.yaml +43 -0
- package/rules/python/py.security.flask-missing-upload-body-limit.rule.yaml +44 -0
- package/rules/python/py.security.flask-unsafe-html-output.rule.yaml +44 -0
- package/rules/python/py.security.flask-unsafe-upload-filename.rule.yaml +44 -0
- package/rules/python/py.testing.pytest-skip-without-ticket-reference.rule.yaml +33 -0
- package/rules/python/py.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/python/py.testing.time-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/ruby/ruby.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/ruby/ruby.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/ruby/ruby.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/ruby/ruby.security.rails-csrf-disabled.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-detailed-exceptions-enabled.rule.yaml +44 -0
- package/rules/ruby/ruby.security.rails-open-redirect.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-unsafe-html-output.rule.yaml +46 -0
- package/rules/ruby/ruby.security.rails-unsafe-render.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-unsafe-session-or-cookie-store.rule.yaml +45 -0
- package/rules/ruby/ruby.security.rails-unsafe-strong-parameters.rule.yaml +46 -0
- package/rules/ruby/ruby.security.sensitive-data-egress.rule.yaml +45 -0
- package/rules/ruby/ruby.security.sidekiq-web-unauthenticated-mount.rule.yaml +45 -0
- package/rules/ruby/ruby.testing.focused-example.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.pending-without-ticket-reference.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.skip-without-ticket-reference.rule.yaml +33 -0
- package/rules/ruby/ruby.testing.sleep-in-unit-test.rule.yaml +33 -0
- package/rules/rust/rust.performance.no-regex-construction-in-loop.rule.yaml +33 -0
- package/rules/rust/rust.performance.no-sync-fs-in-request-path.rule.yaml +33 -0
- package/rules/rust/rust.performance.no-unbounded-concurrency.rule.yaml +33 -0
- package/rules/rust/rust.security.actix-wildcard-cors-with-credentials.rule.yaml +47 -0
- package/rules/rust/rust.security.axum-body-limit-disabled.rule.yaml +45 -0
- package/rules/rust/rust.security.axum-insecure-cors-with-credentials.rule.yaml +47 -0
- package/rules/rust/rust.security.rocket-panic-prone-request-handler.rule.yaml +45 -0
- package/rules/rust/rust.security.rocket-unsafe-template-output.rule.yaml +47 -0
- package/rules/rust/rust.security.sqlx-diesel-raw-interpolated-query.rule.yaml +47 -0
- package/rules/rust/rust.security.template-unescaped-request-value.rule.yaml +47 -0
- package/rules/rust/rust.security.warp-blocking-or-panic-in-async-handler.rule.yaml +45 -0
- package/rules/rust/rust.testing.ignore-without-ticket-reference.rule.yaml +33 -0
- package/rules/rust/rust.testing.real-network-in-unit-test.rule.yaml +33 -0
- package/rules/rust/rust.testing.thread-sleep-in-unit-test.rule.yaml +33 -0
- package/rules/shared/security.archive-path-traversal.rule.yaml +41 -0
- package/rules/shared/security.external-file-upload.rule.yaml +40 -0
- package/rules/shared/security.permissive-file-permissions.rule.yaml +40 -0
- package/rules/shared/security.sensitive-data-egress.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.assignment-in-condition.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.assignment-to-import-binding.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.async-promise-executor.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-function-parameter.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-import-source.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-object-key.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.duplicate-switch-case.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.empty-block-statement.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.identical-comparison-operands.rule.yaml +36 -0
- package/rules/typescript/ts.correctness.reassign-catch-binding.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.regexp-pattern-unusual-control-character.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.self-assignment.rule.yaml +36 -0
- package/rules/typescript/ts.next.server-action-missing-local-auth.rule.yaml +35 -0
- package/rules/typescript/ts.performance.no-array-spread-in-hot-loop.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-cache-miss-from-unstable-key.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-expensive-sort-in-render-path.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-json-parse-stringify-clone.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-large-object-spread-in-loop.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-n-plus-one-await-in-map.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-redundant-network-fetch.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-regex-construction-in-loop.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-sync-fs-in-request-path.rule.yaml +32 -0
- package/rules/typescript/ts.performance.no-unbounded-concurrency.rule.yaml +32 -0
- package/rules/typescript/ts.quality.no-ambiguous-abbreviations.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-barrel-file-cycle.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-boolean-parameter-trap.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-dead-export.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-hidden-side-effect-import.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-inconsistent-error-shape.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-mixed-abstraction-level.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-primitive-obsession-in-domain-model.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-temporal-coupling.rule.yaml +27 -0
- package/rules/typescript/ts.quality.no-wide-public-surface.rule.yaml +27 -0
- package/rules/typescript/ts.react.no-accessibility-label-missing.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-activedescendant-on-non-focusable-host.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-click-without-keyboard-handler.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-deprecated-create-factory.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-deprecated-react-dom-root-api.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-derived-state-from-props.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-effect-fetch-without-cancellation.rule.yaml +35 -0
- package/rules/typescript/ts.react.no-find-dom-node.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-img-missing-alt-text.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-index-as-key-in-dynamic-list.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-interactive-role-on-static-semantics.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-invalid-anchor-href.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-keyboard-interaction-without-widget-role.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-legacy-lifecycle.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-missing-error-boundary.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-positive-tabindex.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-static-element-with-synthetic-handlers.rule.yaml +36 -0
- package/rules/typescript/ts.react.no-string-ref.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-uncontrolled-to-controlled-input.rule.yaml +34 -0
- package/rules/typescript/ts.react.no-widget-role-without-tabindex.rule.yaml +36 -0
- package/rules/typescript/ts.security.ajv-insecure-configuration.rule.yaml +34 -0
- package/rules/typescript/ts.security.angular-dom-sanitizer-bypass-untrusted-input.rule.yaml +35 -0
- package/rules/typescript/ts.security.apollo-server-csrf-disabled.rule.yaml +36 -0
- package/rules/typescript/ts.security.apollo-server-graphql-dev-tooling-exposure.rule.yaml +36 -0
- package/rules/typescript/ts.security.apollo-server-introspection-exposure.rule.yaml +35 -0
- package/rules/typescript/ts.security.apollo-server-missing-query-limits.rule.yaml +35 -0
- package/rules/typescript/ts.security.astro-vite-public-secret-define.rule.yaml +39 -0
- package/rules/typescript/ts.security.debug-statement-in-source.rule.yaml +36 -0
- package/rules/typescript/ts.security.electron-dangerous-webpreferences.rule.yaml +35 -0
- package/rules/typescript/ts.security.electron-insecure-local-state.rule.yaml +35 -0
- package/rules/typescript/ts.security.electron-missing-ipc-origin-check.rule.yaml +35 -0
- package/rules/typescript/ts.security.electron-shell-open-external-unvalidated.rule.yaml +35 -0
- package/rules/typescript/ts.security.express-error-handler-information-disclosure.rule.yaml +35 -0
- package/rules/typescript/ts.security.express-static-dotfiles-allow.rule.yaml +35 -0
- package/rules/typescript/ts.security.express-unbounded-body-parser.rule.yaml +34 -0
- package/rules/typescript/ts.security.express-user-controlled-static-mount.rule.yaml +35 -0
- package/rules/typescript/ts.security.fastify-excessive-body-limit.rule.yaml +34 -0
- package/rules/typescript/ts.security.fastify-public-bind-without-trust-proxy.rule.yaml +38 -0
- package/rules/typescript/ts.security.graphql-upload-without-csrf-guard.rule.yaml +36 -0
- package/rules/typescript/ts.security.iframe-missing-sandbox-attribute.rule.yaml +35 -0
- package/rules/typescript/ts.security.insecure-content-security-policy-literal.rule.yaml +35 -0
- package/rules/typescript/ts.security.insecure-helmet-hardening-options.rule.yaml +36 -0
- package/rules/typescript/ts.security.jwt-insecure-signing-algorithm.rule.yaml +35 -0
- package/rules/typescript/ts.security.legacy-buffer-constructor.rule.yaml +35 -0
- package/rules/typescript/ts.security.log-injection.rule.yaml +36 -0
- package/rules/typescript/ts.security.nestjs-helmet-after-route-mount.rule.yaml +34 -0
- package/rules/typescript/ts.security.nestjs-missing-global-validation-pipe.rule.yaml +35 -0
- package/rules/typescript/ts.security.nestjs-skip-throttle-sensitive-route.rule.yaml +35 -0
- package/rules/typescript/ts.security.nestjs-validation-pipe-without-whitelist.rule.yaml +36 -0
- package/rules/typescript/ts.security.nuxt-public-runtime-secret.rule.yaml +38 -0
- package/rules/typescript/ts.security.open-redirect.rule.yaml +2 -0
- package/rules/typescript/ts.security.request-driven-array-index-access.rule.yaml +33 -0
- package/rules/typescript/ts.security.sensitive-data-egress.rule.yaml +1 -0
- package/rules/typescript/ts.security.ssrf.rule.yaml +1 -0
- package/rules/typescript/ts.security.unsafe-dompurify-version.rule.yaml +36 -0
- package/rules/typescript/ts.security.unsafe-marked-version.rule.yaml +36 -0
- package/rules/typescript/ts.security.xml-parse-string-with-untrusted-input.rule.yaml +35 -0
- package/rules/typescript/ts.testing.no-flaky-timer-test.rule.yaml +38 -0
- package/rules/typescript/ts.testing.no-focused-test.rule.yaml +34 -0
- package/rules/typescript/ts.testing.no-missing-edge-case-tests.rule.yaml +35 -0
- package/rules/typescript/ts.testing.no-network-call-in-unit-test.rule.yaml +38 -0
- package/rules/typescript/ts.testing.no-skipped-test-without-ticket.rule.yaml +34 -0
- package/rules/typescript/ts.testing.no-snapshot-without-intent.rule.yaml +34 -0
- 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.
|