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,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"id": "rust",
|
|
4
|
+
"name": "Rust",
|
|
5
|
+
"summary": "Cargo.toml (dependency sources, release profile, lockfile) and axum and actix web routes with the layers and extractors that protect them. Handler bodies are not read.",
|
|
6
|
+
"edition": "free",
|
|
7
|
+
"languages": [
|
|
8
|
+
"rust"
|
|
9
|
+
],
|
|
10
|
+
"frameworks": [
|
|
11
|
+
"axum",
|
|
12
|
+
"actix-web"
|
|
13
|
+
],
|
|
14
|
+
"level": "L2",
|
|
15
|
+
"limits": [
|
|
16
|
+
"Handler bodies are not read, so data store and outbound call checks stay silent for Rust."
|
|
17
|
+
],
|
|
18
|
+
"parts": {
|
|
19
|
+
"detectors": [
|
|
20
|
+
"rust",
|
|
21
|
+
"axum",
|
|
22
|
+
"actix-web"
|
|
23
|
+
],
|
|
24
|
+
"extractors": [
|
|
25
|
+
{
|
|
26
|
+
"file": "src/map/rust.ts"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"auth_patterns": [
|
|
30
|
+
{
|
|
31
|
+
"file": "src/map/rust.ts"
|
|
32
|
+
}
|
|
33
|
+
],
|
|
34
|
+
"checks": [
|
|
35
|
+
{
|
|
36
|
+
"id": "check.map.admin-route-without-role"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "check.map.mutating-route-without-auth"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "check.map.webhook-verify-before-use"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"id": "check.map.data-read-without-auth"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "check.map.read-by-id-without-owner"
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"mapping": [
|
|
52
|
+
{
|
|
53
|
+
"file": "src/checks/map/config-checks.ts"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"file": "src/checks/map/entry-checks.ts"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"fixture": {
|
|
61
|
+
"dir": "test/fixtures/packs/rust/fail",
|
|
62
|
+
"fixed_dir": "test/fixtures/packs/rust/pass",
|
|
63
|
+
"internal": true,
|
|
64
|
+
"answer_keys": [
|
|
65
|
+
"outside_repo"
|
|
66
|
+
],
|
|
67
|
+
"result": "packs/rust/fixture-result.json"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"detect": {
|
|
3
|
+
"expected": [
|
|
4
|
+
"java",
|
|
5
|
+
"spring-boot"
|
|
6
|
+
],
|
|
7
|
+
"found": [
|
|
8
|
+
"java",
|
|
9
|
+
"spring",
|
|
10
|
+
"spring-boot",
|
|
11
|
+
"spring-security"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"engine": "0.5.0",
|
|
15
|
+
"measured": "2026-10-14",
|
|
16
|
+
"measurements": [
|
|
17
|
+
{
|
|
18
|
+
"blind_key": true,
|
|
19
|
+
"flaws": {
|
|
20
|
+
"false_findings": 0,
|
|
21
|
+
"found": 7,
|
|
22
|
+
"planted": 7
|
|
23
|
+
},
|
|
24
|
+
"kind": "synthetic",
|
|
25
|
+
"mapped": {
|
|
26
|
+
"expected": 12,
|
|
27
|
+
"extra": 0,
|
|
28
|
+
"matched": 12,
|
|
29
|
+
"what": "entry points"
|
|
30
|
+
},
|
|
31
|
+
"name": "test/fixtures/packs/spring/fail and test/fixtures/packs/spring/pass",
|
|
32
|
+
"source": "node bench/packs-measure.ts spring (key kept outside the repository)",
|
|
33
|
+
"stability": {
|
|
34
|
+
"identical": true,
|
|
35
|
+
"runs": 3
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"blind_key": true,
|
|
40
|
+
"flaws": null,
|
|
41
|
+
"kind": "third_party",
|
|
42
|
+
"mapped": {
|
|
43
|
+
"expected": 25,
|
|
44
|
+
"extra": 0,
|
|
45
|
+
"matched": 25,
|
|
46
|
+
"what": "entry points (real route registrations)"
|
|
47
|
+
},
|
|
48
|
+
"name": "WebGoat/WebGoat (seeded sample of its route registrations)",
|
|
49
|
+
"source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
|
|
50
|
+
"stability": {
|
|
51
|
+
"identical": true,
|
|
52
|
+
"runs": 3
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
],
|
|
56
|
+
"notes": [
|
|
57
|
+
"Spring Boot 3 with Spring Security 6: seven planted flaws and a fixed copy. Written before the Spring extractor existed.",
|
|
58
|
+
"2026-10-14: the first flaw also accepts check.map.read-by-id-without-owner, which was built in step 6c after these fixtures missed the flaw."
|
|
59
|
+
],
|
|
60
|
+
"pack": "spring",
|
|
61
|
+
"proof": [],
|
|
62
|
+
"schema": 1
|
|
63
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"id": "spring",
|
|
4
|
+
"name": "Java and Spring",
|
|
5
|
+
"summary": "Spring MVC controllers with method security annotations and the Spring Security filter chain: entry points, protections, taint rules and checks.",
|
|
6
|
+
"edition": "free",
|
|
7
|
+
"languages": [
|
|
8
|
+
"java"
|
|
9
|
+
],
|
|
10
|
+
"frameworks": [
|
|
11
|
+
"spring",
|
|
12
|
+
"spring-boot"
|
|
13
|
+
],
|
|
14
|
+
"level": "L2",
|
|
15
|
+
"limits": [
|
|
16
|
+
"Routes built in code (RouterFunction) and Kotlin Spring apps are not read. Planted flaws were not measured on a real application."
|
|
17
|
+
],
|
|
18
|
+
"parts": {
|
|
19
|
+
"detectors": [
|
|
20
|
+
"java",
|
|
21
|
+
"spring",
|
|
22
|
+
"spring-boot"
|
|
23
|
+
],
|
|
24
|
+
"extractors": [
|
|
25
|
+
{
|
|
26
|
+
"file": "src/map/spring.ts"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"file": "src/map/cblocks.ts"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"auth_patterns": [
|
|
33
|
+
{
|
|
34
|
+
"file": "src/map/light-profiles.ts"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"sources_sinks": [
|
|
38
|
+
{
|
|
39
|
+
"file": "rules/semgrep/taint-java.yaml"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"rules": [
|
|
43
|
+
{
|
|
44
|
+
"file": "rules/semgrep/taint-java.yaml",
|
|
45
|
+
"tests": [
|
|
46
|
+
"test/fixtures/rules/taint-java.java"
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"checks": [
|
|
51
|
+
{
|
|
52
|
+
"id": "check.map.admin-route-without-role"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"id": "check.map.data-read-without-auth"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "check.map.mutating-route-without-auth"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "check.map.privileged-action-without-audit"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "check.map.privileged-field-from-request"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "check.map.redirect-from-request"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "check.map.request-url-fetched"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "check.map.webhook-verify-before-use"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "check.map.write-by-id-without-owner"
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"id": "check.map.read-by-id-without-owner"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "check.authz.owner-filter-on-id-read"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"id": "check.authz.admin-role-check"
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"mapping": [
|
|
89
|
+
{
|
|
90
|
+
"file": "src/checks/map/entry-checks.ts"
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
},
|
|
94
|
+
"fixture": {
|
|
95
|
+
"dir": "test/fixtures/packs/spring/fail",
|
|
96
|
+
"fixed_dir": "test/fixtures/packs/spring/pass",
|
|
97
|
+
"internal": true,
|
|
98
|
+
"answer_keys": [
|
|
99
|
+
"outside_repo"
|
|
100
|
+
],
|
|
101
|
+
"result": "packs/spring/fixture-result.json"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"pack": "supabase",
|
|
3
|
+
"fail_dir": "test/fixtures/map/fail",
|
|
4
|
+
"pass_dir": "test/fixtures/map/pass",
|
|
5
|
+
"stacks": [
|
|
6
|
+
"supabase"
|
|
7
|
+
],
|
|
8
|
+
"detect_expected": [
|
|
9
|
+
"supabase"
|
|
10
|
+
],
|
|
11
|
+
"mapped_what": "tables",
|
|
12
|
+
"mapped": [
|
|
13
|
+
"table docs rls=true policies=2 grants=0",
|
|
14
|
+
"table notes rls=null policies=0 grants=1",
|
|
15
|
+
"table profiles rls=true policies=1 grants=1"
|
|
16
|
+
],
|
|
17
|
+
"flaws": [
|
|
18
|
+
{
|
|
19
|
+
"check": "supabase-open-table",
|
|
20
|
+
"stack": "supabase"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"check": "supabase-privileged-column-grant",
|
|
24
|
+
"stack": "supabase"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"check": "supabase-policy-trusts-claims",
|
|
28
|
+
"stack": "supabase"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"recorded": [
|
|
32
|
+
{
|
|
33
|
+
"name": "hullproof-demo (whole app)",
|
|
34
|
+
"kind": "demo",
|
|
35
|
+
"blind_key": true,
|
|
36
|
+
"source": "bench/PHASE2-MEASURED-2026-10-11.md sections 2.1 and 2.2 (open core rules, new checks as leads), key from the Pro repository, the whole demo app, which includes flaws in Supabase configuration, infrastructure files and CI as well as in application code, so this recall belongs to the engine on this app and not to this pack alone",
|
|
37
|
+
"mapped": null,
|
|
38
|
+
"flaws": {
|
|
39
|
+
"planted": 30,
|
|
40
|
+
"found": 20,
|
|
41
|
+
"false_findings": 0
|
|
42
|
+
},
|
|
43
|
+
"stability": {
|
|
44
|
+
"runs": 3,
|
|
45
|
+
"identical": true
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"notes": [
|
|
50
|
+
"The blind measurement is the whole demo app (a Next.js app on Supabase), see the measurement source. Hosted, so never L4."
|
|
51
|
+
]
|
|
52
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"detect": {
|
|
3
|
+
"expected": [
|
|
4
|
+
"supabase"
|
|
5
|
+
],
|
|
6
|
+
"found": [
|
|
7
|
+
"sql",
|
|
8
|
+
"supabase"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
"engine": "0.5.0",
|
|
12
|
+
"measured": "2026-10-14",
|
|
13
|
+
"measurements": [
|
|
14
|
+
{
|
|
15
|
+
"blind_key": false,
|
|
16
|
+
"flaws": {
|
|
17
|
+
"false_findings": 0,
|
|
18
|
+
"found": 3,
|
|
19
|
+
"planted": 3
|
|
20
|
+
},
|
|
21
|
+
"kind": "synthetic",
|
|
22
|
+
"mapped": {
|
|
23
|
+
"expected": 3,
|
|
24
|
+
"extra": 0,
|
|
25
|
+
"matched": 3,
|
|
26
|
+
"what": "tables"
|
|
27
|
+
},
|
|
28
|
+
"name": "test/fixtures/map/fail and test/fixtures/map/pass",
|
|
29
|
+
"source": "node bench/packs-measure.ts supabase (key packs/supabase/answer-key.json)",
|
|
30
|
+
"stability": {
|
|
31
|
+
"identical": true,
|
|
32
|
+
"runs": 3
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"blind_key": true,
|
|
37
|
+
"flaws": {
|
|
38
|
+
"false_findings": 0,
|
|
39
|
+
"found": 20,
|
|
40
|
+
"planted": 30
|
|
41
|
+
},
|
|
42
|
+
"kind": "demo",
|
|
43
|
+
"mapped": null,
|
|
44
|
+
"name": "hullproof-demo (whole app)",
|
|
45
|
+
"source": "bench/PHASE2-MEASURED-2026-10-11.md sections 2.1 and 2.2 (open core rules, new checks as leads), key from the Pro repository, the whole demo app, which includes flaws in Supabase configuration, infrastructure files and CI as well as in application code, so this recall belongs to the engine on this app and not to this pack alone",
|
|
46
|
+
"stability": {
|
|
47
|
+
"identical": true,
|
|
48
|
+
"runs": 3
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"notes": [
|
|
53
|
+
"The blind measurement is the whole demo app (a Next.js app on Supabase), see the measurement source. Hosted, so never L4."
|
|
54
|
+
],
|
|
55
|
+
"pack": "supabase",
|
|
56
|
+
"proof": [],
|
|
57
|
+
"schema": 1
|
|
58
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"id": "supabase",
|
|
4
|
+
"name": "Supabase",
|
|
5
|
+
"summary": "Tables, grants and row level security policies read from migration files, with checks for open tables, privileged column grants and policies that trust user metadata.",
|
|
6
|
+
"edition": "free",
|
|
7
|
+
"languages": [
|
|
8
|
+
"sql"
|
|
9
|
+
],
|
|
10
|
+
"frameworks": [
|
|
11
|
+
"supabase"
|
|
12
|
+
],
|
|
13
|
+
"level": "L3",
|
|
14
|
+
"limits": [
|
|
15
|
+
"Policies and grants are read from migration files, not from a live database."
|
|
16
|
+
],
|
|
17
|
+
"parts": {
|
|
18
|
+
"detectors": [
|
|
19
|
+
"sql"
|
|
20
|
+
],
|
|
21
|
+
"extractors": [
|
|
22
|
+
{
|
|
23
|
+
"file": "src/map/config.ts"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"auth_patterns": [
|
|
27
|
+
{
|
|
28
|
+
"file": "src/map/config.ts"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"rules": [],
|
|
32
|
+
"checks": [
|
|
33
|
+
{
|
|
34
|
+
"id": "check.map.supabase-open-table"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "check.map.supabase-privileged-column-grant"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"id": "check.map.supabase-policy-trusts-claims"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "check.db.rls-every-table"
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"mapping": [
|
|
47
|
+
{
|
|
48
|
+
"file": "src/checks/map/config-checks.ts"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"fixture": {
|
|
53
|
+
"dir": "test/fixtures/map/fail",
|
|
54
|
+
"fixed_dir": "test/fixtures/map/pass",
|
|
55
|
+
"answer_keys": [
|
|
56
|
+
"in_repo"
|
|
57
|
+
],
|
|
58
|
+
"result": "packs/supabase/fixture-result.json"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright 2026 Rare Phronesis Limited
|
|
3
|
+
# Copied from the Hullproof kit (kit/tools/hullproof/gitleaks.toml).
|
|
4
|
+
#
|
|
5
|
+
# Hullproof gitleaks config.
|
|
6
|
+
#
|
|
7
|
+
# Use it for every scan that produces evidence, with this file and not the repository's own:
|
|
8
|
+
#
|
|
9
|
+
# gitleaks dir . --redact --no-banner --config tools/hullproof/gitleaks.toml --ignore-gitleaks-allow
|
|
10
|
+
# gitleaks git . --redact --no-banner --config tools/hullproof/gitleaks.toml --ignore-gitleaks-allow
|
|
11
|
+
#
|
|
12
|
+
# Gitleaks reads ".gitleaks.toml" from the scanned folder when no --config is given, and a repository can use
|
|
13
|
+
# that file (or "gitleaks:allow" comments) to hide its own findings. Passing --config and
|
|
14
|
+
# --ignore-gitleaks-allow stops both. A scan that does not name this file is not Hullproof evidence.
|
|
15
|
+
#
|
|
16
|
+
# This file extends the default rules and adds the secret shapes of the default stack that the default
|
|
17
|
+
# rules do not find. It has NO path allowlist for build output. Folders such as .next, dist, build and
|
|
18
|
+
# .vercel are scanned on purpose, because that is where a secret ends up in the shipped bundle
|
|
19
|
+
# (SEC-SECRETS-001). The only path exclusion is node_modules, which holds third party code.
|
|
20
|
+
#
|
|
21
|
+
# If a scan ends with "scanned ~0 bytes" it scanned nothing. Treat that as NOT ASSESSED.
|
|
22
|
+
#
|
|
23
|
+
# Shape sources. "docs" means the vendor's own documentation states the shape. "lenient" means the prefix is
|
|
24
|
+
# known and the length is a loose range, because no length was verified. "context" means the value has no
|
|
25
|
+
# shape, so the rule needs a nearby name. The tests in tools/hullproof/tests/test_gitleaks_config.py plant
|
|
26
|
+
# one synthetic value per rule and fail if it is not found.
|
|
27
|
+
|
|
28
|
+
title = "Hullproof gitleaks config"
|
|
29
|
+
|
|
30
|
+
[extend]
|
|
31
|
+
useDefault = true
|
|
32
|
+
|
|
33
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
34
|
+
# Supabase
|
|
35
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
# A legacy service role key is a JWT whose payload holds "role":"service_role". The default jwt rule finds
|
|
38
|
+
# every JWT but cannot tell an anon key from a service role key. This rule matches the base64url text of
|
|
39
|
+
# the role claim at all three byte alignments (shape basis: the payload encoding).
|
|
40
|
+
[[rules]]
|
|
41
|
+
id = "hullproof-supabase-service-role-jwt"
|
|
42
|
+
description = "JWT with the service_role claim (bypasses row level security)"
|
|
43
|
+
regex = '''\b(eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]*(?:InJvbGUiOiJzZXJ2aWNlX3JvbGUi|Jyb2xlIjoic2VydmljZV9yb2xlI|icm9sZSI6InNlcnZpY2Vfcm9sZS)[A-Za-z0-9_-]*\.[A-Za-z0-9_-]{20,})'''
|
|
44
|
+
secretGroup = 1
|
|
45
|
+
keywords = ["eyj"]
|
|
46
|
+
tags = ["supabase", "jwt", "critical"]
|
|
47
|
+
|
|
48
|
+
# New style secret key. Supabase documents the form sb_secret_<random>_<checksum>. Publishable keys
|
|
49
|
+
# (sb_publishable_) are public by design and are never matched.
|
|
50
|
+
[[rules]]
|
|
51
|
+
id = "hullproof-supabase-secret-key"
|
|
52
|
+
description = "Supabase secret API key (sb_secret_)"
|
|
53
|
+
regex = '''\b(sb_secret_[A-Za-z0-9_-]{20,})'''
|
|
54
|
+
secretGroup = 1
|
|
55
|
+
keywords = ["sb_secret_"]
|
|
56
|
+
tags = ["supabase", "critical"]
|
|
57
|
+
|
|
58
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
59
|
+
# Payments
|
|
60
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
# Paddle API key. Shape from the Paddle developer docs:
|
|
63
|
+
# ^pdl_(live|sdbx)_apikey_[a-z\d]{26}_[a-zA-Z\d]{22}_[a-zA-Z\d]{3}$ (docs).
|
|
64
|
+
[[rules]]
|
|
65
|
+
id = "hullproof-paddle-api-key"
|
|
66
|
+
description = "Paddle API key (live or sandbox)"
|
|
67
|
+
regex = '''\b(pdl_(?:live|sdbx)_apikey_[a-z0-9]{26}_[A-Za-z0-9]{22}_[A-Za-z0-9]{3})\b'''
|
|
68
|
+
secretGroup = 1
|
|
69
|
+
keywords = ["pdl_"]
|
|
70
|
+
tags = ["paddle", "payments"]
|
|
71
|
+
|
|
72
|
+
# Paddle webhook signing secret for a notification destination, prefix pdl_ntfset_ (docs). Anyone who holds
|
|
73
|
+
# it can forge webhook calls.
|
|
74
|
+
[[rules]]
|
|
75
|
+
id = "hullproof-paddle-webhook-secret"
|
|
76
|
+
description = "Paddle notification destination secret key"
|
|
77
|
+
regex = '''\b(pdl_ntfset_[a-z0-9]{26}_[A-Za-z0-9]{20,})\b'''
|
|
78
|
+
secretGroup = 1
|
|
79
|
+
keywords = ["pdl_ntfset_"]
|
|
80
|
+
tags = ["paddle", "webhook"]
|
|
81
|
+
|
|
82
|
+
# Paystack secret keys use the sk_live_ / sk_test_ form with 40 hex characters. The default stripe rule
|
|
83
|
+
# already reports this shape (tested), so no separate rule is added here.
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
86
|
+
# Email, hosting, observability
|
|
87
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
# Resend key: prefix re_ (docs show re_xxxxxxxxx). Length is lenient. The shape is two alphanumeric runs
|
|
90
|
+
# joined by an underscore, which keeps snake case identifiers out. (lenient)
|
|
91
|
+
[[rules]]
|
|
92
|
+
id = "hullproof-resend-api-key"
|
|
93
|
+
description = "Resend API key"
|
|
94
|
+
regex = '''\b(re_[A-Za-z0-9]{6,12}_[A-Za-z0-9]{20,40})\b'''
|
|
95
|
+
secretGroup = 1
|
|
96
|
+
entropy = 3.0
|
|
97
|
+
keywords = ["re_"]
|
|
98
|
+
tags = ["resend", "email"]
|
|
99
|
+
|
|
100
|
+
# Render API key: prefix rnd_ followed by an alphanumeric run. (lenient, length not verified)
|
|
101
|
+
[[rules]]
|
|
102
|
+
id = "hullproof-render-api-key"
|
|
103
|
+
description = "Render API key"
|
|
104
|
+
regex = '''\b(rnd_[A-Za-z0-9]{28,40})\b'''
|
|
105
|
+
secretGroup = 1
|
|
106
|
+
entropy = 3.0
|
|
107
|
+
keywords = ["rnd_"]
|
|
108
|
+
tags = ["render"]
|
|
109
|
+
|
|
110
|
+
# PostHog personal API key (phx_) and project secret API key (phs_), both listed by PostHog as secrets.
|
|
111
|
+
# The project token (phc_) is for browsers and is not matched. (prefix: docs, length lenient)
|
|
112
|
+
[[rules]]
|
|
113
|
+
id = "hullproof-posthog-secret-key"
|
|
114
|
+
description = "PostHog personal or project secret API key"
|
|
115
|
+
regex = '''\b(ph[xs]_[A-Za-z0-9]{30,64})\b'''
|
|
116
|
+
secretGroup = 1
|
|
117
|
+
entropy = 3.0
|
|
118
|
+
keywords = ["phx_", "phs_"]
|
|
119
|
+
tags = ["posthog"]
|
|
120
|
+
|
|
121
|
+
# Sentry organization auth token (sntrys_). The user token (sntryu_) is covered by a default rule (tested).
|
|
122
|
+
# A DSN is not a secret and is not matched. (prefix: Sentry docs and scanner issue reports, length lenient)
|
|
123
|
+
[[rules]]
|
|
124
|
+
id = "hullproof-sentry-org-auth-token"
|
|
125
|
+
description = "Sentry organization auth token"
|
|
126
|
+
regex = '''\b(sntrys_[A-Za-z0-9+/=_-]{60,})'''
|
|
127
|
+
secretGroup = 1
|
|
128
|
+
keywords = ["sntrys_"]
|
|
129
|
+
tags = ["sentry"]
|
|
130
|
+
|
|
131
|
+
# OpenAI project, service account and admin keys. The default rule requires an embedded marker string that
|
|
132
|
+
# newer keys may not carry, so this rule matches the documented prefix and a long body. (prefix: lenient,
|
|
133
|
+
# length not verified)
|
|
134
|
+
[[rules]]
|
|
135
|
+
id = "hullproof-openai-project-key"
|
|
136
|
+
description = "OpenAI project, service account or admin API key"
|
|
137
|
+
regex = '''\b(sk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{40,})'''
|
|
138
|
+
secretGroup = 1
|
|
139
|
+
entropy = 3.5
|
|
140
|
+
keywords = ["sk-proj-", "sk-svcacct-", "sk-admin-"]
|
|
141
|
+
tags = ["openai", "ai"]
|
|
142
|
+
|
|
143
|
+
# Anthropic (sk-ant-) and Google API keys (AIza) are found by default rules (tested), so no extra rule is added.
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
146
|
+
# Storage and cache. These values have no prefix, so the rules need a nearby name. A bare value in a
|
|
147
|
+
# minified bundle cannot be found by shape. Use the planted value check in recipes.md for those.
|
|
148
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
149
|
+
|
|
150
|
+
# Cloudflare R2 secret access key: 64 hex characters, next to a name that mentions r2, cloudflare or s3 and
|
|
151
|
+
# secret. (context)
|
|
152
|
+
[[rules]]
|
|
153
|
+
id = "hullproof-r2-secret-access-key"
|
|
154
|
+
description = "Cloudflare R2 or S3 compatible secret access key (64 hex)"
|
|
155
|
+
regex = '''(?i)(?:r2|cloudflare|s3)[\w.-]{0,30}secret[\w.-]{0,20}["'\s:=]{1,6}["']?([a-f0-9]{64})\b'''
|
|
156
|
+
secretGroup = 1
|
|
157
|
+
keywords = ["r2", "cloudflare", "s3"]
|
|
158
|
+
tags = ["cloudflare", "r2"]
|
|
159
|
+
|
|
160
|
+
# Upstash REST token or Redis password next to an upstash name. (context)
|
|
161
|
+
[[rules]]
|
|
162
|
+
id = "hullproof-upstash-token"
|
|
163
|
+
description = "Upstash REST token or password"
|
|
164
|
+
regex = '''(?i)upstash[\w.-]{0,40}(?:token|password|passwd)[\w.-]{0,10}["'\s:=]{1,6}["']?([A-Za-z0-9=_-]{30,})'''
|
|
165
|
+
secretGroup = 1
|
|
166
|
+
entropy = 3.5
|
|
167
|
+
keywords = ["upstash"]
|
|
168
|
+
tags = ["upstash"]
|
|
169
|
+
|
|
170
|
+
# Vercel token next to a vercel name. (context)
|
|
171
|
+
[[rules]]
|
|
172
|
+
id = "hullproof-vercel-token"
|
|
173
|
+
description = "Vercel token next to a vercel name"
|
|
174
|
+
regex = '''(?i)vercel[\w.-]{0,20}(?:token|secret)[\w.-]{0,10}["'\s:=]{1,6}["']?([A-Za-z0-9_-]{24,})'''
|
|
175
|
+
secretGroup = 1
|
|
176
|
+
entropy = 3.5
|
|
177
|
+
keywords = ["vercel"]
|
|
178
|
+
tags = ["vercel"]
|
|
179
|
+
|
|
180
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
181
|
+
# Connection strings and agent config
|
|
182
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
# scheme://user:password@host. Covers Postgres, MySQL, MongoDB, Redis (also Upstash), AMQP and SQL Server.
|
|
185
|
+
# Placeholder passwords are skipped by the rule's own allowlist below.
|
|
186
|
+
[[rules]]
|
|
187
|
+
id = "hullproof-url-with-password"
|
|
188
|
+
description = "Connection URL with a password in the user info part"
|
|
189
|
+
regex = '''(?i)\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|rediss?|amqps?|mssql|sqlserver)://[^\s:@/'"`<>{}$]{1,64}:([^\s@/'"`<>]{3,128})@[A-Za-z0-9.\[\]-]{2,}'''
|
|
190
|
+
secretGroup = 1
|
|
191
|
+
keywords = ["://"]
|
|
192
|
+
tags = ["database", "url"]
|
|
193
|
+
|
|
194
|
+
[[rules.allowlists]]
|
|
195
|
+
description = "Placeholder passwords in examples"
|
|
196
|
+
regexTarget = "secret"
|
|
197
|
+
regexes = [
|
|
198
|
+
'''(?i)^(?:password|passwd|pass|pwd|secret|changeme|change-me|your[-_ ]?password|\[your[-_ ]?password\]|postgres|root|admin|user|xxx+|\*+|\.{3}|%s|\$\{?\w+\}?|\{\{.*\}\})$''',
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
# AWS access key id in a coding agent or MCP config file. The default AWS rule needs the base32 alphabet;
|
|
202
|
+
# this one accepts any uppercase letter or digit after the prefix, and only in agent config paths, where a
|
|
203
|
+
# key does not belong.
|
|
204
|
+
[[rules]]
|
|
205
|
+
id = "hullproof-aws-key-in-agent-config"
|
|
206
|
+
description = "AWS access key id in an MCP or agent settings file"
|
|
207
|
+
path = '''(?i)(^|/)(\.mcp\.json|mcp\.json|\.claude/settings(\.local)?\.json|claude_desktop_config\.json|\.cursor/mcp\.json|\.vscode/mcp\.json|\.windsurf/mcp_config\.json)$'''
|
|
208
|
+
regex = '''\b((?:AKIA|ASIA|AGPA|AIDA|AROA|ANPA|AIPA)[A-Z0-9]{16})\b'''
|
|
209
|
+
secretGroup = 1
|
|
210
|
+
keywords = ["akia", "asia", "agpa", "aida", "aroa", "anpa", "aipa"]
|
|
211
|
+
tags = ["aws", "agent"]
|
|
212
|
+
|
|
213
|
+
# Any literal secret looking value in an MCP or agent settings file. Values that read from the environment
|
|
214
|
+
# (${VAR}) are skipped by the character class.
|
|
215
|
+
[[rules]]
|
|
216
|
+
id = "hullproof-agent-config-literal-secret"
|
|
217
|
+
description = "Literal key, token, secret or password value in an MCP or agent settings file"
|
|
218
|
+
path = '''(?i)(^|/)(\.mcp\.json|mcp\.json|\.claude/settings(\.local)?\.json|claude_desktop_config\.json|\.cursor/mcp\.json|\.vscode/mcp\.json|\.windsurf/mcp_config\.json)$'''
|
|
219
|
+
regex = '''(?i)"[\w.-]*(?:key|token|secret|password|passwd|credential)[\w.-]*"\s*:\s*"([^"$\s]{16,})"'''
|
|
220
|
+
secretGroup = 1
|
|
221
|
+
entropy = 3.0
|
|
222
|
+
keywords = ["key", "token", "secret", "password", "passwd", "credential"]
|
|
223
|
+
tags = ["agent", "mcp"]
|
|
224
|
+
|
|
225
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
226
|
+
# Allowlists. Narrow on purpose. Nothing here excludes a folder that ships.
|
|
227
|
+
# ---------------------------------------------------------------------------------------------------------
|
|
228
|
+
|
|
229
|
+
[[allowlists]]
|
|
230
|
+
description = "Third party code that is not committed source"
|
|
231
|
+
paths = ['''(^|/)node_modules/''']
|
|
232
|
+
|
|
233
|
+
# Supabase anon JWT. The default jwt rule reports every JWT. A JWT is allowed only when its payload holds
|
|
234
|
+
# "role":"anon" (the public client key). It applies to the default jwt rule only, so the service_role
|
|
235
|
+
# rule above is never affected. The three strings are the base64url text of "role":"anon" at each byte
|
|
236
|
+
# alignment.
|
|
237
|
+
[[allowlists]]
|
|
238
|
+
description = "Supabase anon key (public by design)"
|
|
239
|
+
targetRules = ["jwt"]
|
|
240
|
+
regexTarget = "secret"
|
|
241
|
+
regexes = [
|
|
242
|
+
'''^eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]*(?:InJvbGUiOiJhbm9uI|Jyb2xlIjoiYW5vbi|icm9sZSI6ImFub24i)[A-Za-z0-9_-]*\.[A-Za-z0-9_-]+$''',
|
|
243
|
+
]
|
|
244
|
+
|
|
245
|
+
# Supabase publishable key. Public by design.
|
|
246
|
+
[[allowlists]]
|
|
247
|
+
description = "Supabase publishable key (public by design)"
|
|
248
|
+
regexTarget = "secret"
|
|
249
|
+
regexes = ['''^sb_publishable_[A-Za-z0-9_-]{20,}$''']
|
|
250
|
+
|
|
251
|
+
# The kit's own documents quote example text that the generic rule can match. Only the generic rule is
|
|
252
|
+
# excluded, and only for the kit's markdown. Every other rule still applies to these files.
|
|
253
|
+
[[allowlists]]
|
|
254
|
+
description = "Kit documentation examples (generic rule only)"
|
|
255
|
+
targetRules = ["generic-api-key"]
|
|
256
|
+
paths = ['''(^|/)docs/hullproof/(templates/)?[^/]+\.md$''']
|