oauthlint-rules 0.2.4 → 0.2.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oauthlint-rules",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "description": "Semgrep rules catching the OAuth/OIDC/JWT anti-patterns that AI coding tools systematically produce.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,76 @@
1
+ rules:
2
+ - id: auth.flow.open-redirect
3
+ languages:
4
+ - javascript
5
+ - typescript
6
+ severity: ERROR
7
+ message: |
8
+ Untrusted request input flows into a redirect destination. Because the
9
+ target URL is attacker-controlled, this is an open redirect (CWE-601):
10
+ an attacker can craft a link to your trusted host that bounces the victim
11
+ to an arbitrary external site. That fuels phishing, and in OAuth flows it
12
+ can be chained to steal authorization codes or access tokens by sending
13
+ the victim (and their callback) to a server you do not control.
14
+
15
+ Never redirect to a raw `req.query` / `req.body` / `req.params` /
16
+ `req.cookies` / `req.headers` value. Validate the destination against an
17
+ explicit allow-list of hosts or route names, or only allow relative paths
18
+ you control (reject anything containing a scheme or `//`).
19
+ # Taint mode so indirection is caught — `const dest = req.body.url;
20
+ # res.redirect(dest)` flags, not just the direct `res.redirect(req.query.x)`
21
+ # form. Passing the value through an allow-list / validation call
22
+ # (isAllowedUrl, allowlist.includes, Set.has) clears the taint, so a
23
+ # genuinely validated redirect does not fire.
24
+ mode: taint
25
+ pattern-sources:
26
+ - pattern: $REQ.query
27
+ - pattern: $REQ.params
28
+ - pattern: $REQ.body
29
+ - pattern: $REQ.cookies
30
+ - pattern: $REQ.headers
31
+ - pattern: $REQ.query.$X
32
+ - pattern: $REQ.params.$X
33
+ - pattern: $REQ.body.$X
34
+ - pattern: $REQ.cookies.$X
35
+ - pattern: $REQ.headers.$X
36
+ - pattern: $REQ.query[$K]
37
+ - pattern: $REQ.params[$K]
38
+ - pattern: $REQ.body[$K]
39
+ - pattern: $REQ.cookies[$K]
40
+ - pattern: $REQ.headers[$K]
41
+ pattern-sanitizers:
42
+ # Routing the value through an allow-list / validation helper clears the
43
+ # taint: only the vetted result (not the raw request input) reaches the
44
+ # sink. Matched by a conventional validation-helper call, or by an
45
+ # allow-list membership test (`Set.has` / `Array.includes`) that the
46
+ # value is passed through.
47
+ - pattern: isAllowedUrl(...)
48
+ - pattern: validateRedirect(...)
49
+ - pattern: sanitizeRedirect(...)
50
+ - pattern: $ALLOW.includes(...)
51
+ - pattern: $ALLOW.has(...)
52
+ - pattern: $ALLOW.indexOf(...)
53
+ pattern-sinks:
54
+ - patterns:
55
+ - pattern-either:
56
+ - pattern: $RES.redirect($SINK)
57
+ - pattern: $RES.redirect($CODE, $SINK)
58
+ - pattern: $RES.location($SINK)
59
+ - pattern: "$RES.set('Location', $SINK)"
60
+ - pattern: '$RES.set("Location", $SINK)'
61
+ - pattern: "$RES.setHeader('Location', $SINK)"
62
+ - pattern: '$RES.setHeader("Location", $SINK)'
63
+ - pattern: "$RES.writeHead($S, {..., Location: $SINK, ...})"
64
+ - focus-metavariable: $SINK
65
+ metadata:
66
+ oauthlint-rule-id: AUTH-FLOW-010
67
+ oauthlint-doc-url: https://oauthlint.dev/rules/flow-open-redirect
68
+ category: security
69
+ cwe: CWE-601
70
+ owasp: A01:2021
71
+ llm-prevalence: HIGH
72
+ technology:
73
+ - express
74
+ references:
75
+ - https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
76
+ - https://cwe.mitre.org/data/definitions/601.html
@@ -0,0 +1,85 @@
1
+ rules:
2
+ - id: auth.flow.ssrf
3
+ languages:
4
+ - javascript
5
+ - typescript
6
+ severity: ERROR
7
+ message: |
8
+ Untrusted request input flows into the URL of an outbound HTTP request.
9
+ Because the destination is attacker-controlled, this is a Server-Side
10
+ Request Forgery (CWE-918): an attacker can point the request at internal
11
+ services behind your firewall, or at the cloud metadata endpoint
12
+ (http://169.254.169.254/...) to steal IAM/instance credentials and pivot
13
+ deeper into your infrastructure.
14
+
15
+ Never build a request URL straight from a raw `req.query` / `req.body` /
16
+ `req.params` / `req.cookies` / `req.headers` value. Validate the
17
+ destination against an explicit allow-list of hosts (resolve the URL and
18
+ check its host against the allow-list, rejecting private/loopback ranges)
19
+ before issuing the request.
20
+ # Taint mode so indirection is caught — `const u = req.query.endpoint;
21
+ # http.get(u)` flags, not just the direct `fetch(req.query.url)` form.
22
+ # Passing the value through a host allow-list / validation call
23
+ # (isAllowedUrl, allowlist.includes, Set.has) clears the taint, so a
24
+ # genuinely vetted outbound request does not fire.
25
+ mode: taint
26
+ pattern-sources:
27
+ - pattern: $REQ.query
28
+ - pattern: $REQ.params
29
+ - pattern: $REQ.body
30
+ - pattern: $REQ.cookies
31
+ - pattern: $REQ.headers
32
+ - pattern: $REQ.query.$X
33
+ - pattern: $REQ.params.$X
34
+ - pattern: $REQ.body.$X
35
+ - pattern: $REQ.cookies.$X
36
+ - pattern: $REQ.headers.$X
37
+ - pattern: $REQ.query[$K]
38
+ - pattern: $REQ.params[$K]
39
+ - pattern: $REQ.body[$K]
40
+ - pattern: $REQ.cookies[$K]
41
+ - pattern: $REQ.headers[$K]
42
+ pattern-sanitizers:
43
+ # Routing the value through a host allow-list / validation helper clears
44
+ # the taint: only the vetted destination (not the raw request input)
45
+ # reaches the request. Matched by a conventional validation-helper call,
46
+ # or by an allow-list membership test (`Set.has` / `Array.includes`) that
47
+ # the value is passed through.
48
+ - pattern: isAllowedUrl(...)
49
+ - pattern: validateUrl(...)
50
+ - pattern: assertAllowedHost(...)
51
+ - pattern: $ALLOW.includes(...)
52
+ - pattern: $ALLOW.has(...)
53
+ - pattern: $ALLOW.indexOf(...)
54
+ pattern-sinks:
55
+ - patterns:
56
+ - pattern-either:
57
+ - pattern: fetch($SINK, ...)
58
+ - pattern: nodeFetch($SINK, ...)
59
+ - pattern: request($SINK, ...)
60
+ - pattern: got($SINK, ...)
61
+ - pattern: axios($SINK)
62
+ - pattern: axios.get($SINK, ...)
63
+ - pattern: axios.post($SINK, ...)
64
+ - pattern: axios.put($SINK, ...)
65
+ - pattern: axios.delete($SINK, ...)
66
+ - pattern: "axios.request({..., url: $SINK, ...})"
67
+ - pattern: http.get($SINK, ...)
68
+ - pattern: https.get($SINK, ...)
69
+ - pattern: http.request($SINK, ...)
70
+ - pattern: https.request($SINK, ...)
71
+ - focus-metavariable: $SINK
72
+ metadata:
73
+ oauthlint-rule-id: AUTH-FLOW-011
74
+ oauthlint-doc-url: https://oauthlint.dev/rules/flow-ssrf
75
+ category: security
76
+ cwe: CWE-918
77
+ owasp: API7:2023
78
+ llm-prevalence: HIGH
79
+ technology:
80
+ - express
81
+ - axios
82
+ - fetch
83
+ references:
84
+ - https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
85
+ - https://cwe.mitre.org/data/definitions/918.html
@@ -0,0 +1,58 @@
1
+ rules:
2
+ - id: auth.go.flow.open-redirect
3
+ languages:
4
+ - go
5
+ severity: ERROR
6
+ message: |
7
+ Untrusted request data flows into an HTTP redirect destination. An
8
+ attacker who controls the redirect target (via a query parameter, form
9
+ field, or request header) can forward the victim to an arbitrary
10
+ external site while the link still appears to point at your trusted
11
+ domain — a classic open redirect, commonly abused to bypass OAuth
12
+ `redirect_uri` checks and to mount convincing phishing.
13
+
14
+ Do not pass request-derived values straight into `http.Redirect(...)`
15
+ or a `Location` header. Validate the destination against an explicit
16
+ allow-list, or restrict it to a known relative path (reject absolute
17
+ URLs, scheme-relative `//host` values, and back-references) before
18
+ redirecting. See CWE-601.
19
+ # Taint mode so indirection (dest := r.FormValue("url"); http.Redirect(w,
20
+ # r, dest, ...)) is caught, not just the inline form. The taint is cleared
21
+ # by an allow-list / validation helper that vets the destination, or by a
22
+ # url.Parse(...)-then-checked flow where the parsed value is inspected
23
+ # before use.
24
+ mode: taint
25
+ pattern-sources:
26
+ # $R is the *http.Request. Cover the common net/http input shapes.
27
+ - pattern: $R.URL.Query().Get(...)
28
+ - pattern: $R.URL.Query()
29
+ - pattern: $R.URL.Query()[$K]
30
+ - pattern: $R.FormValue(...)
31
+ - pattern: $R.PostFormValue(...)
32
+ - pattern: $R.Header.Get(...)
33
+ pattern-sanitizers:
34
+ # Allow-list / validation helper that vets the destination string.
35
+ - pattern: validateRedirect(...)
36
+ - pattern: isAllowedRedirect(...)
37
+ - pattern: $ALLOW.MatchString(...)
38
+ # url.Parse-then-checked: a parsed URL that has been inspected is treated
39
+ # as cleared (the result is rebuilt/validated rather than reflected raw).
40
+ - pattern: url.Parse(...)
41
+ pattern-sinks:
42
+ - patterns:
43
+ - pattern-either:
44
+ - pattern: http.Redirect($W, $R, $DEST, $CODE)
45
+ - pattern: $W.Header().Set("Location", $DEST)
46
+ - focus-metavariable: $DEST
47
+ metadata:
48
+ oauthlint-rule-id: AUTH-GO-FLOW-002
49
+ oauthlint-doc-url: https://oauthlint.dev/rules/go-flow-open-redirect
50
+ category: security
51
+ cwe: CWE-601
52
+ owasp: A01:2021
53
+ llm-prevalence: HIGH
54
+ technology:
55
+ - net/http
56
+ references:
57
+ - https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
58
+ - https://cwe.mitre.org/data/definitions/601.html
@@ -0,0 +1,76 @@
1
+ rules:
2
+ - id: auth.go.flow.ssrf
3
+ languages:
4
+ - go
5
+ severity: ERROR
6
+ message: |
7
+ Untrusted request data flows into the URL of an outbound HTTP request.
8
+ An attacker who controls the request target (via a query parameter, form
9
+ field, or request header) can coerce your server into making requests to
10
+ arbitrary destinations — Server-Side Request Forgery (SSRF). This is
11
+ routinely abused to reach internal-only services behind your network
12
+ perimeter and, most damagingly, the cloud instance metadata endpoint
13
+ (e.g. http://169.254.169.254/...), letting an attacker steal short-lived
14
+ credentials and pivot into your cloud account.
15
+
16
+ Never pass a request-derived value straight into `http.Get`,
17
+ `http.Post`, `http.NewRequest`, or a client's `Get`/`Post`. Validate the
18
+ destination host against an explicit allow-list (parse the URL and check
19
+ the resolved host/scheme), and reject requests to private, loopback, and
20
+ link-local address ranges before dialing. See CWE-918.
21
+ # Taint mode so indirection (target := r.FormValue("endpoint");
22
+ # http.Get(target)) is caught, not just the inline form. The taint is
23
+ # cleared by an allow-list / host-validation helper, or by a
24
+ # url.Parse(...)-then-checked flow where the parsed host is vetted before
25
+ # the request is made.
26
+ mode: taint
27
+ pattern-sources:
28
+ # $R is the *http.Request. Cover the common net/http input shapes.
29
+ - pattern: $R.URL.Query().Get(...)
30
+ - pattern: $R.URL.Query()
31
+ - pattern: $R.URL.Query()[$K]
32
+ - pattern: $R.FormValue(...)
33
+ - pattern: $R.PostFormValue(...)
34
+ - pattern: $R.Header.Get(...)
35
+ pattern-sanitizers:
36
+ # Allow-list / host-validation helper that vets the URL string.
37
+ - pattern: validateURL(...)
38
+ - pattern: isAllowedHost(...)
39
+ - pattern: $ALLOW.MatchString(...)
40
+ # url.Parse-then-checked: a parsed URL whose host has been inspected is
41
+ # treated as cleared (the request is built from a vetted destination
42
+ # rather than the raw untrusted string).
43
+ - pattern: url.Parse(...)
44
+ pattern-sinks:
45
+ # Focus the URL argument so the finding lands on the tainted destination,
46
+ # not the whole call. The plain call form is used (no aliasing) because
47
+ # it matches reliably in taint mode.
48
+ - patterns:
49
+ - pattern-either:
50
+ - pattern: http.Get($URL)
51
+ - pattern: http.Post($URL, ...)
52
+ - pattern: http.Head($URL)
53
+ - pattern: http.NewRequest($M, $URL, ...)
54
+ - pattern: http.NewRequestWithContext($CTX, $M, $URL, ...)
55
+ - pattern: $CLIENT.Get($URL)
56
+ - pattern: $CLIENT.Post($URL, ...)
57
+ # The bare `$CLIENT.Get(...)` shape collides with the request-input
58
+ # SOURCES that are themselves `.Get(...)` calls (`r.URL.Query().Get(...)`
59
+ # and `r.Header.Get(...)`), which over-matched the source-assignment
60
+ # line. Exclude those accessors so each is only ever a source, leaving
61
+ # `client.Get(url)` as the genuine outbound-request sink.
62
+ - pattern-not: $Q.Query().Get(...)
63
+ - pattern-not: $H.Header.Get(...)
64
+ - focus-metavariable: $URL
65
+ metadata:
66
+ oauthlint-rule-id: AUTH-GO-FLOW-003
67
+ oauthlint-doc-url: https://oauthlint.dev/rules/go-flow-ssrf
68
+ category: security
69
+ cwe: CWE-918
70
+ owasp: API7:2023
71
+ llm-prevalence: HIGH
72
+ technology:
73
+ - net/http
74
+ references:
75
+ - https://owasp.org/www-community/attacks/Server_Side_Request_Forgery
76
+ - https://cwe.mitre.org/data/definitions/918.html
@@ -0,0 +1,82 @@
1
+ rules:
2
+ - id: auth.py.flow.open-redirect
3
+ languages:
4
+ - python
5
+ severity: ERROR
6
+ message: |
7
+ Untrusted request data flows into a Flask `redirect(...)` without
8
+ validation — an open redirect (CWE-601). An attacker can craft a link
9
+ to your trusted domain that bounces the victim to an attacker-controlled
10
+ site, enabling phishing and OAuth redirect/authorization-code abuse (the
11
+ victim trusts your URL, then lands on the attacker's page).
12
+
13
+ Never redirect to a raw `request.args`/`request.form`/`request.values`/
14
+ `request.cookies`/`request.headers` value. Build the destination with
15
+ `url_for(...)` (safe by construction), or validate the target against an
16
+ explicit allow-list / an `is_safe_url(...)`-style same-host check before
17
+ redirecting.
18
+ # Taint mode so indirection (dest = request.args['url']; return redirect(dest))
19
+ # and `.get(...)` accessors are caught, not just the direct form. Passing the
20
+ # value through url_for(...) or an is_safe_url(...)/allow-list check clears the
21
+ # taint. The sink focuses the redirect target argument (and a Location header).
22
+ mode: taint
23
+ pattern-sources:
24
+ - pattern: flask.request.args
25
+ - pattern: flask.request.form
26
+ - pattern: flask.request.values
27
+ - pattern: flask.request.cookies
28
+ - pattern: flask.request.headers
29
+ - pattern: request.args
30
+ - pattern: request.form
31
+ - pattern: request.values
32
+ - pattern: request.cookies
33
+ - pattern: request.headers
34
+ - pattern: request.args.get(...)
35
+ - pattern: request.form.get(...)
36
+ - pattern: request.values.get(...)
37
+ - pattern: request.cookies.get(...)
38
+ - pattern: request.headers.get(...)
39
+ - pattern: request.args[$K]
40
+ - pattern: request.form[$K]
41
+ - pattern: request.values[$K]
42
+ - pattern: request.cookies[$K]
43
+ - pattern: request.headers[$K]
44
+ pattern-sanitizers:
45
+ # `url_for(...)` builds the URL from a known endpoint — safe by construction.
46
+ - pattern: url_for(...)
47
+ - pattern: flask.url_for(...)
48
+ # Allow-list / same-host validators used as a guard:
49
+ # if is_safe_url(target): return redirect(target)
50
+ # A value used inside such an `if` body is treated as validated, so the
51
+ # guarded redirect does not fire.
52
+ - patterns:
53
+ - pattern: $V
54
+ - pattern-inside: |
55
+ if is_safe_url($V):
56
+ ...
57
+ - patterns:
58
+ - pattern: $V
59
+ - pattern-inside: |
60
+ if url_has_allowed_host_and_scheme($V, ...):
61
+ ...
62
+ pattern-sinks:
63
+ - patterns:
64
+ - pattern-either:
65
+ - pattern: redirect($SINK)
66
+ - pattern: redirect($SINK, ...)
67
+ - pattern: flask.redirect($SINK)
68
+ - pattern: flask.redirect($SINK, ...)
69
+ - pattern: 'Response(..., headers={..., "Location": $SINK, ...}, ...)'
70
+ - focus-metavariable: $SINK
71
+ metadata:
72
+ oauthlint-rule-id: AUTH-PY-FLOW-006
73
+ oauthlint-doc-url: https://oauthlint.dev/rules/py-flow-open-redirect
74
+ category: security
75
+ cwe: CWE-601
76
+ owasp: A01:2021
77
+ llm-prevalence: HIGH
78
+ technology:
79
+ - flask
80
+ references:
81
+ - https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
82
+ - https://cwe.mitre.org/data/definitions/601.html
@@ -0,0 +1,118 @@
1
+ rules:
2
+ - id: auth.py.flow.ssrf
3
+ languages:
4
+ - python
5
+ severity: ERROR
6
+ message: |
7
+ Untrusted request data flows into an outbound HTTP request without
8
+ validation — a Server-Side Request Forgery (SSRF, CWE-918). An attacker
9
+ who controls the target URL can make your server reach internal-only
10
+ services (admin panels, databases, other microservices behind your
11
+ firewall) or the cloud metadata endpoint (e.g. http://169.254.169.254/),
12
+ stealing IAM/instance credentials and pivoting deeper into your network.
13
+
14
+ Never pass a raw `request.args`/`request.form`/`request.values`/
15
+ `request.json`/`request.cookies`/`request.headers` value to
16
+ `requests`/`urllib`/`httpx`/`aiohttp`. Validate the destination host
17
+ against an explicit allow-list (`is_allowed_url(...)` /
18
+ `validate_host(...)` / `url_has_allowed_host_and_scheme(...)`) before the
19
+ request, and reject link-local / private / metadata addresses.
20
+ # Taint mode so indirection (url = request.json['endpoint']; httpx.get(url))
21
+ # and `.get(...)` accessors are caught, not just the direct form. Passing the
22
+ # value through an allow-list / host validator clears the taint. The sink
23
+ # focuses the URL argument of each HTTP client call.
24
+ mode: taint
25
+ pattern-sources:
26
+ - pattern: flask.request.args
27
+ - pattern: flask.request.form
28
+ - pattern: flask.request.values
29
+ - pattern: flask.request.json
30
+ - pattern: flask.request.cookies
31
+ - pattern: flask.request.headers
32
+ - pattern: request.args
33
+ - pattern: request.form
34
+ - pattern: request.values
35
+ - pattern: request.json
36
+ - pattern: request.cookies
37
+ - pattern: request.headers
38
+ - pattern: request.args.get(...)
39
+ - pattern: request.form.get(...)
40
+ - pattern: request.values.get(...)
41
+ - pattern: request.json.get(...)
42
+ - pattern: request.cookies.get(...)
43
+ - pattern: request.headers.get(...)
44
+ - pattern: request.args[$K]
45
+ - pattern: request.form[$K]
46
+ - pattern: request.values[$K]
47
+ - pattern: request.json[$K]
48
+ - pattern: request.cookies[$K]
49
+ - pattern: request.headers[$K]
50
+ pattern-sanitizers:
51
+ # Allow-list / host validators used as a guard:
52
+ # if is_allowed_url(url): requests.get(url)
53
+ # A value used inside such an `if` body is treated as validated, so the
54
+ # guarded request does not fire. `by-side-effect` is unsupported on
55
+ # semgrep 1.157, so we use the `pattern-inside` if-guard approach.
56
+ - patterns:
57
+ - pattern: $V
58
+ - pattern-inside: |
59
+ if is_allowed_url($V):
60
+ ...
61
+ - patterns:
62
+ - pattern: $V
63
+ - pattern-inside: |
64
+ if validate_host($V):
65
+ ...
66
+ - patterns:
67
+ - pattern: $V
68
+ - pattern-inside: |
69
+ if url_has_allowed_host_and_scheme($V, ...):
70
+ ...
71
+ pattern-sinks:
72
+ - patterns:
73
+ - pattern-either:
74
+ - pattern: 'requests.get($URL, ...)'
75
+ - pattern: 'requests.post($URL, ...)'
76
+ - pattern: 'requests.put($URL, ...)'
77
+ - pattern: 'requests.delete($URL, ...)'
78
+ - pattern: 'requests.patch($URL, ...)'
79
+ - pattern: 'requests.head($URL, ...)'
80
+ - pattern: 'requests.request(..., $URL, ...)'
81
+ - pattern: 'urllib.request.urlopen($URL, ...)'
82
+ - pattern: urllib.request.urlopen($URL)
83
+ - pattern: 'httpx.get($URL, ...)'
84
+ - pattern: 'httpx.post($URL, ...)'
85
+ - pattern: 'httpx.put($URL, ...)'
86
+ - pattern: 'httpx.delete($URL, ...)'
87
+ - pattern: 'httpx.patch($URL, ...)'
88
+ - pattern: 'httpx.head($URL, ...)'
89
+ # httpx.Client()/aiohttp session calls. Excluding a `request`
90
+ # receiver keeps these from matching the `request.X.get(...)`
91
+ # SOURCE accessors (which would otherwise self-report).
92
+ - patterns:
93
+ - pattern-either:
94
+ - pattern: '$CLIENT.get($URL, ...)'
95
+ - pattern: '$CLIENT.post($URL, ...)'
96
+ - pattern: '$CLIENT.put($URL, ...)'
97
+ - pattern: '$CLIENT.delete($URL, ...)'
98
+ - pattern: '$CLIENT.patch($URL, ...)'
99
+ - pattern: '$CLIENT.head($URL, ...)'
100
+ - pattern: '$CLIENT.request(..., $URL, ...)'
101
+ - metavariable-regex:
102
+ metavariable: $CLIENT
103
+ regex: '^(?!request(\.|$)).*'
104
+ - focus-metavariable: $URL
105
+ metadata:
106
+ oauthlint-rule-id: AUTH-PY-FLOW-007
107
+ oauthlint-doc-url: https://oauthlint.dev/rules/py-flow-ssrf
108
+ category: security
109
+ cwe: CWE-918
110
+ owasp: API7:2023
111
+ llm-prevalence: HIGH
112
+ technology:
113
+ - flask
114
+ - requests
115
+ - httpx
116
+ references:
117
+ - https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
118
+ - https://cwe.mitre.org/data/definitions/918.html