@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.
- package/README.md +63 -39
- package/built/appMapIndex.js +40 -0
- package/built/appMapIndex.js.map +1 -0
- package/built/check.js +3 -3
- package/built/check.js.map +1 -1
- package/built/checkInstance.js +4 -4
- package/built/checkInstance.js.map +1 -1
- package/built/cli/ci/command.js +21 -26
- package/built/cli/ci/command.js.map +1 -1
- package/built/cli/fail.js +13 -0
- package/built/cli/fail.js.map +1 -0
- package/built/cli/merge/command.js +101 -0
- package/built/cli/merge/command.js.map +1 -0
- package/built/cli/merge/options.js +3 -0
- package/built/cli/merge/options.js.map +1 -0
- package/built/cli/reportUploadURL.js +11 -0
- package/built/cli/reportUploadURL.js.map +1 -0
- package/built/cli/scan/command.js +5 -1
- package/built/cli/scan/command.js.map +1 -1
- package/built/cli/scan/scanner.js +2 -2
- package/built/cli/scan/scanner.js.map +1 -1
- package/built/cli/scan.js +4 -2
- package/built/cli/scan.js.map +1 -1
- package/built/cli/updateCommitStatus.js +65 -0
- package/built/cli/updateCommitStatus.js.map +1 -0
- package/built/cli/upload/command.js +10 -5
- package/built/cli/upload/command.js.map +1 -1
- package/built/cli.js +2 -0
- package/built/cli.js.map +1 -1
- package/built/database/index.js +136 -161
- package/built/database/index.js.map +1 -1
- package/built/integration/appland/{fetchStatus.js → app/listFindingStatus.js} +1 -1
- package/built/integration/appland/app/listFindingStatus.js.map +1 -0
- package/built/integration/appland/{appMap.js → appMap/create.js} +43 -48
- package/built/integration/appland/appMap/create.js.map +1 -0
- package/built/integration/appland/location.js +3 -0
- package/built/integration/appland/location.js.map +1 -0
- package/built/integration/appland/{mapset.js → mapset/create.js} +41 -46
- package/built/integration/appland/mapset/create.js.map +1 -0
- package/built/integration/appland/{upload.js → scannerJob/create.js} +27 -19
- package/built/integration/appland/scannerJob/create.js.map +1 -0
- package/built/integration/appland/scannerJob/merge.js +92 -0
- package/built/integration/appland/scannerJob/merge.js.map +1 -0
- package/built/integration/appland/scannerJob.js +3 -0
- package/built/integration/appland/scannerJob.js.map +1 -0
- package/built/report/summaryReport.js +1 -1
- package/built/report/summaryReport.js.map +1 -1
- package/built/ruleChecker.js +12 -11
- package/built/ruleChecker.js.map +1 -1
- package/built/rules/authzBeforeAuthn.js +6 -0
- package/built/rules/authzBeforeAuthn.js.map +1 -1
- package/built/rules/circularDependency.js +4 -0
- package/built/rules/circularDependency.js.map +1 -1
- package/built/rules/deserializationOfUntrustedData.js +8 -0
- package/built/rules/deserializationOfUntrustedData.js.map +1 -1
- package/built/rules/http500.js +7 -0
- package/built/rules/http500.js.map +1 -1
- package/built/rules/illegalPackageDependency.js +7 -0
- package/built/rules/illegalPackageDependency.js.map +1 -1
- package/built/rules/incompatibleHttpClientRequest.js +7 -0
- package/built/rules/incompatibleHttpClientRequest.js.map +1 -1
- package/built/rules/insecureCompare.js +4 -0
- package/built/rules/insecureCompare.js.map +1 -1
- package/built/rules/jobNotCancelled.js +3 -0
- package/built/rules/jobNotCancelled.js.map +1 -1
- package/built/rules/lib/matchEvent.js +3 -4
- package/built/rules/lib/matchEvent.js.map +1 -1
- package/built/rules/lib/parseRuleDescription.js +18 -0
- package/built/rules/lib/parseRuleDescription.js.map +1 -0
- package/built/rules/logoutWithoutSessionReset.js +8 -0
- package/built/rules/logoutWithoutSessionReset.js.map +1 -1
- package/built/rules/missingAuthentication.js +6 -0
- package/built/rules/missingAuthentication.js.map +1 -1
- package/built/rules/missingContentType.js +6 -0
- package/built/rules/missingContentType.js.map +1 -1
- package/built/rules/nPlusOneQuery.js +8 -2
- package/built/rules/nPlusOneQuery.js.map +1 -1
- package/built/rules/queryFromInvalidPackage.js +6 -0
- package/built/rules/queryFromInvalidPackage.js.map +1 -1
- package/built/rules/queryFromView.js +6 -0
- package/built/rules/queryFromView.js.map +1 -1
- package/built/rules/rpcWithoutCircuitBreaker.js +6 -0
- package/built/rules/rpcWithoutCircuitBreaker.js.map +1 -1
- package/built/rules/saveWithoutValidation.js +6 -0
- package/built/rules/saveWithoutValidation.js.map +1 -1
- package/built/rules/secretInLog.js +3 -0
- package/built/rules/secretInLog.js.map +1 -1
- package/built/rules/slowFunctionCall.js +6 -0
- package/built/rules/slowFunctionCall.js.map +1 -1
- package/built/rules/slowHttpServerRequest.js +6 -0
- package/built/rules/slowHttpServerRequest.js.map +1 -1
- package/built/rules/slowQuery.js +6 -0
- package/built/rules/slowQuery.js.map +1 -1
- package/built/rules/tooManyJoins.js +9 -3
- package/built/rules/tooManyJoins.js.map +1 -1
- package/built/rules/tooManyUpdates.js +6 -0
- package/built/rules/tooManyUpdates.js.map +1 -1
- package/built/rules/unbatchedMaterializedQuery.js +9 -4
- package/built/rules/unbatchedMaterializedQuery.js.map +1 -1
- package/built/rules/updateInGetRequest.js +6 -0
- package/built/rules/updateInGetRequest.js.map +1 -1
- package/built/scope/sqlTransactionScope.js +3 -2
- package/built/scope/sqlTransactionScope.js.map +1 -1
- package/built/sqlWarning.js +56 -0
- package/built/sqlWarning.js.map +1 -0
- package/doc/architecture.md +48 -0
- package/doc/labels/audit.md +7 -0
- package/doc/labels/dao.materialize.md +12 -0
- package/doc/labels/deserialize.safe.md +9 -0
- package/doc/labels/deserialize.unsafe.md +12 -0
- package/doc/labels/http.session.clear.md +7 -0
- package/doc/labels/job.cancel.md +11 -0
- package/doc/labels/job.create.md +13 -0
- package/doc/labels/log.md +12 -0
- package/doc/labels/public.md +8 -0
- package/doc/labels/rpc.circuit_breaker.md +16 -0
- package/doc/labels/sanitize.md +29 -0
- package/doc/labels/secret.md +11 -0
- package/doc/labels/security.authentication.md +10 -0
- package/doc/labels/security.authorization.md +9 -0
- package/doc/labels/security.logout.md +9 -0
- package/doc/labels/string.equals.md +18 -0
- package/doc/rules/authzBeforeAuthn.md +47 -0
- package/doc/rules/circularDependency.md +57 -0
- package/doc/rules/deserializationOfUntrustedData.md +55 -0
- package/doc/rules/http500.md +36 -0
- package/doc/rules/illegalPackageDependency.md +50 -0
- package/doc/rules/incompatibleHttpClientRequest.md +35 -0
- package/doc/rules/insecureCompare.md +59 -0
- package/doc/rules/jobNotCancelled.md +49 -0
- package/doc/rules/logoutWithoutSessionReset.md +40 -0
- package/doc/rules/missingAuthentication.md +59 -0
- package/doc/rules/missingContentType.md +33 -0
- package/doc/rules/nPlusOneQuery.md +52 -0
- package/doc/rules/queryFromInvalidPackage.md +45 -0
- package/doc/rules/queryFromView.md +42 -0
- package/doc/rules/rpcWithoutCircuitBreaker.md +44 -0
- package/doc/rules/saveWithoutValidation.md +33 -0
- package/doc/rules/secretInLog.md +49 -0
- package/doc/rules/slowFunctionCall.md +39 -0
- package/doc/rules/slowHttpServerRequest.md +34 -0
- package/doc/rules/slowQuery.md +33 -0
- package/doc/rules/tooManyJoins.md +40 -0
- package/doc/rules/tooManyUpdates.md +46 -0
- package/doc/rules/unbatchedMaterializedQuery.md +54 -0
- package/doc/rules/updateInGetRequest.md +44 -0
- package/package.json +10 -6
- package/built/integration/appland/appMap.js.map +0 -1
- package/built/integration/appland/fetchStatus.js.map +0 -1
- package/built/integration/appland/mapset.js.map +0 -1
- package/built/integration/appland/upload.js.map +0 -1
|
@@ -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
|
+
```
|