@appland/scanner 1.40.3 → 1.44.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 (151) hide show
  1. package/README.md +63 -39
  2. package/built/appMapIndex.js +40 -0
  3. package/built/appMapIndex.js.map +1 -0
  4. package/built/check.js +3 -3
  5. package/built/check.js.map +1 -1
  6. package/built/checkInstance.js +4 -4
  7. package/built/checkInstance.js.map +1 -1
  8. package/built/cli/ci/command.js +21 -26
  9. package/built/cli/ci/command.js.map +1 -1
  10. package/built/cli/fail.js +13 -0
  11. package/built/cli/fail.js.map +1 -0
  12. package/built/cli/merge/command.js +101 -0
  13. package/built/cli/merge/command.js.map +1 -0
  14. package/built/cli/merge/options.js +3 -0
  15. package/built/cli/merge/options.js.map +1 -0
  16. package/built/cli/reportUploadURL.js +11 -0
  17. package/built/cli/reportUploadURL.js.map +1 -0
  18. package/built/cli/scan/command.js +5 -1
  19. package/built/cli/scan/command.js.map +1 -1
  20. package/built/cli/scan/scanner.js +2 -2
  21. package/built/cli/scan/scanner.js.map +1 -1
  22. package/built/cli/scan.js +4 -2
  23. package/built/cli/scan.js.map +1 -1
  24. package/built/cli/updateCommitStatus.js +65 -0
  25. package/built/cli/updateCommitStatus.js.map +1 -0
  26. package/built/cli/upload/command.js +10 -5
  27. package/built/cli/upload/command.js.map +1 -1
  28. package/built/cli.js +2 -0
  29. package/built/cli.js.map +1 -1
  30. package/built/database/index.js +136 -161
  31. package/built/database/index.js.map +1 -1
  32. package/built/integration/appland/{fetchStatus.js → app/listFindingStatus.js} +1 -1
  33. package/built/integration/appland/app/listFindingStatus.js.map +1 -0
  34. package/built/integration/appland/{appMap.js → appMap/create.js} +43 -48
  35. package/built/integration/appland/appMap/create.js.map +1 -0
  36. package/built/integration/appland/location.js +3 -0
  37. package/built/integration/appland/location.js.map +1 -0
  38. package/built/integration/appland/{mapset.js → mapset/create.js} +41 -46
  39. package/built/integration/appland/mapset/create.js.map +1 -0
  40. package/built/integration/appland/{upload.js → scannerJob/create.js} +27 -19
  41. package/built/integration/appland/scannerJob/create.js.map +1 -0
  42. package/built/integration/appland/scannerJob/merge.js +92 -0
  43. package/built/integration/appland/scannerJob/merge.js.map +1 -0
  44. package/built/integration/appland/scannerJob.js +3 -0
  45. package/built/integration/appland/scannerJob.js.map +1 -0
  46. package/built/report/summaryReport.js +1 -1
  47. package/built/report/summaryReport.js.map +1 -1
  48. package/built/ruleChecker.js +12 -11
  49. package/built/ruleChecker.js.map +1 -1
  50. package/built/rules/authzBeforeAuthn.js +6 -0
  51. package/built/rules/authzBeforeAuthn.js.map +1 -1
  52. package/built/rules/circularDependency.js +4 -0
  53. package/built/rules/circularDependency.js.map +1 -1
  54. package/built/rules/deserializationOfUntrustedData.js +8 -0
  55. package/built/rules/deserializationOfUntrustedData.js.map +1 -1
  56. package/built/rules/http500.js +7 -0
  57. package/built/rules/http500.js.map +1 -1
  58. package/built/rules/illegalPackageDependency.js +7 -0
  59. package/built/rules/illegalPackageDependency.js.map +1 -1
  60. package/built/rules/incompatibleHttpClientRequest.js +7 -0
  61. package/built/rules/incompatibleHttpClientRequest.js.map +1 -1
  62. package/built/rules/insecureCompare.js +4 -0
  63. package/built/rules/insecureCompare.js.map +1 -1
  64. package/built/rules/jobNotCancelled.js +3 -0
  65. package/built/rules/jobNotCancelled.js.map +1 -1
  66. package/built/rules/lib/matchEvent.js +3 -4
  67. package/built/rules/lib/matchEvent.js.map +1 -1
  68. package/built/rules/lib/parseRuleDescription.js +18 -0
  69. package/built/rules/lib/parseRuleDescription.js.map +1 -0
  70. package/built/rules/logoutWithoutSessionReset.js +8 -0
  71. package/built/rules/logoutWithoutSessionReset.js.map +1 -1
  72. package/built/rules/missingAuthentication.js +6 -0
  73. package/built/rules/missingAuthentication.js.map +1 -1
  74. package/built/rules/missingContentType.js +6 -0
  75. package/built/rules/missingContentType.js.map +1 -1
  76. package/built/rules/nPlusOneQuery.js +8 -2
  77. package/built/rules/nPlusOneQuery.js.map +1 -1
  78. package/built/rules/queryFromInvalidPackage.js +6 -0
  79. package/built/rules/queryFromInvalidPackage.js.map +1 -1
  80. package/built/rules/queryFromView.js +6 -0
  81. package/built/rules/queryFromView.js.map +1 -1
  82. package/built/rules/rpcWithoutCircuitBreaker.js +6 -0
  83. package/built/rules/rpcWithoutCircuitBreaker.js.map +1 -1
  84. package/built/rules/saveWithoutValidation.js +6 -0
  85. package/built/rules/saveWithoutValidation.js.map +1 -1
  86. package/built/rules/secretInLog.js +3 -0
  87. package/built/rules/secretInLog.js.map +1 -1
  88. package/built/rules/slowFunctionCall.js +6 -0
  89. package/built/rules/slowFunctionCall.js.map +1 -1
  90. package/built/rules/slowHttpServerRequest.js +6 -0
  91. package/built/rules/slowHttpServerRequest.js.map +1 -1
  92. package/built/rules/slowQuery.js +6 -0
  93. package/built/rules/slowQuery.js.map +1 -1
  94. package/built/rules/tooManyJoins.js +9 -3
  95. package/built/rules/tooManyJoins.js.map +1 -1
  96. package/built/rules/tooManyUpdates.js +6 -0
  97. package/built/rules/tooManyUpdates.js.map +1 -1
  98. package/built/rules/unbatchedMaterializedQuery.js +9 -4
  99. package/built/rules/unbatchedMaterializedQuery.js.map +1 -1
  100. package/built/rules/updateInGetRequest.js +6 -0
  101. package/built/rules/updateInGetRequest.js.map +1 -1
  102. package/built/scope/sqlTransactionScope.js +3 -2
  103. package/built/scope/sqlTransactionScope.js.map +1 -1
  104. package/built/sqlWarning.js +56 -0
  105. package/built/sqlWarning.js.map +1 -0
  106. package/doc/architecture.md +48 -0
  107. package/doc/labels/audit.md +7 -0
  108. package/doc/labels/dao.materialize.md +12 -0
  109. package/doc/labels/deserialize.safe.md +9 -0
  110. package/doc/labels/deserialize.unsafe.md +12 -0
  111. package/doc/labels/http.session.clear.md +7 -0
  112. package/doc/labels/job.cancel.md +11 -0
  113. package/doc/labels/job.create.md +13 -0
  114. package/doc/labels/log.md +12 -0
  115. package/doc/labels/public.md +8 -0
  116. package/doc/labels/rpc.circuit_breaker.md +16 -0
  117. package/doc/labels/sanitize.md +29 -0
  118. package/doc/labels/secret.md +11 -0
  119. package/doc/labels/security.authentication.md +10 -0
  120. package/doc/labels/security.authorization.md +9 -0
  121. package/doc/labels/security.logout.md +9 -0
  122. package/doc/labels/string.equals.md +18 -0
  123. package/doc/rules/authzBeforeAuthn.md +47 -0
  124. package/doc/rules/circularDependency.md +57 -0
  125. package/doc/rules/deserializationOfUntrustedData.md +55 -0
  126. package/doc/rules/http500.md +36 -0
  127. package/doc/rules/illegalPackageDependency.md +50 -0
  128. package/doc/rules/incompatibleHttpClientRequest.md +35 -0
  129. package/doc/rules/insecureCompare.md +59 -0
  130. package/doc/rules/jobNotCancelled.md +49 -0
  131. package/doc/rules/logoutWithoutSessionReset.md +40 -0
  132. package/doc/rules/missingAuthentication.md +59 -0
  133. package/doc/rules/missingContentType.md +33 -0
  134. package/doc/rules/nPlusOneQuery.md +52 -0
  135. package/doc/rules/queryFromInvalidPackage.md +45 -0
  136. package/doc/rules/queryFromView.md +42 -0
  137. package/doc/rules/rpcWithoutCircuitBreaker.md +44 -0
  138. package/doc/rules/saveWithoutValidation.md +33 -0
  139. package/doc/rules/secretInLog.md +49 -0
  140. package/doc/rules/slowFunctionCall.md +39 -0
  141. package/doc/rules/slowHttpServerRequest.md +34 -0
  142. package/doc/rules/slowQuery.md +33 -0
  143. package/doc/rules/tooManyJoins.md +40 -0
  144. package/doc/rules/tooManyUpdates.md +46 -0
  145. package/doc/rules/unbatchedMaterializedQuery.md +54 -0
  146. package/doc/rules/updateInGetRequest.md +44 -0
  147. package/package.json +10 -6
  148. package/built/integration/appland/appMap.js.map +0 -1
  149. package/built/integration/appland/fetchStatus.js.map +0 -1
  150. package/built/integration/appland/mapset.js.map +0 -1
  151. package/built/integration/appland/upload.js.map +0 -1
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: security.authorization
3
+ rules:
4
+ - authz-before-authn
5
+ ---
6
+
7
+ Test whether the current authenticated user has permission to make a web request.
8
+
9
+ Returns `truthy` if the request is allowed; otherwise `falsey`.
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: security.logout
3
+ rules:
4
+ - logout-without-session-reset
5
+ ---
6
+
7
+ Logs out an application user.
8
+
9
+ The function is assumed to be successful regardless of the return value.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: string.equals
3
+ rules:
4
+ - insecure-compare
5
+ ---
6
+
7
+ Compares two strings for equality.
8
+
9
+ The function receiver should be a string, and the function should take one argument that is the
10
+ other string.
11
+
12
+ Returns `truthy` if the strings are equal; otherwise `falsey`.
13
+
14
+ ## Examples
15
+
16
+ - Ruby [String#==](https://ruby-doc.org/core-3.1.0/String.html#method-i-3D-3D)
17
+ - Java
18
+ [String#equals](<https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/String.html#equals(java.lang.Object)>)
@@ -0,0 +1,47 @@
1
+ ---
2
+ rule: authz-before-authn
3
+ name: Authz before authn
4
+ title: Authorization performed before authentication
5
+ references:
6
+ CWE-863: https://cwe.mitre.org/data/definitions/863.html
7
+ impactDomain: Security
8
+ labels:
9
+ - security.authorization
10
+ - security.authentication
11
+ scope: http_server_request
12
+ ---
13
+
14
+ Determines when authorization logic is applied to a user identity that has not been properly
15
+ verified. Because the the user's identity has not been verified yet, the outcome of the
16
+ authorization check cannot be trusted. A malicious user might be able to get themselves authorized
17
+ as a different user than they really are - or they may not be logged in at all.
18
+
19
+ ### Rule logic
20
+
21
+ Iterates over all descendants of the HTTP server request. If an event labeled
22
+ `security.authentication` is encountered, the rule is satisfied. If an event labeled
23
+ `security.authorization` is encountered, and the event returns a truthy value, the descendants of
24
+ the authentication event are searched for an event labeled `security.authentication`. If such an
25
+ event is found, the rule is satisfied. Otherwise a finding is emitted.
26
+
27
+ ### Notes
28
+
29
+ A `security.authorization` event which returns a falsey value (`false`, `null`, etc) will not
30
+ trigger a finding.
31
+
32
+ The `security.authentication` event must return a truthy value (`true`, any object) in order to
33
+ satisfy the rule.
34
+
35
+ ### Resolution
36
+
37
+ Ensure that the user's identity is established before performing authorization.
38
+
39
+ ### Options
40
+
41
+ None
42
+
43
+ ### Examples
44
+
45
+ ```yaml
46
+ - rule: authzBeforeAuthn
47
+ ```
@@ -0,0 +1,57 @@
1
+ ---
2
+ rule: circular-dependency
3
+ name: Circular dependency
4
+ title: Circular package dependency
5
+ references:
6
+ CWE-1047: https://cwe.mitre.org/data/definitions/1047.html
7
+ impactDomain: Maintainability
8
+ scope: command
9
+ ---
10
+
11
+ Finds cycles in the package dependency graph. Cyclic dependencies make code hard to maintain,
12
+ because all the code in the cycle is inter-dependent. While it might look like the code in the
13
+ different packages has separate functions, in essence all the code in the cycle acts like one big
14
+ package.
15
+
16
+ ### Rule logic
17
+
18
+ Builds the package dependency graph, in which each package is a graph node, and each function call
19
+ from one package to another is an edge. The edges are directional, pointing from the caller package
20
+ to the callee package.
21
+
22
+ A graph traversal finds cycles - a cycle being a path which starts with a package (a node),
23
+ traverses through other packages (via edges), and returns to the original package.
24
+
25
+ For each package cycle that's detected in the call graph, the rule then searches for a sequence of
26
+ function calls that matches the cycle. This sequence of events is returned in the finding.
27
+
28
+ ### Notes
29
+
30
+ There may be multiple paths through the event trace that produce a given package cycle. Only one of
31
+ these paths is reported in the finding.
32
+
33
+ ### Resolution
34
+
35
+ If a package in the circular dependency is designed to call back into the code that call it, it can
36
+ be added to the `ignoredPackages` list. This is common with helper and middleware code.
37
+
38
+ Otherwise, you can fix the cyclic dependency by refactoring the code. One way to do this is to
39
+ refactor some of the code into a new package, class, or library.
40
+
41
+ ### Options
42
+
43
+ - `depth`. Minimum number of packages in a path that will be reported. Default: 4.
44
+ - `ignoredPackages: ` [MatchPatternConfig](/docs/analysis/match-pattern-config.html)`[]`. Packages
45
+ which match this pattern are not included in the dependency graph. Default: empty - including all
46
+ packages.
47
+
48
+ ### Examples
49
+
50
+ ```yaml
51
+ - rule: circularDependency
52
+ properties:
53
+ depth: 4 # default
54
+ ignoredPackages:
55
+ - equal: activesupport
56
+ - equal: app/helpers
57
+ ```
@@ -0,0 +1,55 @@
1
+ ---
2
+ rule: deserialization-of-untrusted-data
3
+ name: Deserialization of untrusted data
4
+ title: Deserialization of untrusted data
5
+ references:
6
+ CWE-502: https://cwe.mitre.org/data/definitions/502.html
7
+ Ruby Security: https://docs.ruby-lang.org/en/3.0/doc/security_rdoc.html
8
+ impactDomain: Security
9
+ labels:
10
+ - deserialize.unsafe
11
+ - deserialize.safe
12
+ - sanitize
13
+ ---
14
+
15
+ Finds occurrances of deserialization in which the mechanism employed is known to be unsafe, and the
16
+ data is not known to be trusted.
17
+
18
+ ### Rule logic
19
+
20
+ Finds all events labeled `deserialize.unsafe`, that are not a descendant of an event labeled
21
+ `deserialize.safe`. For each of these events, all event parameters are checked.
22
+
23
+ Each parameter whose type is `string` or `object` is verified to ensure that it's trusted. For data
24
+ to be trusted, it must be the return value of a function labeled `sanitize`.
25
+
26
+ ### Notes
27
+
28
+ With insecure deserialization, it is usually possible for an attacker to craft a malicious payload
29
+ that executes code shortly after deserialization.
30
+
31
+ ### Resolution
32
+
33
+ If you can guarantee that you are using unsafe deserialization in a safe way, but it's not possible
34
+ to obtain the raw data from a function labeled `sanitize`, you can wrap the deserialization in a
35
+ function labeled `deserialize.safe`.
36
+
37
+ If you need to deserialize untrusted data, JSON is often a good choice as it is only capable of
38
+ returning ‘primitive’ types such as strings, arrays, hashes, numbers and nil. If you need to
39
+ deserialize other classes, you should handle this manually. Never deserialize to a user specified
40
+ class¹.
41
+
42
+ Ensure that the JSON library provided by your language and framework does not perform unsafe
43
+ deserialization.
44
+
45
+ 1. https://docs.ruby-lang.org/en/3.0/doc/security_rdoc.html
46
+
47
+ ### Options
48
+
49
+ None
50
+
51
+ ### Examples
52
+
53
+ ```yaml
54
+ - rule: deserializationOfUntrustedData
55
+ ```
@@ -0,0 +1,36 @@
1
+ ---
2
+ rule: http-500
3
+ name: HTTP 500
4
+ title: HTTP 500 status code
5
+ references:
6
+ CWE-392: https://cwe.mitre.org/data/definitions/392.html
7
+ impactDomain: Stability
8
+ scope: http_server_request
9
+ ---
10
+
11
+ Identifies when an HTTP server requset has returned a 500 status code. HTTP 500 status code
12
+ generally indicate an unanticipated problem in the backend that is not handled in a predictable way.
13
+ 500 status codes are also hard for client code to handle, because they don't indicate any particular
14
+ problem or suggest a solution.
15
+
16
+ ### Rule logic
17
+
18
+ An HTTP 500 status code that's returned by an HTTP server request will be emitted as a finding by
19
+ this rule.
20
+
21
+ ### Resolution
22
+
23
+ The execution trace of request may show an unhandled exception. Or it may show exception or error
24
+ handling that failed in some way, and was caught and handled generically by the framework. Use the
25
+ trace to figure out the root cause of the problem, and update the code to report the problem using a
26
+ more informative HTTP status code.
27
+
28
+ ### Options
29
+
30
+ None
31
+
32
+ ### Examples
33
+
34
+ ```yaml
35
+ - rule: http500
36
+ ```
@@ -0,0 +1,50 @@
1
+ ---
2
+ rule: illegal-package-dependency
3
+ name: Illegal package dependency
4
+ title: Illegal use of code by a non-whitelisted package
5
+ references:
6
+ CWE-1120: https://cwe.mitre.org/data/definitions/1120.html
7
+ CWE-1154: https://cwe.mitre.org/data/definitions/1154.html
8
+ impactDomain: Maintainability
9
+ scope: command
10
+ ---
11
+
12
+ Ensures that all calls to a specified `callee` package come from an approved `caller` package. This
13
+ is a way of defining and enforcing an architectural constraint that may not be provided by the
14
+ programming language itself.
15
+
16
+ ### Rule logic
17
+
18
+ All packages which call the `calleePackage` are inspected. Each one must match one of the
19
+ `callerPackage` options.
20
+
21
+ ### Notes
22
+
23
+ Many programming languages do not provide a way to make a package "private" or "protected" in the
24
+ same way as a class or function. Yet, it's often desirable to limit the places from which code in a
25
+ certain package can be called. This rule provides a way to define and enforce this type of
26
+ architectural constraint.
27
+
28
+ ### Resolution
29
+
30
+ The code which is illegally calling into the `calleePackage` should be refactored to call one of the
31
+ allowed `callerPackages` instead. If the needed functionality is not available on a `callerPackage`,
32
+ then one of the `callerPackages` should be modified to provide it.
33
+
34
+ ### Options
35
+
36
+ - `callerPackages: ` [MatchPatternConfig](/docs/analysis/match-pattern-config.html)`[]`. Packages
37
+ which are allowed to call the `calleePackage`. Required.
38
+ - `calleePackage: `[MatchPatternConfig](/docs/analysis/match-pattern-config.html). Package whose
39
+ callers should be checked. Required.
40
+
41
+ ### Examples
42
+
43
+ ```yaml
44
+ - rule: illegalPackageDependency
45
+ properties:
46
+ callerPackages:
47
+ - equal: actionpack
48
+ calleePackage:
49
+ equal: app/controllers
50
+ ```
@@ -0,0 +1,35 @@
1
+ ---
2
+ rule: incompatible-http-client-request
3
+ name: Incompatible HTTP client request
4
+ title: Incompatible HTTP client request
5
+ impactDomain: Stability
6
+ scope: http_client_request
7
+ ---
8
+
9
+ Detects HTTP client requests which are incompatible with a published OpenAPI schema.
10
+
11
+ ### Rule logic
12
+
13
+ Each HTTP client request is converted to an OpenAPI schema document. This is done by examining the
14
+ request method, request URI, parameters, body, headers, etc. and representing them as OpenAPI. Then,
15
+ the client OpenAPI schema is compared to the published server OpenAPI schema. If any breaking
16
+ changes are detected between the client request and the published server schema, these are reported
17
+ as findings.
18
+
19
+ ### Resolution
20
+
21
+ Modify the HTTP client request to conform to the published schema.
22
+
23
+ ### Options
24
+
25
+ - `schemata: Record<string, string>` A map from server hostnames to schema URLs. A schema must be
26
+ provided for each server hostname that's invoked in the AppMap.
27
+
28
+ ### Examples
29
+
30
+ ```yaml
31
+ - rule: incompatibleHttpClientRequest
32
+ parameters:
33
+ schemata:
34
+ 'myserver:8080': https://github.com/mycorp/myserver/tree/main/openapi.yaml
35
+ ```
@@ -0,0 +1,59 @@
1
+ ---
2
+ rule: insecure-compare
3
+ name: Insecure compare
4
+ title: Insecure comparison of secrets
5
+ references:
6
+ CWE-208: https://cwe.mitre.org/data/definitions/208.html
7
+ impactDomain: Security
8
+ labels:
9
+ - secret
10
+ - string.equals
11
+ ---
12
+
13
+ Identifies cases in which secrets are being compared directly using `string.equals`.
14
+
15
+ Ordinary string comparison of user-provided data with a piece of secret data can leak information
16
+ about the secret through [timing attacks](https://en.wikipedia.org/wiki/Timing_attack), because of
17
+ short-circuting (returning false on first mismatch). This can allow the attacker to significantly
18
+ speed up brute forcing, turning an intractable exponential problem into a linear one.
19
+
20
+ ### Rule logic
21
+
22
+ The rule looks for events labeled `secret` and `string.equals`.
23
+
24
+ On encountering an event labeled `secret` it remembers the return value.
25
+
26
+ On encountering `string.equals` it looks at the arguments and the receiver. If any of the arguments
27
+ is a previously seen secret, or matches a list of known secret-like regular expressions, the
28
+ comparison is flagged as insecure, unless any of the arguments is a BCrypt digest.
29
+
30
+ ### Notes
31
+
32
+ When generating appmaps, ensure that string comparison functions (such as `String#==` in Ruby and
33
+ `String.equals` in Java) are traced and correctly labeled with `string.equals`. Any functions you
34
+ know to return a secret (eg. a model accessor for an API key) should be labeled `secret`.
35
+
36
+ Since using this rule generally requires labeling all string comparisons its use is currently
37
+ limited due to performance and space overhead of tracing them: string comparisons are commonly used
38
+ throughout the code base and libraries.
39
+
40
+ It's advisable to only trace string equality on a limited subset of tests (perhaps the ones known to
41
+ touch secret related functionality); alas, this is not something easily attainable with current
42
+ AppMap recorders and requires swapping or modifying configuration files.
43
+
44
+ ### Resolution
45
+
46
+ To fix this issue, either hash values before comparing or use a constant-time comparison in such
47
+ operations. Constant-time comparison functions always compare every character of the string,
48
+ removing the timing side channel. You can usually find functions like this in cryptographic and
49
+ utility libraries, eg. `ActiveSupport::SecurityUtils.secure_compare`.
50
+
51
+ ### Options
52
+
53
+ None
54
+
55
+ ### Examples
56
+
57
+ ```yaml
58
+ - rule: insecureCompare
59
+ ```
@@ -0,0 +1,49 @@
1
+ ---
2
+ rule: job-not-cancelled
3
+ name: Job not cancelled
4
+ title: Job created in a rolled back transaction and not cancelled
5
+ references:
6
+ CWE-672: https://cwe.mitre.org/data/definitions/672.html
7
+ impactDomain: Stability
8
+ labels:
9
+ - job.create
10
+ - job.cancel
11
+ scope: transaction
12
+ ---
13
+
14
+ Finds jobs which are created in a transaction, and not cancelled when the transaction is rolled
15
+ back.
16
+
17
+ ### Rule logic
18
+
19
+ THe rule identifies SQL transaction boundaries by examining the SQL queries for `START TRANSACTION`,
20
+ `ROLLBACK`, `COMMIT`, etc.
21
+
22
+ Within each transaction, the rule looks for events labeled `job.create`. If the transaction is
23
+ rolled back, and there is not a corresponding event labeled `job.cancel`, then a finding is
24
+ reported.
25
+
26
+ ### Notes
27
+
28
+ It's recommended to program delayed jobs defensively to check for data and silently do nothing if
29
+ that data is missing (eg. due to a rollback or a duplicate job); job details in this design are
30
+ stored in the database and the queue entries only reference them.
31
+
32
+ This rule is designed for use when this practice is impossible or not followed, and with external
33
+ job queues that do not automatically roll back with the transaction. If the job queue is the
34
+ database and the same connection is used for the job queue and for the request, then this check is
35
+ not needed.
36
+
37
+ ### Resolution
38
+
39
+ Cancel any queued jobs when the transaction rolls back.
40
+
41
+ ### Options
42
+
43
+ None
44
+
45
+ ### Examples
46
+
47
+ ```yaml
48
+ - rule: jobNotCanceled
49
+ ```
@@ -0,0 +1,40 @@
1
+ ---
2
+ rule: logout-without-session-reset
3
+ name: Logout without session reset
4
+ title: Logout without session reset
5
+ references:
6
+ CWE-488: https://cwe.mitre.org/data/definitions/488.html
7
+ OWASP - Session fixation: https://owasp.org/www-community/attacks/Session_fixation
8
+ Ruby on Rails - Session fixation countermeasures: >-
9
+ https://guides.rubyonrails.org/security.html#session-fixation-countermeasures
10
+ impactDomain: Security
11
+ labels:
12
+ - http.session.clear
13
+ - security.logout
14
+ scope: http_server_request
15
+ ---
16
+
17
+ Determines when a user has been logged out from the application, but the session hasn't been
18
+ cleared. When the session isn't cleared after logout, the session is vulnerable to a
19
+ [session fixation attack](https://owasp.org/www-community/attacks/Session_fixation).
20
+
21
+ ### Rule logic
22
+
23
+ Iterates over all descendants of the HTTP server request. If an event labeled `security.logout` is
24
+ encountered, the event must have a descendant labeled `http.session.clear`, otherwise a finding is
25
+ emitted.
26
+
27
+ ### Notes
28
+
29
+ Return values from `security.logout` and `http.session.clear` are not checked, as these methods are
30
+ assumed to always succeed.
31
+
32
+ ### Options
33
+
34
+ None
35
+
36
+ ### Examples
37
+
38
+ ```yaml
39
+ - rule: logoutWithoutSessionReset
40
+ ```
@@ -0,0 +1,59 @@
1
+ ---
2
+ rule: missing-authentication
3
+ name: Missing authentication
4
+ title: Unauthenticated HTTP server request
5
+ references:
6
+ CWE-306: https://cwe.mitre.org/data/definitions/306.html
7
+ impactDomain: Security
8
+ labels:
9
+ - public
10
+ - security.authentication
11
+ scope: http_server_request
12
+ ---
13
+
14
+ An HTTP server request is missing authentication. In this case, the request may be serving assets
15
+ that should be protected by authentication - but no authentication is actually happening.
16
+
17
+ ### Rule logic
18
+
19
+ This rule checks all HTTP server requests that satisfy the following conditions:
20
+
21
+ - HTTP status code is `< 300`
22
+ - Matches include and exclude lists of content type (by default, these are empty).
23
+
24
+ For each matching request, any event that satisfies either of these conditions will satisfy the rule:
25
+
26
+ 1. Has label `public`.
27
+ 2. Has label `security.authentication`, and returns a truthy value.
28
+
29
+ ### Notes
30
+
31
+ If a request does not require an authenticated user (e.g. because it contains completely public
32
+ information), then this rule can be satisfied by calling any function labeled `public`.
33
+
34
+ If the `security.authentication` event returns a falsey value (`false`, `null`, etc), then
35
+ authentication is assumed to be denied, and the rule is not satisfied.
36
+
37
+ ### Resolution
38
+
39
+ If the request is designed to be public, and the omission of authentication is intentionaly, modify
40
+ the code so that it calls a function labeled `public`.
41
+
42
+ Otherwise, modify the code so that it calls a function labeled `security.authentication` which
43
+ returns a truthy result (for example, a User object).
44
+
45
+ ### Options
46
+
47
+ - `includeContentTypes: ` [MatchPatternConfig](/docs/analysis/match-pattern-config.html)`[]`.
48
+ Default: empty - including all content types.
49
+ - `excludeContentTypes: ` [MatchPatternConfig](/docs/analysis/match-pattern-config.html)`[]`.
50
+ Default: empty - excluding no content types.
51
+
52
+ ### Examples
53
+
54
+ ```yaml
55
+ - rule: missingAuthentication
56
+ properties:
57
+ includeContentTypes:
58
+ - match: ^application/json
59
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ rule: missing-content-type
3
+ name: Missing content type
4
+ title: HTTP server request without a Content-Type header
5
+ impactDomain: Stability
6
+ scope: http_server_request
7
+ ---
8
+
9
+ Finds HTTP server requests that don't provide a `Content-Type` header in the response.
10
+
11
+ ### Rule logic
12
+
13
+ Every HTTP server request is checked. If the status code indicates redirect or "No content", then
14
+ the rule passes. Otherwise, a finding is issued if the response is missing a `Content-Type` header.
15
+
16
+ ### Notes
17
+
18
+ When a response is missing the `Content-Type` header, it's unclear to clients how to handle the
19
+ response data. Bugs are likely to result.
20
+
21
+ ### Resolution
22
+
23
+ Provide a `Content-Type` in the response.
24
+
25
+ ### Options
26
+
27
+ None
28
+
29
+ ### Examples
30
+
31
+ ```yaml
32
+ - rule: missingContentType
33
+ ```
@@ -0,0 +1,52 @@
1
+ ---
2
+ rule: n-plus-one-query
3
+ name: N plus one query
4
+ title: N plus 1 SQL query
5
+ references:
6
+ CWE-1073: https://cwe.mitre.org/data/definitions/1073.html
7
+ impactDomain: Performance
8
+ scope: command
9
+ ---
10
+
11
+
12
+ Finds occurrences of a query being repeated within a loop.
13
+
14
+ ### Rule logic
15
+
16
+ Within each command, SQL queries are normalized, grouped, and counted.
17
+
18
+ If the number of duplicate instances of a normalized query exceeds the threshold, it's reported as a
19
+ finding.
20
+
21
+ ### Notes
22
+
23
+ N plus one queries typically occur when a
24
+ [data access object (DAO)](https://en.wikipedia.org/wiki/Data_access_object) has a one-to-many or
25
+ many-to-many relationship, and the relationship is enumerated within a loop. The DAO will issue a
26
+ separate query to fetch each related record. If the number of related objects is large, or if each
27
+ one is fairly expensive to fetch, application performance suffers.
28
+
29
+ ### Resolution
30
+
31
+ DAO libraries typically offer a feature called "eager loading". For example:
32
+
33
+ - [ActiveRecord](https://news.learnenough.com/eager-loading)
34
+ - [Django ORM](https://docs.djangoproject.com/en/4.0/topics/db/optimization/#retrieve-everything-at-once-if-you-know-you-will-need-it)
35
+ - [Hibernate](https://docs.jboss.org/hibernate/orm/5.3/javadocs/org/hibernate/jpamodelgen/xml/jaxb/FetchType.html)
36
+
37
+ Enable eager loading on the association in question to fetch the data efficiently, without repeated,
38
+ identical queries.
39
+
40
+ ### Options
41
+
42
+ - `warningLimit` Threshold for reporting a warning. Default: 5.
43
+ - `errorLimit` Threshold for reporting an error. Default: 10.
44
+
45
+ ### Examples
46
+
47
+ ```yaml
48
+ - rule: nPlusOneQuery
49
+ parameters:
50
+ warningLimit: 5
51
+ errorLimit: 10
52
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ rule: query-from-invalid-package
3
+ name: Query from invalid package
4
+ title: Queries from invalid packages
5
+ references:
6
+ CWE-1057: https://cwe.mitre.org/data/definitions/1057.html
7
+ impactDomain: Maintainability
8
+ ---
9
+
10
+ Ensures that SQL queries are made only from an approved list of packages. This helps to make the
11
+ code more maintainable by encapsulating access to the database.
12
+
13
+ ### Notes
14
+
15
+ When too many packages are performing direct SQL queries, it's very hard to keep the code modular.
16
+ The result is a lack of coherent design and degredation in maintainability.
17
+
18
+ ### Rule logic
19
+
20
+ All functions which make SQL queries are inspected. Each one must match one of the
21
+ `allowedPackages`.
22
+
23
+ ### Resolution
24
+
25
+ The code which is making the direct query should be refactored to use the database through one of
26
+ the allowed packages.
27
+
28
+ ### Options
29
+
30
+ - `allowedPackages: `[MatchPatternConfig](/docs/analysis/match-pattern-config.html)`[]`. Packages
31
+ which are allowed to make queries. Required.
32
+ - `allowedQueries: `[MatchPatternConfig](/docs/analysis/match-pattern-config.html)`[]`. Queries which
33
+ are allowed from anywhere. Default:
34
+ `[/\bBEGIN\b/i, /\bCOMMIT\b/i, /\bROLLBACK\b/i, /\bRELEASE\b/i, /\bSAVEPOINT\b/i]`.
35
+
36
+ ### Examples
37
+
38
+ ```yaml
39
+ - rule: queryFromInvalidPackage
40
+ properties:
41
+ callerPackages:
42
+ - equal: actionpack
43
+ calleePackage:
44
+ equal: app/controllers
45
+ ```