hullproof 0.0.0-stage → 0.5.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/LICENSE +222 -0
- package/NOTICE +32 -0
- package/README.md +313 -2
- package/checks/db.firebase-rules-not-open.json +24 -0
- package/checks/db.rls-every-table.json +25 -0
- package/checks/log.no-credential-in-logs.json +30 -0
- package/checks/secrets.no-env-file-committed.json +31 -0
- package/checks/secrets.no-secret-in-public-env.json +37 -0
- package/checks/storage.firebase-rules-not-open.json +22 -0
- package/checks/supply.no-untrusted-event-in-run.json +23 -0
- package/checks/web.cors-no-reflected-origin.json +31 -0
- package/detectors/ai.json +25 -0
- package/detectors/auth.json +27 -0
- package/detectors/ci.json +19 -0
- package/detectors/containers.json +8 -0
- package/detectors/data_stores.json +38 -0
- package/detectors/frameworks.json +94 -0
- package/detectors/hosting.json +44 -0
- package/detectors/iac.json +43 -0
- package/detectors/languages.json +48 -0
- package/detectors/mobile.json +22 -0
- package/detectors/package_managers.json +39 -0
- package/detectors/payments.json +19 -0
- package/detectors/runtimes.json +17 -0
- package/dist/checks/code/admin-role.js +46 -0
- package/dist/checks/code/owner-filter.js +91 -0
- package/dist/checks/code/shared.js +84 -0
- package/dist/checks/code/webhook-verify.js +77 -0
- package/dist/checks/context.js +64 -0
- package/dist/checks/map/config-checks.js +74 -0
- package/dist/checks/map/entry-checks.js +97 -0
- package/dist/checks/map/shared.js +44 -0
- package/dist/checks/ops.js +307 -0
- package/dist/checks/pro-map.js +1 -0
- package/dist/checks/run.js +92 -0
- package/dist/checks/types.js +1 -0
- package/dist/ci/comment.js +44 -0
- package/dist/ci/sarif-check.js +157 -0
- package/dist/ci/sarif.js +61 -0
- package/dist/cli.js +358 -0
- package/dist/commands/ci.js +115 -0
- package/dist/commands/git.js +58 -0
- package/dist/commands/hooks.js +30 -0
- package/dist/commands/hunt-pro.js +1 -0
- package/dist/commands/hunt.js +86 -0
- package/dist/commands/map.js +33 -0
- package/dist/commands/mcp.js +17 -0
- package/dist/commands/pack.js +48 -0
- package/dist/commands/prove-pro.js +1 -0
- package/dist/commands/prove.js +173 -0
- package/dist/commands/report-gate.js +92 -0
- package/dist/commands/scan.js +158 -0
- package/dist/confirm/agreement.js +18 -0
- package/dist/confirm/chain.js +84 -0
- package/dist/confirm/confirm.js +112 -0
- package/dist/confirm/honesty.js +75 -0
- package/dist/confirm/lead.js +92 -0
- package/dist/confirm/merge.js +88 -0
- package/dist/confirm/query.js +145 -0
- package/dist/confirm/rule.js +86 -0
- package/dist/confirm/store.js +42 -0
- package/dist/confirm/summary.js +6 -0
- package/dist/confirm/synthesis.js +28 -0
- package/dist/discover/detectors.js +50 -0
- package/dist/discover/discover.js +270 -0
- package/dist/discover/extract.js +282 -0
- package/dist/discover/git.js +40 -0
- package/dist/discover/kit-files.js +47 -0
- package/dist/discover/walk.js +110 -0
- package/dist/env.js +57 -0
- package/dist/gate/gate.js +173 -0
- package/dist/hooks/install.js +153 -0
- package/dist/hooks/run.js +112 -0
- package/dist/map/analyze.js +201 -0
- package/dist/map/build.js +253 -0
- package/dist/map/candidates.js +49 -0
- package/dist/map/cblocks.js +77 -0
- package/dist/map/config.js +291 -0
- package/dist/map/dotnet.js +242 -0
- package/dist/map/entry.js +78 -0
- package/dist/map/expo.js +190 -0
- package/dist/map/go.js +292 -0
- package/dist/map/js-express.js +143 -0
- package/dist/map/js-misc.js +295 -0
- package/dist/map/js-next.js +292 -0
- package/dist/map/laravel.js +389 -0
- package/dist/map/lex-more.js +305 -0
- package/dist/map/lex.js +425 -0
- package/dist/map/light-index.js +191 -0
- package/dist/map/light-profiles.js +324 -0
- package/dist/map/light.js +574 -0
- package/dist/map/local-vocab.js +27 -0
- package/dist/map/mobile.js +326 -0
- package/dist/map/py-django.js +281 -0
- package/dist/map/py.js +391 -0
- package/dist/map/rails.js +391 -0
- package/dist/map/repo.js +178 -0
- package/dist/map/rust.js +312 -0
- package/dist/map/spring.js +207 -0
- package/dist/map/taint.js +96 -0
- package/dist/map/touches.js +355 -0
- package/dist/map/vocab.js +88 -0
- package/dist/mapping/controls.js +34 -0
- package/dist/mapping/dependency-policy.js +44 -0
- package/dist/mapping/map.js +44 -0
- package/dist/mapping/maps/gitleaks.json +12 -0
- package/dist/mapping/maps/osv-scanner.json +7 -0
- package/dist/mapping/maps/trivy.json +13 -0
- package/dist/mcp/confine.js +59 -0
- package/dist/mcp/protocol.js +140 -0
- package/dist/mcp/schema.js +43 -0
- package/dist/mcp/server.js +37 -0
- package/dist/mcp/tools.js +238 -0
- package/dist/packs/coverage.js +79 -0
- package/dist/packs/manifest.js +36 -0
- package/dist/packs/validate.js +271 -0
- package/dist/prove/container.js +276 -0
- package/dist/prove/exec-main.js +20 -0
- package/dist/prove/executor.js +149 -0
- package/dist/prove/local.js +131 -0
- package/dist/prove/probes.js +65 -0
- package/dist/prove/recipe.js +278 -0
- package/dist/prove/run.js +136 -0
- package/dist/prove/runner.js +1 -0
- package/dist/prove/safety.js +126 -0
- package/dist/prove/spec.js +357 -0
- package/dist/prove/store.js +65 -0
- package/dist/report/build.js +297 -0
- package/dist/report/entry-points.js +75 -0
- package/dist/report/hunt-section.js +71 -0
- package/dist/report/kit.js +41 -0
- package/dist/report/load.js +35 -0
- package/dist/report/messages.js +273 -0
- package/dist/report/prove-section.js +65 -0
- package/dist/report/report.js +156 -0
- package/dist/report/surface.js +21 -0
- package/dist/report/test-code.js +51 -0
- package/dist/report/tiers.js +44 -0
- package/dist/scanners/common.js +162 -0
- package/dist/scanners/gitleaks.js +90 -0
- package/dist/scanners/index.js +113 -0
- package/dist/scanners/osv-scanner.js +77 -0
- package/dist/scanners/run-targets.js +34 -0
- package/dist/scanners/secret-noise.js +89 -0
- package/dist/scanners/semgrep.js +142 -0
- package/dist/scanners/trivy.js +65 -0
- package/dist/scanners/types.js +1 -0
- package/dist/types/check.js +1 -0
- package/dist/types/codemap.js +1 -0
- package/dist/types/findings.js +5 -0
- package/dist/types/hunt.js +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/prove.js +1 -0
- package/dist/types/results.js +2 -0
- package/dist/types/scan.js +1 -0
- package/dist/types/stack.js +5 -0
- package/dist/util.js +71 -0
- package/dist/version.js +2 -0
- package/package.json +46 -4
- package/packs/android/fixture-result.json +43 -0
- package/packs/android/pack.json +56 -0
- package/packs/dotnet/fixture-result.json +62 -0
- package/packs/dotnet/pack.json +88 -0
- package/packs/expo/answer-key.json +51 -0
- package/packs/expo/fixture-result.json +62 -0
- package/packs/expo/pack.json +79 -0
- package/packs/firebase/answer-key.json +27 -0
- package/packs/firebase/fixture-result.json +43 -0
- package/packs/firebase/pack.json +58 -0
- package/packs/go/answer-key.json +101 -0
- package/packs/go/fixture-result.json +64 -0
- package/packs/go/pack.json +99 -0
- package/packs/ios/fixture-result.json +43 -0
- package/packs/ios/pack.json +55 -0
- package/packs/laravel/answer-key.json +84 -0
- package/packs/laravel/fixture-result.json +60 -0
- package/packs/laravel/pack.json +91 -0
- package/packs/node-ts/answer-key.json +220 -0
- package/packs/node-ts/fixture-result.json +114 -0
- package/packs/node-ts/pack.json +134 -0
- package/packs/python/answer-key.json +195 -0
- package/packs/python/fixture-result.json +119 -0
- package/packs/python/pack.json +121 -0
- package/packs/rails/answer-key.json +84 -0
- package/packs/rails/fixture-result.json +60 -0
- package/packs/rails/pack.json +78 -0
- package/packs/rust/fixture-result.json +43 -0
- package/packs/rust/pack.json +69 -0
- package/packs/spring/fixture-result.json +63 -0
- package/packs/spring/pack.json +103 -0
- package/packs/supabase/answer-key.json +52 -0
- package/packs/supabase/fixture-result.json +58 -0
- package/packs/supabase/pack.json +60 -0
- package/rules/gitleaks.toml +256 -0
- package/rules/semgrep/api-route-no-auth.yaml +31 -0
- package/rules/semgrep/cors-reflect-origin.yaml +48 -0
- package/rules/semgrep/eval-or-new-function.yaml +185 -0
- package/rules/semgrep/log-session-token.yaml +48 -0
- package/rules/semgrep/math-random-tokens.yaml +24 -0
- package/rules/semgrep/next-public-secret-name.yaml +32 -0
- package/rules/semgrep/postgrest-filter-injection.yaml +78 -0
- package/rules/semgrep/raw-sql-concat.yaml +42 -0
- package/rules/semgrep/read-by-id-no-owner.yaml +49 -0
- package/rules/semgrep/server-action-no-auth.yaml +26 -0
- package/rules/semgrep/sql-variants.yaml +99 -0
- package/rules/semgrep/ssrf-unguarded-url.yaml +137 -0
- package/rules/semgrep/subprocess-injection.yaml +163 -0
- package/rules/semgrep/taint-go.yaml +333 -0
- package/rules/semgrep/taint-java.yaml +317 -0
- package/rules/semgrep/taint-javascript.yaml +412 -0
- package/rules/semgrep/taint-php.yaml +361 -0
- package/rules/semgrep/taint-python.yaml +414 -0
- package/rules/semgrep/tool-endpoint-admin-client.yaml +86 -0
- package/rules/semgrep/user-metadata-authz.yaml +22 -0
- package/rules/semgrep/verify-result-unused.yaml +62 -0
- package/rules/semgrep/webhook-parse-before-verify.yaml +29 -0
- package/rules/test-artifact-ids.json +4 -0
- package/rules/tiers.json +427 -0
- package/schemas/check-results.schema.json +55 -0
- package/schemas/check.schema.json +41 -0
- package/schemas/codemap.schema.json +216 -0
- package/schemas/findings.schema.json +1048 -0
- package/schemas/hunt-output.schema.json +46 -0
- package/schemas/hunt-result.schema.json +58 -0
- package/schemas/results.schema.json +17 -0
- package/schemas/scan-hits.schema.json +32 -0
- package/schemas/scan-meta.schema.json +25 -0
- package/schemas/stack.schema.json +93 -0
- package/src/checks/README.md +32 -0
- package/src/checks/code/admin-role.ts +49 -0
- package/src/checks/code/owner-filter.ts +95 -0
- package/src/checks/code/shared.ts +66 -0
- package/src/checks/code/webhook-verify.ts +75 -0
- package/src/checks/context.ts +72 -0
- package/src/checks/map/config-checks.ts +79 -0
- package/src/checks/map/entry-checks.ts +116 -0
- package/src/checks/map/shared.ts +63 -0
- package/src/checks/ops.ts +280 -0
- package/src/checks/pro-map.ts +4 -0
- package/src/checks/run.ts +80 -0
- package/src/checks/types.ts +12 -0
- package/src/ci/comment.ts +52 -0
- package/src/ci/sarif-check.ts +100 -0
- package/src/ci/sarif.ts +72 -0
- package/src/cli.ts +273 -0
- package/src/commands/ci.ts +104 -0
- package/src/commands/git.ts +59 -0
- package/src/commands/hooks.ts +27 -0
- package/src/commands/hunt-pro.ts +4 -0
- package/src/commands/hunt.ts +68 -0
- package/src/commands/map.ts +27 -0
- package/src/commands/mcp.ts +18 -0
- package/src/commands/pack.ts +34 -0
- package/src/commands/prove-pro.ts +4 -0
- package/src/commands/prove.ts +126 -0
- package/src/commands/report-gate.ts +75 -0
- package/src/commands/scan.ts +156 -0
- package/src/confirm/agreement.ts +23 -0
- package/src/confirm/chain.ts +67 -0
- package/src/confirm/confirm.ts +107 -0
- package/src/confirm/honesty.ts +65 -0
- package/src/confirm/lead.ts +76 -0
- package/src/confirm/merge.ts +89 -0
- package/src/confirm/query.ts +126 -0
- package/src/confirm/rule.ts +76 -0
- package/src/confirm/store.ts +42 -0
- package/src/confirm/summary.ts +9 -0
- package/src/confirm/synthesis.ts +33 -0
- package/src/discover/detectors.ts +71 -0
- package/src/discover/discover.ts +253 -0
- package/src/discover/extract.ts +235 -0
- package/src/discover/git.ts +31 -0
- package/src/discover/kit-files.ts +37 -0
- package/src/discover/walk.ts +88 -0
- package/src/env.ts +51 -0
- package/src/gate/gate.ts +169 -0
- package/src/hooks/install.ts +142 -0
- package/src/hooks/run.ts +121 -0
- package/src/map/analyze.ts +219 -0
- package/src/map/build.ts +206 -0
- package/src/map/candidates.ts +47 -0
- package/src/map/cblocks.ts +55 -0
- package/src/map/config.ts +207 -0
- package/src/map/dotnet.ts +205 -0
- package/src/map/entry.ts +80 -0
- package/src/map/expo.ts +171 -0
- package/src/map/go.ts +271 -0
- package/src/map/js-express.ts +135 -0
- package/src/map/js-misc.ts +221 -0
- package/src/map/js-next.ts +282 -0
- package/src/map/laravel.ts +327 -0
- package/src/map/lex-more.ts +152 -0
- package/src/map/lex.ts +274 -0
- package/src/map/light-index.ts +134 -0
- package/src/map/light-profiles.ts +363 -0
- package/src/map/light.ts +484 -0
- package/src/map/local-vocab.ts +30 -0
- package/src/map/mobile.ts +263 -0
- package/src/map/py-django.ts +239 -0
- package/src/map/py.ts +329 -0
- package/src/map/rails.ts +291 -0
- package/src/map/repo.ts +150 -0
- package/src/map/rust.ts +256 -0
- package/src/map/spring.ts +185 -0
- package/src/map/taint.ts +86 -0
- package/src/map/touches.ts +296 -0
- package/src/map/vocab.ts +106 -0
- package/src/mapping/controls.ts +47 -0
- package/src/mapping/dependency-policy.ts +55 -0
- package/src/mapping/map.ts +59 -0
- package/src/mapping/maps/gitleaks.json +12 -0
- package/src/mapping/maps/osv-scanner.json +7 -0
- package/src/mapping/maps/trivy.json +13 -0
- package/src/mcp/confine.ts +44 -0
- package/src/mcp/protocol.ts +144 -0
- package/src/mcp/schema.ts +35 -0
- package/src/mcp/server.ts +32 -0
- package/src/mcp/tools.ts +235 -0
- package/src/packs/coverage.ts +98 -0
- package/src/packs/manifest.ts +97 -0
- package/src/packs/validate.ts +204 -0
- package/src/prove/container.ts +237 -0
- package/src/prove/exec-main.ts +16 -0
- package/src/prove/executor.ts +130 -0
- package/src/prove/local.ts +100 -0
- package/src/prove/probes.ts +68 -0
- package/src/prove/recipe.ts +215 -0
- package/src/prove/run.ts +124 -0
- package/src/prove/runner.ts +28 -0
- package/src/prove/safety.ts +98 -0
- package/src/prove/spec.ts +256 -0
- package/src/prove/store.ts +48 -0
- package/src/report/build.ts +304 -0
- package/src/report/entry-points.ts +78 -0
- package/src/report/hunt-section.ts +67 -0
- package/src/report/kit.ts +59 -0
- package/src/report/load.ts +49 -0
- package/src/report/messages.ts +270 -0
- package/src/report/prove-section.ts +61 -0
- package/src/report/report.ts +160 -0
- package/src/report/surface.ts +32 -0
- package/src/report/test-code.ts +56 -0
- package/src/report/tiers.ts +50 -0
- package/src/scanners/common.ts +149 -0
- package/src/scanners/gitleaks.ts +89 -0
- package/src/scanners/index.ts +103 -0
- package/src/scanners/osv-scanner.ts +90 -0
- package/src/scanners/run-targets.ts +35 -0
- package/src/scanners/secret-noise.ts +80 -0
- package/src/scanners/semgrep.ts +139 -0
- package/src/scanners/trivy.ts +66 -0
- package/src/scanners/types.ts +98 -0
- package/src/types/check.ts +52 -0
- package/src/types/codemap.ts +142 -0
- package/src/types/findings.ts +107 -0
- package/src/types/hunt.ts +97 -0
- package/src/types/index.ts +10 -0
- package/src/types/prove.ts +83 -0
- package/src/types/results.ts +15 -0
- package/src/types/scan.ts +63 -0
- package/src/types/stack.ts +61 -0
- package/src/util.ts +59 -0
- package/src/version.ts +2 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2026 Rare Phronesis Limited
|
|
3
|
+
# Copied from the Hullproof kit (kit/tools/hullproof/rules/ssrf-unguarded-url.yaml).
|
|
4
|
+
#
|
|
5
|
+
rules:
|
|
6
|
+
- id: hullproof-ssrf-request-data-to-url
|
|
7
|
+
languages: [typescript, javascript]
|
|
8
|
+
mode: taint
|
|
9
|
+
options:
|
|
10
|
+
taint_assume_safe_functions: true
|
|
11
|
+
severity: ERROR
|
|
12
|
+
message: >-
|
|
13
|
+
Request data reaches an outbound HTTP call, or the second argument form of new URL, with no guard
|
|
14
|
+
call in between. A caller can point the server at internal hosts, cloud metadata addresses or
|
|
15
|
+
redirects. Resolve the host, reject private, loopback, link local and mapped addresses, connect to
|
|
16
|
+
the address that was checked, and do not follow redirects without checking each hop. If the value
|
|
17
|
+
is only a path or a numeric id, encode it with encodeURIComponent or Number.
|
|
18
|
+
# Guard calls are recognized by name. Edit the regex in the sanitizer below to match the project's own
|
|
19
|
+
# guard function. A guard that is not on the list shows up as a finding, which is the safe failure.
|
|
20
|
+
pattern-sources:
|
|
21
|
+
- patterns:
|
|
22
|
+
- pattern-either:
|
|
23
|
+
- pattern: $R.body
|
|
24
|
+
- pattern: $R.query
|
|
25
|
+
- pattern: $R.params
|
|
26
|
+
- pattern: $R.headers
|
|
27
|
+
- pattern: $R.cookies
|
|
28
|
+
- pattern: $R.url
|
|
29
|
+
- pattern: $R.nextUrl
|
|
30
|
+
- pattern: $R.nextUrl.searchParams
|
|
31
|
+
- pattern: $R.searchParams
|
|
32
|
+
- metavariable-regex:
|
|
33
|
+
metavariable: $R
|
|
34
|
+
regex: ^(req|request|ctx|event|context|c\.req|req\.raw)$
|
|
35
|
+
- patterns:
|
|
36
|
+
- pattern-either:
|
|
37
|
+
- pattern: await $R.json()
|
|
38
|
+
- pattern: await $R.formData()
|
|
39
|
+
- pattern: await $R.text()
|
|
40
|
+
- pattern: $R.json()
|
|
41
|
+
- pattern: $R.formData()
|
|
42
|
+
- metavariable-regex:
|
|
43
|
+
metavariable: $R
|
|
44
|
+
regex: ^(req|request|ctx|c\.req|req\.raw)$
|
|
45
|
+
- patterns:
|
|
46
|
+
- pattern-either:
|
|
47
|
+
- pattern: $S.get(...)
|
|
48
|
+
- pattern: $S.getAll(...)
|
|
49
|
+
- metavariable-regex:
|
|
50
|
+
metavariable: $S
|
|
51
|
+
regex: (?s)^(?:.*\.)?(?:searchParams|params|query)$|^(?:formData|data|fd)$
|
|
52
|
+
pattern-sinks:
|
|
53
|
+
- patterns:
|
|
54
|
+
- pattern: $F($U, ...)
|
|
55
|
+
- focus-metavariable: $U
|
|
56
|
+
- metavariable-regex:
|
|
57
|
+
metavariable: $F
|
|
58
|
+
regex: ^(fetch|axios|got|ky|ofetch|\$fetch|needle|superagent|request|undici\.(fetch|request|stream)|axios\.(get|post|put|patch|delete|head|options|request)|got\.(get|post|put|patch|delete|head|stream)|ky\.(get|post|put|patch|delete|head)|https?\.(get|request)|page\.goto|\w+\.goto)$
|
|
59
|
+
- patterns:
|
|
60
|
+
- pattern: new URL($U, $BASE)
|
|
61
|
+
- focus-metavariable: $U
|
|
62
|
+
pattern-sanitizers:
|
|
63
|
+
- by-side-effect: true
|
|
64
|
+
patterns:
|
|
65
|
+
- pattern: $G($X, ...)
|
|
66
|
+
- focus-metavariable: $X
|
|
67
|
+
- metavariable-regex:
|
|
68
|
+
metavariable: $G
|
|
69
|
+
regex: (?i)(safe|ssrf|allowlist|allowedhost|ispublic|assertpublic|validateurl|validatehost|asserturl|checkurl|guard|resolveandcheck|publicurl|externalurl)
|
|
70
|
+
- pattern: encodeURIComponent(...)
|
|
71
|
+
- pattern: encodeURI(...)
|
|
72
|
+
- pattern: Number(...)
|
|
73
|
+
- pattern: parseInt(...)
|
|
74
|
+
- pattern: parseFloat(...)
|
|
75
|
+
metadata:
|
|
76
|
+
sec_ids: [SEC-API-035, SEC-API-034]
|
|
77
|
+
severity_hint: CRITICAL
|
|
78
|
+
confidence: MEDIUM
|
|
79
|
+
note: >-
|
|
80
|
+
Taint within one file. Does not follow values across files or through function parameters
|
|
81
|
+
that are not request objects. Host allowlist checks written inline (an if on the hostname) are
|
|
82
|
+
not recognized, so those show as findings to be closed by reading the check.
|
|
83
|
+
- id: hullproof-ssrf-url-built-from-base
|
|
84
|
+
languages: [typescript, javascript]
|
|
85
|
+
severity: WARNING
|
|
86
|
+
message: >-
|
|
87
|
+
A fixed base URL is joined to a value by concatenation. If the value comes from a caller, it can
|
|
88
|
+
add an at sign, dot dot segments or a query string and change the host or path that is called.
|
|
89
|
+
Encode path segments with encodeURIComponent, or build the URL with new URL and check its origin.
|
|
90
|
+
patterns:
|
|
91
|
+
- pattern-either:
|
|
92
|
+
- pattern: $F($BASE + $X, ...)
|
|
93
|
+
- pattern: $F($BASE + "/" + $X, ...)
|
|
94
|
+
- metavariable-regex:
|
|
95
|
+
metavariable: $F
|
|
96
|
+
regex: ^(fetch|axios|got|ky|ofetch|\$fetch|undici\.(fetch|request)|axios\.(get|post|put|patch|delete|request))$
|
|
97
|
+
- metavariable-regex:
|
|
98
|
+
metavariable: $BASE
|
|
99
|
+
regex: (?i)^[\w.]*(base|api|host|origin|endpoint|baseurl|root)\w*$
|
|
100
|
+
- metavariable-regex:
|
|
101
|
+
metavariable: $X
|
|
102
|
+
regex: (?s)^(?!["'`])(?!\s*(?:encodeURIComponent|encodeURI|Number|parseInt)\s*\()
|
|
103
|
+
metadata:
|
|
104
|
+
sec_ids: [SEC-API-034, SEC-API-035]
|
|
105
|
+
severity_hint: MEDIUM
|
|
106
|
+
confidence: LOW
|
|
107
|
+
note: >-
|
|
108
|
+
Concatenation only. Template literals that join a base and an id are very common and are not
|
|
109
|
+
matched here to keep noise low. A reviewer should read any outbound URL that is built from a caller value.
|
|
110
|
+
- id: hullproof-ssrf-stored-url
|
|
111
|
+
languages: [typescript, javascript]
|
|
112
|
+
severity: WARNING
|
|
113
|
+
message: >-
|
|
114
|
+
An outbound call uses a URL property from a stored record or an options object (a customer webhook
|
|
115
|
+
endpoint, a callback address, a feed address). The address was supplied by a user earlier, so it is
|
|
116
|
+
request data that was saved. Apply the same host checks at the moment of connection, not only when the
|
|
117
|
+
address was saved, and do not follow redirects without checking each hop.
|
|
118
|
+
patterns:
|
|
119
|
+
- pattern-either:
|
|
120
|
+
- pattern: $F($O.$P, ...)
|
|
121
|
+
- pattern: $F($O.$P)
|
|
122
|
+
- metavariable-regex:
|
|
123
|
+
metavariable: $F
|
|
124
|
+
regex: ^(fetch|axios|got|ky|ofetch|\$fetch|needle|superagent|undici\.(fetch|request)|axios\.(get|post|put|patch|delete|head|request)|got\.(get|post|put|patch|delete|head|stream)|https?\.(get|request))$
|
|
125
|
+
- metavariable-regex:
|
|
126
|
+
metavariable: $P
|
|
127
|
+
regex: (?i)^(url|webhookurl|callbackurl|endpoint|endpointurl|targeturl|hookurl|feedurl|href|uri)$
|
|
128
|
+
- metavariable-regex:
|
|
129
|
+
metavariable: $O
|
|
130
|
+
regex: (?s)^(?!(?:window|document|location|response|res|resp|result|self|this|process|req|request|ctx|event|body|query|params|import\.meta|import_meta|new URL)\b)
|
|
131
|
+
metadata:
|
|
132
|
+
sec_ids: [SEC-API-035, SEC-API-034]
|
|
133
|
+
severity_hint: HIGH
|
|
134
|
+
confidence: LOW
|
|
135
|
+
note: >-
|
|
136
|
+
Name based lead. It finds the common customer webhook shape that the request taint rule cannot see
|
|
137
|
+
because the value comes from a database row. Confirm whether a guard runs at connection time.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2026 Rare Phronesis Limited
|
|
3
|
+
# Copied from the Hullproof kit (kit/tools/hullproof/rules/subprocess-injection.yaml).
|
|
4
|
+
#
|
|
5
|
+
rules:
|
|
6
|
+
- id: hullproof-subprocess-shell-string
|
|
7
|
+
languages: [typescript, javascript]
|
|
8
|
+
severity: ERROR
|
|
9
|
+
message: >-
|
|
10
|
+
A command string that is not a constant goes to a shell. Anything in the string can add commands.
|
|
11
|
+
Call the program directly with an argument array (execFile, spawn with no shell), pass user values
|
|
12
|
+
only as separate arguments after a double dash, and never concatenate them into the command.
|
|
13
|
+
patterns:
|
|
14
|
+
- pattern-either:
|
|
15
|
+
- pattern: exec($C, ...)
|
|
16
|
+
- pattern: execSync($C, ...)
|
|
17
|
+
- pattern: execAsync($C, ...)
|
|
18
|
+
- pattern: execPromise($C, ...)
|
|
19
|
+
- pattern: execP($C, ...)
|
|
20
|
+
- pattern: execaCommand($C, ...)
|
|
21
|
+
- pattern: execaCommandSync($C, ...)
|
|
22
|
+
- pattern: promisify(exec)($C, ...)
|
|
23
|
+
- pattern: util.promisify(exec)($C, ...)
|
|
24
|
+
- pattern: shell.exec($C, ...)
|
|
25
|
+
- pattern: shelljs.exec($C, ...)
|
|
26
|
+
- patterns:
|
|
27
|
+
- pattern-either:
|
|
28
|
+
- pattern: $CP.exec($C, ...)
|
|
29
|
+
- pattern: $CP.execSync($C, ...)
|
|
30
|
+
- metavariable-regex:
|
|
31
|
+
metavariable: $CP
|
|
32
|
+
regex: ^(cp|child_process|childProcess|proc|node_child_process|cproc)$
|
|
33
|
+
- patterns:
|
|
34
|
+
- pattern: '$F($C, ..., {..., shell: true, ...})'
|
|
35
|
+
- metavariable-regex:
|
|
36
|
+
metavariable: $F
|
|
37
|
+
regex: ^(?:\w+\.)?(?:execFile|execFileSync|spawn|spawnSync|execa|execaSync)$
|
|
38
|
+
- metavariable-regex:
|
|
39
|
+
metavariable: $C
|
|
40
|
+
regex: (?s)^(?!(?:"[^"\\]*"|'[^'\\]*'|`[^`$\\]*`)$)
|
|
41
|
+
metadata:
|
|
42
|
+
sec_ids: [SEC-API-020]
|
|
43
|
+
severity_hint: CRITICAL
|
|
44
|
+
confidence: MEDIUM
|
|
45
|
+
note: >-
|
|
46
|
+
Any command that is not a plain string literal. A command built only from constants held in
|
|
47
|
+
variables is a false positive. The bare exec name is matched only as a function call, so
|
|
48
|
+
RegExp exec on a variable is not matched.
|
|
49
|
+
- id: hullproof-subprocess-shell-interpreter
|
|
50
|
+
languages: [typescript, javascript]
|
|
51
|
+
severity: ERROR
|
|
52
|
+
message: >-
|
|
53
|
+
A shell interpreter is started with a script argument that is not a constant. This is the same as
|
|
54
|
+
running a command string through a shell. Run the target program directly with an argument array.
|
|
55
|
+
patterns:
|
|
56
|
+
- pattern-either:
|
|
57
|
+
- pattern: $F($SH, [..., "-c", $S, ...], ...)
|
|
58
|
+
- pattern: $F($SH, [..., "/c", $S, ...], ...)
|
|
59
|
+
- pattern: $F($SH, [..., "/C", $S, ...], ...)
|
|
60
|
+
- pattern: $F($SH, [..., "-Command", $S, ...], ...)
|
|
61
|
+
- pattern: $F($SH, [..., "-lc", $S, ...], ...)
|
|
62
|
+
- metavariable-regex:
|
|
63
|
+
metavariable: $SH
|
|
64
|
+
regex: (?i)^["'`](?:.*[/\\])?(?:sh|bash|zsh|dash|ksh|fish|cmd|cmd\.exe|powershell|powershell\.exe|pwsh|pwsh\.exe)["'`]$
|
|
65
|
+
- metavariable-regex:
|
|
66
|
+
metavariable: $F
|
|
67
|
+
regex: ^(?:\w+\.)?(?:execFile|execFileSync|spawn|spawnSync|execa|execaSync|fork)$
|
|
68
|
+
- metavariable-regex:
|
|
69
|
+
metavariable: $S
|
|
70
|
+
regex: (?s)^(?!(?:"[^"\\]*"|'[^'\\]*'|`[^`$\\]*`)$)
|
|
71
|
+
metadata:
|
|
72
|
+
sec_ids: [SEC-API-020]
|
|
73
|
+
severity_hint: CRITICAL
|
|
74
|
+
confidence: HIGH
|
|
75
|
+
- id: hullproof-subprocess-arg-no-separator
|
|
76
|
+
languages: [typescript, javascript]
|
|
77
|
+
severity: WARNING
|
|
78
|
+
message: >-
|
|
79
|
+
A program is started with an argument that is not a constant, and the argument list has no double
|
|
80
|
+
dash separator. If the value starts with a dash the program reads it as an option (for example git
|
|
81
|
+
ls-remote with an upload pack option runs a command). Put the double dash before user values, check
|
|
82
|
+
that the value does not start with a dash, and pin the allowed options.
|
|
83
|
+
patterns:
|
|
84
|
+
- pattern-either:
|
|
85
|
+
- pattern: $F($BIN, [..., $A, ...], ...)
|
|
86
|
+
- metavariable-regex:
|
|
87
|
+
metavariable: $F
|
|
88
|
+
regex: ^(?:\w+\.)?(?:execFile|execFileSync|spawn|spawnSync|execa|execaSync)$
|
|
89
|
+
- metavariable-regex:
|
|
90
|
+
metavariable: $A
|
|
91
|
+
regex: (?s)^(?!(?:"[^"\\]*"|'[^'\\]*'|`[^`$\\]*`)$)
|
|
92
|
+
- pattern-not: $F($BIN, [..., "--", ...], ...)
|
|
93
|
+
- metavariable-regex:
|
|
94
|
+
metavariable: $BIN
|
|
95
|
+
regex: (?is)^(??(?:sh|bash|zsh|dash|ksh|fish|cmd|cmd\.exe|powershell|powershell\.exe|pwsh|pwsh\.exe)["'`]$)
|
|
96
|
+
metadata:
|
|
97
|
+
sec_ids: [SEC-API-020]
|
|
98
|
+
severity_hint: HIGH
|
|
99
|
+
confidence: LOW
|
|
100
|
+
note: >-
|
|
101
|
+
Every call that passes a non constant list entry without a double dash anywhere in the list.
|
|
102
|
+
Many calls pass a constant held in a variable, or a program that has no dash options. Review each.
|
|
103
|
+
Option injection is a program specific issue: git, curl, tar, ssh, rsync, ffmpeg and convert are
|
|
104
|
+
the usual targets.
|
|
105
|
+
- id: hullproof-subprocess-request-data
|
|
106
|
+
languages: [typescript, javascript]
|
|
107
|
+
mode: taint
|
|
108
|
+
severity: ERROR
|
|
109
|
+
message: >-
|
|
110
|
+
Request data reaches a subprocess call. Run a fixed program with a fixed argument list, put user
|
|
111
|
+
values after a double dash, and allowlist the values that are allowed.
|
|
112
|
+
pattern-sources:
|
|
113
|
+
- patterns:
|
|
114
|
+
- pattern-either:
|
|
115
|
+
- pattern: $R.body
|
|
116
|
+
- pattern: $R.query
|
|
117
|
+
- pattern: $R.params
|
|
118
|
+
- pattern: $R.headers
|
|
119
|
+
- pattern: $R.url
|
|
120
|
+
- pattern: $R.nextUrl.searchParams
|
|
121
|
+
- pattern: $R.searchParams
|
|
122
|
+
- metavariable-regex:
|
|
123
|
+
metavariable: $R
|
|
124
|
+
regex: ^(req|request|ctx|event|context|c\.req|req\.raw)$
|
|
125
|
+
- patterns:
|
|
126
|
+
- pattern-either:
|
|
127
|
+
- pattern: await $R.json()
|
|
128
|
+
- pattern: await $R.formData()
|
|
129
|
+
- pattern: await $R.text()
|
|
130
|
+
- metavariable-regex:
|
|
131
|
+
metavariable: $R
|
|
132
|
+
regex: ^(req|request|ctx|c\.req|req\.raw)$
|
|
133
|
+
- patterns:
|
|
134
|
+
- pattern-either:
|
|
135
|
+
- pattern: $S.get(...)
|
|
136
|
+
- pattern: $S.getAll(...)
|
|
137
|
+
- metavariable-regex:
|
|
138
|
+
metavariable: $S
|
|
139
|
+
regex: ^(searchParams|formData|params|query|\w+\.searchParams|data|fd)$
|
|
140
|
+
pattern-sinks:
|
|
141
|
+
- patterns:
|
|
142
|
+
- pattern-either:
|
|
143
|
+
- pattern: $F($C, ...)
|
|
144
|
+
- pattern: $F($C2, [...], ...)
|
|
145
|
+
- focus-metavariable: $C
|
|
146
|
+
- metavariable-regex:
|
|
147
|
+
metavariable: $F
|
|
148
|
+
regex: ^(?:\w+\.)?(?:exec|execSync|execFile|execFileSync|spawn|spawnSync|execa|execaSync|execaCommand|fork)$
|
|
149
|
+
- patterns:
|
|
150
|
+
- pattern: $F($BIN, [..., $A, ...], ...)
|
|
151
|
+
- focus-metavariable: $A
|
|
152
|
+
- metavariable-regex:
|
|
153
|
+
metavariable: $F
|
|
154
|
+
regex: ^(?:\w+\.)?(?:exec|execSync|execFile|execFileSync|spawn|spawnSync|execa|execaSync|fork)$
|
|
155
|
+
pattern-sanitizers:
|
|
156
|
+
- pattern: Number(...)
|
|
157
|
+
- pattern: parseInt(...)
|
|
158
|
+
- pattern: parseFloat(...)
|
|
159
|
+
metadata:
|
|
160
|
+
sec_ids: [SEC-API-020]
|
|
161
|
+
severity_hint: CRITICAL
|
|
162
|
+
confidence: HIGH
|
|
163
|
+
note: Taint within one file. The parameter names of the request object are matched by name (req, request, ctx, event).
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2026 Rare Phronesis Limited
|
|
3
|
+
# Written for the Hullproof Engine from the CWE definitions named in each rule. Not copied or derived from any Semgrep
|
|
4
|
+
# registry rule. Fixtures: test/fixtures/rules/taint-go.go, run by test/rules.test.ts with semgrep --test.
|
|
5
|
+
#
|
|
6
|
+
# Sources are request data in net/http (an *http.Request), gorilla/mux and chi route variables, Gin (*gin.Context) and
|
|
7
|
+
# Echo (echo.Context). Taint flows through string building, fmt.Sprintf, assignment and calls by default. A project
|
|
8
|
+
# guard is recognised when its name says what it checks.
|
|
9
|
+
rules:
|
|
10
|
+
- id: hullproof-taint-go-sql-injection
|
|
11
|
+
languages: [go]
|
|
12
|
+
mode: taint
|
|
13
|
+
severity: ERROR
|
|
14
|
+
message: >-
|
|
15
|
+
Request data reaches the text of a SQL query (CWE-89). Pass values as query arguments with placeholders
|
|
16
|
+
(db.Query("... WHERE id = $1", id)) and keep the query text constant; with GORM, use Where with ? placeholders.
|
|
17
|
+
metadata:
|
|
18
|
+
cwe: "CWE-89: Improper Neutralization of Special Elements used in an SQL Command"
|
|
19
|
+
sec_ids: [SEC-API-017]
|
|
20
|
+
pattern-sources:
|
|
21
|
+
- patterns:
|
|
22
|
+
- pattern: '($R : *http.Request).$M(...)'
|
|
23
|
+
- metavariable-regex:
|
|
24
|
+
metavariable: $M
|
|
25
|
+
regex: ^(FormValue|PostFormValue|Cookie|Cookies|FormFile|MultipartReader|Referer|UserAgent)$
|
|
26
|
+
- patterns:
|
|
27
|
+
- pattern: '($R : *http.Request).$F'
|
|
28
|
+
- metavariable-regex:
|
|
29
|
+
metavariable: $F
|
|
30
|
+
regex: ^(URL|Form|PostForm|MultipartForm|Header|Body|RequestURI|Host)$
|
|
31
|
+
- pattern: mux.Vars(...)
|
|
32
|
+
- pattern: chi.URLParam(...)
|
|
33
|
+
- patterns:
|
|
34
|
+
- pattern-either:
|
|
35
|
+
- pattern: '($C : *gin.Context).$G(...)'
|
|
36
|
+
- pattern: '($C : echo.Context).$G(...)'
|
|
37
|
+
- metavariable-regex:
|
|
38
|
+
metavariable: $G
|
|
39
|
+
regex: ^(Query|DefaultQuery|QueryArray|QueryMap|GetQuery|Param|Params|PostForm|DefaultPostForm|PostFormArray|GetPostForm|GetHeader|Cookie|FormValue|QueryParam|QueryParams|FormParams|GetRawData|FormFile|ShouldBind|ShouldBindJSON|ShouldBindQuery|Bind|BindJSON)$
|
|
40
|
+
pattern-sanitizers:
|
|
41
|
+
- pattern-either:
|
|
42
|
+
- pattern: strconv.Atoi(...)
|
|
43
|
+
- pattern: strconv.ParseInt(...)
|
|
44
|
+
- pattern: strconv.ParseUint(...)
|
|
45
|
+
- pattern: strconv.ParseFloat(...)
|
|
46
|
+
- pattern: strconv.ParseBool(...)
|
|
47
|
+
- pattern: uuid.Parse(...)
|
|
48
|
+
pattern-sinks:
|
|
49
|
+
- patterns:
|
|
50
|
+
- pattern-either:
|
|
51
|
+
- patterns:
|
|
52
|
+
- pattern: $DB.$M($Q, ...)
|
|
53
|
+
- metavariable-regex:
|
|
54
|
+
metavariable: $M
|
|
55
|
+
regex: ^(Query|QueryRow|Exec|Prepare|Queryx|QueryRowx|MustExec|NamedExec|NamedQuery|Raw|Where|Order|Having|Joins)$
|
|
56
|
+
- patterns:
|
|
57
|
+
- pattern: $DB.$M($DEST, $Q, ...)
|
|
58
|
+
- metavariable-regex:
|
|
59
|
+
metavariable: $M
|
|
60
|
+
regex: ^(Get|Select)$
|
|
61
|
+
- patterns:
|
|
62
|
+
- pattern: $DB.$M($CTX, $Q, ...)
|
|
63
|
+
- metavariable-regex:
|
|
64
|
+
metavariable: $M
|
|
65
|
+
regex: ^(QueryContext|QueryRowContext|ExecContext|PrepareContext|QueryxContext|QueryRowxContext|GetContext|SelectContext)$
|
|
66
|
+
- pattern-not: '($C : *gin.Context).$M(...)'
|
|
67
|
+
- pattern-not: '($C : echo.Context).$M(...)'
|
|
68
|
+
- pattern-not: http.$M(...)
|
|
69
|
+
- pattern-not: '($CL : *http.Client).$M(...)'
|
|
70
|
+
- focus-metavariable: $Q
|
|
71
|
+
|
|
72
|
+
- id: hullproof-taint-go-xss
|
|
73
|
+
languages: [go]
|
|
74
|
+
mode: taint
|
|
75
|
+
severity: ERROR
|
|
76
|
+
message: >-
|
|
77
|
+
Request data is written into an HTML response without encoding (CWE-79). Render it with html/template, which
|
|
78
|
+
escapes by context, or encode it with html.EscapeString before writing it; never wrap request data in
|
|
79
|
+
template.HTML.
|
|
80
|
+
metadata:
|
|
81
|
+
cwe: "CWE-79: Improper Neutralization of Input During Web Page Generation"
|
|
82
|
+
sec_ids: [SEC-WEB-031]
|
|
83
|
+
pattern-sources:
|
|
84
|
+
- patterns:
|
|
85
|
+
- pattern: '($R : *http.Request).$M(...)'
|
|
86
|
+
- metavariable-regex:
|
|
87
|
+
metavariable: $M
|
|
88
|
+
regex: ^(FormValue|PostFormValue|Cookie|Cookies|FormFile|MultipartReader|Referer|UserAgent)$
|
|
89
|
+
- patterns:
|
|
90
|
+
- pattern: '($R : *http.Request).$F'
|
|
91
|
+
- metavariable-regex:
|
|
92
|
+
metavariable: $F
|
|
93
|
+
regex: ^(URL|Form|PostForm|MultipartForm|Header|Body|RequestURI|Host)$
|
|
94
|
+
- pattern: mux.Vars(...)
|
|
95
|
+
- pattern: chi.URLParam(...)
|
|
96
|
+
- patterns:
|
|
97
|
+
- pattern-either:
|
|
98
|
+
- pattern: '($C : *gin.Context).$G(...)'
|
|
99
|
+
- pattern: '($C : echo.Context).$G(...)'
|
|
100
|
+
- metavariable-regex:
|
|
101
|
+
metavariable: $G
|
|
102
|
+
regex: ^(Query|DefaultQuery|QueryArray|QueryMap|GetQuery|Param|Params|PostForm|DefaultPostForm|PostFormArray|GetPostForm|GetHeader|Cookie|FormValue|QueryParam|QueryParams|FormParams|GetRawData|FormFile|ShouldBind|ShouldBindJSON|ShouldBindQuery|Bind|BindJSON)$
|
|
103
|
+
pattern-sanitizers:
|
|
104
|
+
- pattern-either:
|
|
105
|
+
- pattern: strconv.Atoi(...)
|
|
106
|
+
- pattern: strconv.ParseInt(...)
|
|
107
|
+
- pattern: strconv.ParseUint(...)
|
|
108
|
+
- pattern: strconv.ParseFloat(...)
|
|
109
|
+
- pattern: strconv.ParseBool(...)
|
|
110
|
+
- pattern: uuid.Parse(...)
|
|
111
|
+
|
|
112
|
+
- pattern-either:
|
|
113
|
+
- pattern: html.EscapeString(...)
|
|
114
|
+
- pattern: template.HTMLEscapeString(...)
|
|
115
|
+
- pattern: template.JSEscapeString(...)
|
|
116
|
+
- pattern: url.QueryEscape(...)
|
|
117
|
+
- pattern: url.PathEscape(...)
|
|
118
|
+
- pattern: json.Marshal(...)
|
|
119
|
+
pattern-sinks:
|
|
120
|
+
- patterns:
|
|
121
|
+
- pattern-either:
|
|
122
|
+
- pattern: '($W : http.ResponseWriter).Write($X)'
|
|
123
|
+
- pattern: 'fmt.Fprintf(($W : http.ResponseWriter), ..., $X, ...)'
|
|
124
|
+
- pattern: 'fmt.Fprint(($W : http.ResponseWriter), ..., $X, ...)'
|
|
125
|
+
- pattern: 'fmt.Fprintln(($W : http.ResponseWriter), ..., $X, ...)'
|
|
126
|
+
- pattern: 'io.WriteString(($W : http.ResponseWriter), $X)'
|
|
127
|
+
- pattern: template.HTML($X)
|
|
128
|
+
- pattern: template.JS($X)
|
|
129
|
+
- pattern: template.HTMLAttr($X)
|
|
130
|
+
- pattern: '($C : *gin.Context).Writer.WriteString($X)'
|
|
131
|
+
- pattern: '($C : echo.Context).HTML($CODE, $X)'
|
|
132
|
+
- patterns:
|
|
133
|
+
- pattern: '($C : *gin.Context).Data($CODE, $CT, $X)'
|
|
134
|
+
- metavariable-regex:
|
|
135
|
+
metavariable: $CT
|
|
136
|
+
regex: (?i).*html.*
|
|
137
|
+
- focus-metavariable: $X
|
|
138
|
+
|
|
139
|
+
- id: hullproof-taint-go-command-injection
|
|
140
|
+
languages: [go]
|
|
141
|
+
mode: taint
|
|
142
|
+
severity: ERROR
|
|
143
|
+
message: >-
|
|
144
|
+
Request data reaches an operating system command or chooses the program that runs (CWE-78). Run a fixed program
|
|
145
|
+
with exec.Command and separate arguments, never through sh -c, and map the request value to a fixed set of
|
|
146
|
+
options.
|
|
147
|
+
metadata:
|
|
148
|
+
cwe: "CWE-78: Improper Neutralization of Special Elements used in an OS Command"
|
|
149
|
+
sec_ids: [SEC-API-020]
|
|
150
|
+
pattern-sources:
|
|
151
|
+
- patterns:
|
|
152
|
+
- pattern: '($R : *http.Request).$M(...)'
|
|
153
|
+
- metavariable-regex:
|
|
154
|
+
metavariable: $M
|
|
155
|
+
regex: ^(FormValue|PostFormValue|Cookie|Cookies|FormFile|MultipartReader|Referer|UserAgent)$
|
|
156
|
+
- patterns:
|
|
157
|
+
- pattern: '($R : *http.Request).$F'
|
|
158
|
+
- metavariable-regex:
|
|
159
|
+
metavariable: $F
|
|
160
|
+
regex: ^(URL|Form|PostForm|MultipartForm|Header|Body|RequestURI|Host)$
|
|
161
|
+
- pattern: mux.Vars(...)
|
|
162
|
+
- pattern: chi.URLParam(...)
|
|
163
|
+
- patterns:
|
|
164
|
+
- pattern-either:
|
|
165
|
+
- pattern: '($C : *gin.Context).$G(...)'
|
|
166
|
+
- pattern: '($C : echo.Context).$G(...)'
|
|
167
|
+
- metavariable-regex:
|
|
168
|
+
metavariable: $G
|
|
169
|
+
regex: ^(Query|DefaultQuery|QueryArray|QueryMap|GetQuery|Param|Params|PostForm|DefaultPostForm|PostFormArray|GetPostForm|GetHeader|Cookie|FormValue|QueryParam|QueryParams|FormParams|GetRawData|FormFile|ShouldBind|ShouldBindJSON|ShouldBindQuery|Bind|BindJSON)$
|
|
170
|
+
pattern-sanitizers:
|
|
171
|
+
- pattern-either:
|
|
172
|
+
- pattern: strconv.Atoi(...)
|
|
173
|
+
- pattern: strconv.ParseInt(...)
|
|
174
|
+
- pattern: strconv.ParseUint(...)
|
|
175
|
+
- pattern: strconv.ParseFloat(...)
|
|
176
|
+
- pattern: strconv.ParseBool(...)
|
|
177
|
+
- pattern: uuid.Parse(...)
|
|
178
|
+
pattern-sinks:
|
|
179
|
+
- patterns:
|
|
180
|
+
- pattern-either:
|
|
181
|
+
- pattern: exec.Command($X, ...)
|
|
182
|
+
- pattern: exec.CommandContext($CTX, $X, ...)
|
|
183
|
+
- pattern: exec.Command($SH, "-c", $X, ...)
|
|
184
|
+
- pattern: exec.CommandContext($CTX, $SH, "-c", $X, ...)
|
|
185
|
+
- pattern: syscall.Exec($X, ...)
|
|
186
|
+
- focus-metavariable: $X
|
|
187
|
+
|
|
188
|
+
- id: hullproof-taint-go-path-traversal
|
|
189
|
+
languages: [go]
|
|
190
|
+
mode: taint
|
|
191
|
+
severity: WARNING
|
|
192
|
+
message: >-
|
|
193
|
+
Request data becomes part of a file path the server opens, writes, lists, deletes or serves (CWE-22).
|
|
194
|
+
filepath.Clean alone does not stop a relative path from leaving the folder. Reduce the name with filepath.Base,
|
|
195
|
+
or join it to a fixed root and check the result still has that root as its prefix before using it.
|
|
196
|
+
metadata:
|
|
197
|
+
cwe: "CWE-22: Improper Limitation of a Pathname to a Restricted Directory"
|
|
198
|
+
sec_ids: []
|
|
199
|
+
pattern-sources:
|
|
200
|
+
- patterns:
|
|
201
|
+
- pattern: '($R : *http.Request).$M(...)'
|
|
202
|
+
- metavariable-regex:
|
|
203
|
+
metavariable: $M
|
|
204
|
+
regex: ^(FormValue|PostFormValue|Cookie|Cookies|FormFile|MultipartReader|Referer|UserAgent)$
|
|
205
|
+
- patterns:
|
|
206
|
+
- pattern: '($R : *http.Request).$F'
|
|
207
|
+
- metavariable-regex:
|
|
208
|
+
metavariable: $F
|
|
209
|
+
regex: ^(URL|Form|PostForm|MultipartForm|Header|Body|RequestURI|Host)$
|
|
210
|
+
- pattern: mux.Vars(...)
|
|
211
|
+
- pattern: chi.URLParam(...)
|
|
212
|
+
- patterns:
|
|
213
|
+
- pattern-either:
|
|
214
|
+
- pattern: '($C : *gin.Context).$G(...)'
|
|
215
|
+
- pattern: '($C : echo.Context).$G(...)'
|
|
216
|
+
- metavariable-regex:
|
|
217
|
+
metavariable: $G
|
|
218
|
+
regex: ^(Query|DefaultQuery|QueryArray|QueryMap|GetQuery|Param|Params|PostForm|DefaultPostForm|PostFormArray|GetPostForm|GetHeader|Cookie|FormValue|QueryParam|QueryParams|FormParams|GetRawData|FormFile|ShouldBind|ShouldBindJSON|ShouldBindQuery|Bind|BindJSON)$
|
|
219
|
+
pattern-sanitizers:
|
|
220
|
+
- pattern-either:
|
|
221
|
+
- pattern: strconv.Atoi(...)
|
|
222
|
+
- pattern: strconv.ParseInt(...)
|
|
223
|
+
- pattern: strconv.ParseUint(...)
|
|
224
|
+
- pattern: strconv.ParseFloat(...)
|
|
225
|
+
- pattern: strconv.ParseBool(...)
|
|
226
|
+
- pattern: uuid.Parse(...)
|
|
227
|
+
|
|
228
|
+
- pattern-either:
|
|
229
|
+
- pattern: filepath.Base(...)
|
|
230
|
+
- pattern: path.Base(...)
|
|
231
|
+
|
|
232
|
+
- by-side-effect: true
|
|
233
|
+
patterns:
|
|
234
|
+
- pattern: $GUARD($X, ...)
|
|
235
|
+
- metavariable-regex:
|
|
236
|
+
metavariable: $GUARD
|
|
237
|
+
regex: (?i)^(.*\.)?\w*(safe|allow|valid|guard|check|verify|within|inside|contain)\w*$
|
|
238
|
+
- focus-metavariable: $X
|
|
239
|
+
pattern-sinks:
|
|
240
|
+
- patterns:
|
|
241
|
+
- pattern-either:
|
|
242
|
+
- patterns:
|
|
243
|
+
- pattern: os.$F($X, ...)
|
|
244
|
+
- metavariable-regex:
|
|
245
|
+
metavariable: $F
|
|
246
|
+
regex: ^(Open|OpenFile|Create|ReadFile|WriteFile|Remove|RemoveAll|Mkdir|MkdirAll|ReadDir|Stat|Lstat|Rename|Chmod|Truncate)$
|
|
247
|
+
- pattern: os.Rename($S, $X)
|
|
248
|
+
- pattern: ioutil.ReadFile($X)
|
|
249
|
+
- pattern: ioutil.WriteFile($X, ...)
|
|
250
|
+
- pattern: ioutil.ReadDir($X)
|
|
251
|
+
- pattern: http.ServeFile($W, $R, $X)
|
|
252
|
+
- pattern: '($C : *gin.Context).File($X)'
|
|
253
|
+
- pattern: '($C : *gin.Context).FileAttachment($X, ...)'
|
|
254
|
+
- pattern: '($C : echo.Context).File($X)'
|
|
255
|
+
- pattern: '($C : echo.Context).Attachment($X, ...)'
|
|
256
|
+
- focus-metavariable: $X
|
|
257
|
+
|
|
258
|
+
- id: hullproof-taint-go-ssrf
|
|
259
|
+
languages: [go]
|
|
260
|
+
mode: taint
|
|
261
|
+
severity: ERROR
|
|
262
|
+
message: >-
|
|
263
|
+
Request data chooses the address of an outbound request the server makes (CWE-918). Allow only http and https,
|
|
264
|
+
resolve the host, refuse private, loopback, link local and metadata addresses, dial the checked address and
|
|
265
|
+
check every redirect. A value that only fills a path or query under a fixed host is not matched.
|
|
266
|
+
metadata:
|
|
267
|
+
cwe: "CWE-918: Server-Side Request Forgery (SSRF)"
|
|
268
|
+
sec_ids: [SEC-API-035]
|
|
269
|
+
pattern-sources:
|
|
270
|
+
- patterns:
|
|
271
|
+
- pattern: '($R : *http.Request).$M(...)'
|
|
272
|
+
- metavariable-regex:
|
|
273
|
+
metavariable: $M
|
|
274
|
+
regex: ^(FormValue|PostFormValue|Cookie|Cookies|FormFile|MultipartReader|Referer|UserAgent)$
|
|
275
|
+
- patterns:
|
|
276
|
+
- pattern: '($R : *http.Request).$F'
|
|
277
|
+
- metavariable-regex:
|
|
278
|
+
metavariable: $F
|
|
279
|
+
regex: ^(URL|Form|PostForm|MultipartForm|Header|Body|RequestURI|Host)$
|
|
280
|
+
- pattern: mux.Vars(...)
|
|
281
|
+
- pattern: chi.URLParam(...)
|
|
282
|
+
- patterns:
|
|
283
|
+
- pattern-either:
|
|
284
|
+
- pattern: '($C : *gin.Context).$G(...)'
|
|
285
|
+
- pattern: '($C : echo.Context).$G(...)'
|
|
286
|
+
- metavariable-regex:
|
|
287
|
+
metavariable: $G
|
|
288
|
+
regex: ^(Query|DefaultQuery|QueryArray|QueryMap|GetQuery|Param|Params|PostForm|DefaultPostForm|PostFormArray|GetPostForm|GetHeader|Cookie|FormValue|QueryParam|QueryParams|FormParams|GetRawData|FormFile|ShouldBind|ShouldBindJSON|ShouldBindQuery|Bind|BindJSON)$
|
|
289
|
+
pattern-sanitizers:
|
|
290
|
+
- pattern-either:
|
|
291
|
+
- pattern: strconv.Atoi(...)
|
|
292
|
+
- pattern: strconv.ParseInt(...)
|
|
293
|
+
- pattern: strconv.ParseUint(...)
|
|
294
|
+
- pattern: strconv.ParseFloat(...)
|
|
295
|
+
- pattern: strconv.ParseBool(...)
|
|
296
|
+
- pattern: uuid.Parse(...)
|
|
297
|
+
|
|
298
|
+
- pattern-either:
|
|
299
|
+
- pattern: url.QueryEscape(...)
|
|
300
|
+
- pattern: url.PathEscape(...)
|
|
301
|
+
- patterns:
|
|
302
|
+
- pattern: '"$URL" + $Y'
|
|
303
|
+
- metavariable-regex:
|
|
304
|
+
metavariable: $URL
|
|
305
|
+
regex: ^https?://[^/]+/
|
|
306
|
+
- patterns:
|
|
307
|
+
- pattern: fmt.Sprintf("$URL", ...)
|
|
308
|
+
- metavariable-regex:
|
|
309
|
+
metavariable: $URL
|
|
310
|
+
regex: ^https?://[^/%]+/
|
|
311
|
+
|
|
312
|
+
- by-side-effect: true
|
|
313
|
+
patterns:
|
|
314
|
+
- pattern: $GUARD($X, ...)
|
|
315
|
+
- metavariable-regex:
|
|
316
|
+
metavariable: $GUARD
|
|
317
|
+
regex: (?i)^(.*\.)?\w*(safe|allow|valid|guard|check|verify)\w*$
|
|
318
|
+
- focus-metavariable: $X
|
|
319
|
+
pattern-sinks:
|
|
320
|
+
- patterns:
|
|
321
|
+
- pattern-either:
|
|
322
|
+
- pattern: http.Get($X)
|
|
323
|
+
- pattern: http.Head($X)
|
|
324
|
+
- pattern: http.Post($X, ...)
|
|
325
|
+
- pattern: http.PostForm($X, ...)
|
|
326
|
+
- pattern: http.NewRequest($M, $X, ...)
|
|
327
|
+
- pattern: http.NewRequestWithContext($CTX, $M, $X, ...)
|
|
328
|
+
- pattern: '($CL : *http.Client).Get($X)'
|
|
329
|
+
- pattern: '($CL : *http.Client).Head($X)'
|
|
330
|
+
- pattern: '($CL : *http.Client).Post($X, ...)'
|
|
331
|
+
- pattern: net.Dial($N, $X)
|
|
332
|
+
- pattern: net.DialTimeout($N, $X, ...)
|
|
333
|
+
- focus-metavariable: $X
|