@critiq/rules 0.0.1
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 +169 -0
- package/catalog.yaml +599 -0
- package/package.json +21 -0
- package/rules/shared/security.insecure-http-transport.rule.yaml +42 -0
- package/rules/shared/security.no-command-execution-with-request-input.rule.yaml +42 -0
- package/rules/shared/security.no-hardcoded-credentials.rule.yaml +42 -0
- package/rules/shared/security.no-request-path-file-read.rule.yaml +42 -0
- package/rules/shared/security.no-sensitive-data-in-logs-and-telemetry.rule.yaml +44 -0
- package/rules/shared/security.no-sql-interpolation.rule.yaml +42 -0
- package/rules/shared/security.tls-verification-disabled.rule.yaml +42 -0
- package/rules/shared/security.unsafe-deserialization.rule.yaml +41 -0
- package/rules/shared/security.weak-hash-algorithm.rule.yaml +41 -0
- package/rules/typescript/ts.config.no-process-env-outside-config.rule.yaml +37 -0
- package/rules/typescript/ts.correctness.blocking-call-in-async-flow.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.constant-condition.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.implicit-undefined-return.rule.yaml +34 -0
- package/rules/typescript/ts.correctness.incorrect-boolean-logic.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.missing-await-on-async-call.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.missing-default-dispatch.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.missing-timeout-on-external-call.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.nested-property-access-without-check.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.off-by-one-loop-boundary.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.optional-value-without-fallback.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.possible-null-dereference.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.shared-state-race.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.unchecked-map-key-access.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.unhandled-async-error.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.unreachable-statement.rule.yaml +40 -0
- package/rules/typescript/ts.logging.no-console-error.rule.yaml +34 -0
- package/rules/typescript/ts.logging.no-console-log.rule.yaml +34 -0
- package/rules/typescript/ts.next.no-server-client-boundary-leaks.rule.yaml +36 -0
- package/rules/typescript/ts.performance.inefficient-data-structure-usage.rule.yaml +35 -0
- package/rules/typescript/ts.performance.large-payload-without-streaming.rule.yaml +35 -0
- package/rules/typescript/ts.performance.missing-batch-operations.rule.yaml +35 -0
- package/rules/typescript/ts.performance.nested-loops-hot-path.rule.yaml +35 -0
- package/rules/typescript/ts.performance.repeated-expensive-computation.rule.yaml +35 -0
- package/rules/typescript/ts.performance.repeated-io-in-loop.rule.yaml +35 -0
- package/rules/typescript/ts.performance.retained-large-object.rule.yaml +35 -0
- package/rules/typescript/ts.performance.sequential-async-calls.rule.yaml +35 -0
- package/rules/typescript/ts.performance.unbounded-growth-memory-leak.rule.yaml +35 -0
- package/rules/typescript/ts.performance.unnecessary-rerenders-from-state-misuse.rule.yaml +35 -0
- package/rules/typescript/ts.quality.deep-nesting.rule.yaml +35 -0
- package/rules/typescript/ts.quality.duplicate-code-block.rule.yaml +35 -0
- package/rules/typescript/ts.quality.function-too-large-or-complex.rule.yaml +35 -0
- package/rules/typescript/ts.quality.hardcoded-configuration-values.rule.yaml +35 -0
- package/rules/typescript/ts.quality.logic-change-without-test-updates.rule.yaml +36 -0
- package/rules/typescript/ts.quality.magic-numbers-or-strings.rule.yaml +35 -0
- package/rules/typescript/ts.quality.missing-error-context.rule.yaml +35 -0
- package/rules/typescript/ts.quality.missing-tests-for-critical-logic.rule.yaml +35 -0
- package/rules/typescript/ts.quality.swallowed-error.rule.yaml +35 -0
- package/rules/typescript/ts.quality.tight-module-coupling.rule.yaml +35 -0
- package/rules/typescript/ts.random.no-math-random-in-core.rule.yaml +37 -0
- package/rules/typescript/ts.react.no-cascaded-effect-fetches.rule.yaml +37 -0
- package/rules/typescript/ts.runtime.no-debugger-statement.rule.yaml +29 -0
- package/rules/typescript/ts.security.bind-to-all-interfaces.rule.yaml +36 -0
- package/rules/typescript/ts.security.browser-token-storage.rule.yaml +37 -0
- package/rules/typescript/ts.security.dangerous-insert-html.rule.yaml +36 -0
- package/rules/typescript/ts.security.dangerously-set-inner-html.rule.yaml +38 -0
- package/rules/typescript/ts.security.datadog-browser-track-user-interactions.rule.yaml +37 -0
- package/rules/typescript/ts.security.debug-mode-enabled.rule.yaml +38 -0
- package/rules/typescript/ts.security.dynamodb-query-injection.rule.yaml +36 -0
- package/rules/typescript/ts.security.exposed-directory-listing.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-cookie-missing-http-only.rule.yaml +36 -0
- package/rules/typescript/ts.security.express-default-cookie-config.rule.yaml +39 -0
- package/rules/typescript/ts.security.express-default-session-config.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-insecure-cookie.rule.yaml +36 -0
- package/rules/typescript/ts.security.express-missing-helmet.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-nosql-injection.rule.yaml +36 -0
- package/rules/typescript/ts.security.express-permissive-cookie-config.rule.yaml +38 -0
- package/rules/typescript/ts.security.express-reduce-fingerprint.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-static-assets-after-session.rule.yaml +37 -0
- package/rules/typescript/ts.security.external-file-upload.rule.yaml +36 -0
- package/rules/typescript/ts.security.file-generation.rule.yaml +36 -0
- package/rules/typescript/ts.security.format-string-using-user-input.rule.yaml +36 -0
- package/rules/typescript/ts.security.frontend-only-authorization.rule.yaml +35 -0
- package/rules/typescript/ts.security.handlebars-no-escape.rule.yaml +38 -0
- package/rules/typescript/ts.security.hardcoded-auth-secret.rule.yaml +37 -0
- package/rules/typescript/ts.security.import-using-user-input.rule.yaml +36 -0
- package/rules/typescript/ts.security.information-leakage.rule.yaml +38 -0
- package/rules/typescript/ts.security.insecure-allow-origin.rule.yaml +36 -0
- package/rules/typescript/ts.security.insecure-auth-cookie-flags.rule.yaml +37 -0
- package/rules/typescript/ts.security.insecure-password-hash-configuration.rule.yaml +37 -0
- package/rules/typescript/ts.security.insecure-websocket-transport.rule.yaml +37 -0
- package/rules/typescript/ts.security.insufficiently-random-values.rule.yaml +36 -0
- package/rules/typescript/ts.security.jwt-not-revoked.rule.yaml +37 -0
- package/rules/typescript/ts.security.jwt-sensitive-claims.rule.yaml +37 -0
- package/rules/typescript/ts.security.manual-html-sanitization.rule.yaml +37 -0
- package/rules/typescript/ts.security.missing-authorization-before-sensitive-action.rule.yaml +35 -0
- package/rules/typescript/ts.security.missing-integrity-check.rule.yaml +36 -0
- package/rules/typescript/ts.security.missing-message-origin-check.rule.yaml +36 -0
- package/rules/typescript/ts.security.missing-ownership-validation.rule.yaml +35 -0
- package/rules/typescript/ts.security.missing-request-timeout-or-retry.rule.yaml +35 -0
- package/rules/typescript/ts.security.no-dynamic-execution.rule.yaml +34 -0
- package/rules/typescript/ts.security.no-innerhtml-assignment.rule.yaml +36 -0
- package/rules/typescript/ts.security.non-literal-fs-filename.rule.yaml +36 -0
- package/rules/typescript/ts.security.observable-timing-discrepancy.rule.yaml +37 -0
- package/rules/typescript/ts.security.open-redirect.rule.yaml +37 -0
- package/rules/typescript/ts.security.permissive-allow-origin.rule.yaml +36 -0
- package/rules/typescript/ts.security.permissive-file-permissions.rule.yaml +37 -0
- package/rules/typescript/ts.security.postmessage-wildcard-origin.rule.yaml +36 -0
- package/rules/typescript/ts.security.predictable-token-generation.rule.yaml +36 -0
- package/rules/typescript/ts.security.raw-html-using-user-input.rule.yaml +37 -0
- package/rules/typescript/ts.security.sensitive-data-egress.rule.yaml +36 -0
- package/rules/typescript/ts.security.sensitive-data-in-exception.rule.yaml +37 -0
- package/rules/typescript/ts.security.sensitive-data-written-to-file.rule.yaml +37 -0
- package/rules/typescript/ts.security.ssrf.rule.yaml +34 -0
- package/rules/typescript/ts.security.token-or-session-not-validated.rule.yaml +35 -0
- package/rules/typescript/ts.security.ui-redress.rule.yaml +37 -0
- package/rules/typescript/ts.security.unsanitized-http-response.rule.yaml +36 -0
- package/rules/typescript/ts.security.unvalidated-external-input.rule.yaml +35 -0
- package/rules/typescript/ts.security.user-controlled-sendfile.rule.yaml +36 -0
- package/rules/typescript/ts.security.user-controlled-view-render.rule.yaml +36 -0
- package/rules/typescript/ts.security.weak-cipher-or-mode.rule.yaml +35 -0
- package/rules/typescript/ts.security.weak-key-strength.rule.yaml +36 -0
- package/rules/typescript/ts.security.weak-tls-version.rule.yaml +36 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +5 -0
- package/src/index.js.map +1 -0
- package/src/lib/rules-package.d.ts +3 -0
- package/src/lib/rules-package.js +16 -0
- package/src/lib/rules-package.js.map +1 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.import-using-user-input
|
|
5
|
+
title: Constrain module-loading trust boundaries
|
|
6
|
+
summary: "`require()` and dynamic `import()` should not resolve modules from untrusted input."
|
|
7
|
+
rationale: Untrusted module paths let attackers steer module-loading boundaries toward unintended files, packages, or plugins.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- execution
|
|
11
|
+
- module-loading
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.import-using-user-input
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.execution
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.92
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- execution
|
|
31
|
+
- module-loading
|
|
32
|
+
message:
|
|
33
|
+
title: Resolve `${captures.issue.text}` from a trusted module map
|
|
34
|
+
summary: "`${captures.issue.text}` crosses a module-loading trust boundary with untrusted input."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Resolve modules from a fixed allowlist or explicit dispatcher instead of untrusted request or event data.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.information-leakage
|
|
5
|
+
title: Avoid leaking sensitive or diagnostic state
|
|
6
|
+
summary: Logs, stdout or stderr, and direct response sinks should not expose sensitive fields or internal diagnostic detail.
|
|
7
|
+
rationale: Stack traces, request metadata, auth or session objects, and environment state are often leaked through "temporary" debugging output that later reaches production paths.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- privacy
|
|
11
|
+
- logging
|
|
12
|
+
- diagnostics
|
|
13
|
+
- rules-catalog
|
|
14
|
+
stability: stable
|
|
15
|
+
appliesTo: block
|
|
16
|
+
scope:
|
|
17
|
+
languages:
|
|
18
|
+
- typescript
|
|
19
|
+
- javascript
|
|
20
|
+
match:
|
|
21
|
+
fact:
|
|
22
|
+
kind: security.information-leakage
|
|
23
|
+
bind: issue
|
|
24
|
+
emit:
|
|
25
|
+
finding:
|
|
26
|
+
category: security.privacy
|
|
27
|
+
severity: high
|
|
28
|
+
confidence: 0.9
|
|
29
|
+
tags:
|
|
30
|
+
- security
|
|
31
|
+
- privacy
|
|
32
|
+
- logging
|
|
33
|
+
- diagnostics
|
|
34
|
+
message:
|
|
35
|
+
title: Remove sensitive or diagnostic data from `${captures.issue.text}`
|
|
36
|
+
summary: "`${captures.issue.text}` exposes sensitive fields or internal diagnostic detail through a direct sink."
|
|
37
|
+
remediation:
|
|
38
|
+
summary: Replace the payload with a fixed summary, redact sensitive fields, and strip stack, env, request, or cookie data from production output.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.insecure-allow-origin
|
|
5
|
+
title: Do not reflect request origin into CORS policy
|
|
6
|
+
summary: "`Access-Control-Allow-Origin` should not be set from request-controlled input."
|
|
7
|
+
rationale: Reflecting the request origin into a CORS allowlist turns origin validation into a no-op.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- cors
|
|
11
|
+
- misconfiguration
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.insecure-allow-origin
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.misconfiguration
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.92
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- cors
|
|
31
|
+
- misconfiguration
|
|
32
|
+
message:
|
|
33
|
+
title: Validate the origin before setting `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` reflects request input into `Access-Control-Allow-Origin`."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Set CORS origins from a fixed allowlist or explicit trusted origin check.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.insecure-auth-cookie-flags
|
|
5
|
+
title: Harden auth-bearing cookies
|
|
6
|
+
summary: Auth and session cookies should set HttpOnly, Secure, and SameSite.
|
|
7
|
+
rationale: Cookie flags prevent browser scripts, mixed transport, and cross-site requests from exposing session-bearing values.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- authentication
|
|
11
|
+
- cookies
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: ts.security.insecure-auth-cookie-flags
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.authentication
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- authentication
|
|
31
|
+
- cookies
|
|
32
|
+
message:
|
|
33
|
+
title: Harden `${captures.issue.text}` for auth cookies
|
|
34
|
+
summary: "`${captures.issue.text}` sets an auth-bearing cookie without the expected protections."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Add `HttpOnly`, `Secure`, and an explicit `SameSite` policy before the cookie is used for session or auth state.
|
|
37
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.insecure-password-hash-configuration
|
|
5
|
+
title: Avoid legacy Argon2 password hash modes
|
|
6
|
+
summary: Password hashing should not use `argon2i` or `argon2d` when safer modern modes are available.
|
|
7
|
+
rationale: Older Argon2 modes are weaker choices for password storage than the modern hybrid mode.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- cryptography
|
|
11
|
+
- password-storage
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.insecure-password-hash-configuration
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.cryptography
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- cryptography
|
|
31
|
+
- password-storage
|
|
32
|
+
message:
|
|
33
|
+
title: Upgrade the hash mode used by `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` uses an older Argon2 mode for password hashing."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Prefer `argon2id` and keep the password hash configuration aligned with current password-storage guidance.
|
|
37
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.insecure-websocket-transport
|
|
5
|
+
title: Use secure WebSocket transport
|
|
6
|
+
summary: WebSocket clients should not connect over cleartext `ws://` when sensitive application data is involved.
|
|
7
|
+
rationale: Cleartext WebSocket transport exposes application traffic to interception and manipulation.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- transport
|
|
11
|
+
- websocket
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.insecure-websocket-transport
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.transport
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.95
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- transport
|
|
31
|
+
- websocket
|
|
32
|
+
message:
|
|
33
|
+
title: Replace `${captures.issue.text}` with a secure WebSocket URL
|
|
34
|
+
summary: "`${captures.issue.text}` uses cleartext WebSocket transport."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Switch the endpoint to `wss://` and keep certificate validation enabled.
|
|
37
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.insufficiently-random-values
|
|
5
|
+
title: Use enough entropy for secrets and tokens
|
|
6
|
+
summary: Secret-bearing tokens and secrets should use at least 16 bytes of cryptographic entropy.
|
|
7
|
+
rationale: Short random values are harder to brute-force than predictable values, but they can still be guessed faster than modern secret-bearing flows should allow.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- cryptography
|
|
11
|
+
- randomness
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.insufficiently-random-values
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.cryptography
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- cryptography
|
|
31
|
+
- randomness
|
|
32
|
+
message:
|
|
33
|
+
title: Increase the entropy used by `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` uses a cryptographically random source, but not enough entropy for a secret-bearing value."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Generate at least 16 bytes of entropy for reset tokens, invitation codes, session secrets, and similar secret-bearing values.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.jwt-not-revoked
|
|
5
|
+
title: Add a JWT revocation hook
|
|
6
|
+
summary: Express JWT middleware should check revocation state when bearer tokens can be invalidated early.
|
|
7
|
+
rationale: Signature validation alone does not handle logout, compromise, or forced token invalidation.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- authentication
|
|
11
|
+
- jwt
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.jwt-not-revoked
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.authentication
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- authentication
|
|
31
|
+
- jwt
|
|
32
|
+
message:
|
|
33
|
+
title: Add revocation handling to `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` configures Express JWT validation without an `isRevoked` check."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Add an `isRevoked` callback or equivalent revocation check for tokens that can be invalidated before expiry.
|
|
37
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.jwt-sensitive-claims
|
|
5
|
+
title: Remove sensitive claims from JWT payloads
|
|
6
|
+
summary: JWT payloads should avoid embedding PII or secrets unless absolutely required.
|
|
7
|
+
rationale: Client-visible tokens often outlive a single request and can leak more data than intended.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- privacy
|
|
11
|
+
- jwt
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: ts.security.jwt-sensitive-claims
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.privacy
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- privacy
|
|
31
|
+
- jwt
|
|
32
|
+
message:
|
|
33
|
+
title: Remove sensitive claims from `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` includes claims that expose personal or secret data in a token payload."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Keep JWT claims minimal. Prefer stable identifiers, not direct PII or secret-bearing fields.
|
|
37
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.manual-html-sanitization
|
|
5
|
+
title: Avoid ad hoc HTML sanitization
|
|
6
|
+
summary: Hand-rolled HTML escaping and sanitization should be replaced with vetted sanitizers or safe rendering paths.
|
|
7
|
+
rationale: String replacement chains miss edge cases and are easy to bypass as rendering behavior evolves.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- xss
|
|
11
|
+
- sanitization
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.manual-html-sanitization
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.output-encoding
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.88
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- xss
|
|
31
|
+
- sanitization
|
|
32
|
+
message:
|
|
33
|
+
title: Replace `${captures.issue.text}` with a vetted sanitizer
|
|
34
|
+
summary: "`${captures.issue.text}` performs manual HTML escaping instead of using a trusted sanitization or safe rendering path."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Use a vetted sanitizer or framework-native escaping model instead of string replacement chains.
|
|
37
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.missing-authorization-before-sensitive-action
|
|
5
|
+
title: Missing authorization before sensitive action
|
|
6
|
+
summary: Sensitive backend actions should be guarded by an authorization or permission check.
|
|
7
|
+
rationale: Calling destructive or privileged actions without an authorization guard increases the risk of broken access control.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- authorization
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-sec-021
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: function
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.missing-authorization-before-sensitive-action
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.authorization
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.75
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- authorization
|
|
31
|
+
message:
|
|
32
|
+
title: Add authorization before sensitive backend actions
|
|
33
|
+
summary: "`${captures.issue.text}` performs a sensitive action without a matching authorization guard."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Add an explicit authorization or permission check before the sensitive action executes.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.missing-integrity-check
|
|
5
|
+
title: Use authenticated encryption for secrets and tokens
|
|
6
|
+
summary: Session, cookie, and token encryption should provide integrity protection in the same helper.
|
|
7
|
+
rationale: Confidentiality-only encryption leaves secret-bearing values vulnerable to tampering unless the code also applies an integrity check or uses an authenticated mode.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- cryptography
|
|
11
|
+
- integrity
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.missing-integrity-check
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.cryptography
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- cryptography
|
|
31
|
+
- integrity
|
|
32
|
+
message:
|
|
33
|
+
title: Add integrity protection to `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` encrypts a secret-bearing value without authenticated encryption or a same-helper integrity check."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Prefer authenticated encryption such as AES-GCM, or pair non-AEAD encryption with an explicit integrity check in the same helper.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.missing-message-origin-check
|
|
5
|
+
title: Verify `message` event origins
|
|
6
|
+
summary: "`message` handlers should validate `event.origin` before trusting cross-window data."
|
|
7
|
+
rationale: Without an origin check, hostile pages can post crafted messages into the handler.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- browser
|
|
11
|
+
- messaging
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.missing-message-origin-check
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.browser
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.92
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- browser
|
|
31
|
+
- messaging
|
|
32
|
+
message:
|
|
33
|
+
title: Check `event.origin` before processing `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` handles cross-window messages without validating the sender origin."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Gate the handler on a strict allowlist of expected origins before reading `event.data`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.missing-ownership-validation
|
|
5
|
+
title: Missing ownership validation
|
|
6
|
+
summary: Resource identifiers from request input should be checked against the caller before sensitive actions run.
|
|
7
|
+
rationale: Authorization alone is not enough when handlers act on caller-provided resource ids that may belong to someone else.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- authorization
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-sec-022
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: function
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.missing-ownership-validation
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.authorization
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.75
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- authorization
|
|
31
|
+
message:
|
|
32
|
+
title: Validate ownership before acting on caller-supplied resource ids
|
|
33
|
+
summary: "`${captures.issue.text}` is used in a sensitive path without a matching ownership check."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Compare the request-derived resource id to the authenticated caller or load the resource through an ownership-enforcing query.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.missing-request-timeout-or-retry
|
|
5
|
+
title: Missing request timeout or retry protection
|
|
6
|
+
summary: External calls should define timeout, cancellation, or retry behavior before they enter security-sensitive flows.
|
|
7
|
+
rationale: Authentication and dependency calls that have neither timeout nor retry protection fail unpredictably under network stress.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- resilience
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-sec-030
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.missing-request-timeout-or-retry
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.resilience
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.8
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- resilience
|
|
31
|
+
message:
|
|
32
|
+
title: Add timeout or retry protection to external calls
|
|
33
|
+
summary: "`${captures.issue.text}` performs an external call without timeout, cancellation, or retry handling."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Add explicit timeout or cancellation support, wrap the call in retry handling, or do both when the dependency is critical.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.no-dynamic-execution
|
|
5
|
+
title: Eval or dynamic code execution
|
|
6
|
+
summary: Eval-like helpers, `vm` execution APIs, and string-evaluated timers should not execute dynamic code.
|
|
7
|
+
rationale: Dynamic execution turns data into code, widens the attack surface, and bypasses normal control flow.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- execution
|
|
11
|
+
- rules-catalog
|
|
12
|
+
stability: stable
|
|
13
|
+
appliesTo: block
|
|
14
|
+
scope:
|
|
15
|
+
languages:
|
|
16
|
+
- typescript
|
|
17
|
+
- javascript
|
|
18
|
+
match:
|
|
19
|
+
fact:
|
|
20
|
+
kind: security.dynamic-execution
|
|
21
|
+
bind: issue
|
|
22
|
+
emit:
|
|
23
|
+
finding:
|
|
24
|
+
category: security.execution
|
|
25
|
+
severity: high
|
|
26
|
+
confidence: 0.95
|
|
27
|
+
tags:
|
|
28
|
+
- security
|
|
29
|
+
- execution
|
|
30
|
+
message:
|
|
31
|
+
title: Avoid `${captures.issue.text}`
|
|
32
|
+
summary: "`${captures.issue.text}` executes dynamic code and should be replaced with a safer alternative."
|
|
33
|
+
remediation:
|
|
34
|
+
summary: Replace dynamic execution with explicit parsing, fixed dispatch tables, or normal function callbacks.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.no-innerhtml-assignment
|
|
5
|
+
title: Avoid unsafe `innerHTML` assignment
|
|
6
|
+
summary: "`innerHTML` assignments should only use fixed or explicitly sanitized HTML."
|
|
7
|
+
rationale: Direct HTML injection can allow untrusted or weakly reviewed content to execute in the browser.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- output-encoding
|
|
11
|
+
- xss
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.no-innerhtml-assignment
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.output-encoding
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.92
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- xss
|
|
31
|
+
- output-encoding
|
|
32
|
+
message:
|
|
33
|
+
title: Avoid unsafe `innerHTML` assignment in `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` inserts non-literal, non-sanitized HTML into `innerHTML`."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Prefer text-only rendering APIs or assign only fixed or explicitly sanitized HTML.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.security.non-literal-fs-filename
|
|
5
|
+
title: Avoid attacker-controlled filesystem read paths
|
|
6
|
+
summary: Direct filesystem read APIs should not consume request- or upload-controlled filenames.
|
|
7
|
+
rationale: Dynamic read paths can expose unintended local files or bypass expected file-selection constraints.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- filesystem
|
|
11
|
+
- path-traversal
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: security.non-literal-fs-filename
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: security.filesystem
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- security
|
|
30
|
+
- filesystem
|
|
31
|
+
- path-traversal
|
|
32
|
+
message:
|
|
33
|
+
title: Constrain the filename used by `${captures.issue.text}`
|
|
34
|
+
summary: "`${captures.issue.text}` reads from a filename derived from external input."
|
|
35
|
+
remediation:
|
|
36
|
+
summary: Resolve reads from a trusted allowlist or a validated server-controlled mapping instead of external filenames.
|