torusguard 1.3.3 → 1.3.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/.torusguard/.manifest.json +66 -63
- package/.torusguard/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +30 -14
- package/.torusguard/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +33 -16
- package/.torusguard/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +31 -15
- package/.torusguard/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +26 -16
- package/.torusguard/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +24 -16
- package/.torusguard/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +32 -18
- package/.torusguard/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +24 -17
- package/.torusguard/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +31 -18
- package/.torusguard/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +28 -17
- package/.torusguard/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +33 -17
- package/.torusguard/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +31 -16
- package/.torusguard/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +25 -16
- package/.torusguard/rules/secrets/TG-SEC-005-secret-in-git-history.md +24 -19
- package/.torusguard/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +36 -19
- package/.torusguard/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +21 -16
- package/.torusguard/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +45 -18
- package/.torusguard/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +20 -16
- package/.torusguard/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +28 -19
- package/.torusguard/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +25 -18
- package/.torusguard/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +29 -19
- package/.torusguard/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +23 -18
- package/.torusguard/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +23 -18
- package/.torusguard/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +36 -16
- package/.torusguard/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +26 -17
- package/.torusguard/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +30 -16
- package/.torusguard/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +25 -16
- package/.torusguard/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +28 -17
- package/.torusguard/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +31 -17
- package/.torusguard/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +31 -17
- package/.torusguard/rules_catalog.json +520 -0
- package/.torusguard/runs/report-latest.html +93 -7
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-256-c8a22e/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-256-c8a22e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-002-256-c8a22e/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-platform-001-183-47fd5e/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-platform-001-183-47fd5e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-platform-001-183-47fd5e/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260910-120238-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
- package/.torusguard/runs/run-20260910-120238-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260910-120238-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260910-120238-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260910-120238-audit/recheck.md +86 -0
- package/.torusguard/runs/run-20260910-120238-audit/remediation.md +262 -0
- package/.torusguard/runs/run-20260910-120238-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260910-121238-audit/findings.json +794 -0
- package/.torusguard/runs/run-20260910-121238-audit/findings.md +344 -0
- package/.torusguard/runs/run-20260910-121238-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260910-121238-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260910-130454-audit/findings.json +893 -0
- package/.torusguard/runs/run-20260910-130454-audit/findings.md +386 -0
- package/.torusguard/runs/run-20260910-130454-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260910-130454-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260910-130519-audit/findings.json +563 -0
- package/.torusguard/runs/run-20260910-130519-audit/findings.md +246 -0
- package/.torusguard/runs/run-20260910-130519-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260910-130519-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-214110-audit/findings.json +1256 -0
- package/.torusguard/runs/run-20260912-214110-audit/findings.md +534 -0
- package/.torusguard/runs/run-20260912-214110-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260912-214110-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-214813-audit/findings.json +992 -0
- package/.torusguard/runs/run-20260912-214813-audit/findings.md +422 -0
- package/.torusguard/runs/run-20260912-214813-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260912-214813-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-auth-003-49-7c96f3/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-auth-003-49-7c96f3/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-auth-003-49-7c96f3/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-platform-001-12-cf8156/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-platform-001-12-cf8156/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-platform-001-12-cf8156/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-rate-001-26-affcfa/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-rate-001-26-affcfa/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-rate-001-26-affcfa/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-sec-001-9-e22e50/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-sec-001-9-e22e50/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-sec-001-9-e22e50/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-ssrf-004-9-9803ad/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-ssrf-004-9-9803ad/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-ssrf-004-9-9803ad/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215555-audit/findings.json +530 -0
- package/.torusguard/runs/run-20260912-215555-audit/findings.md +232 -0
- package/.torusguard/runs/run-20260912-215555-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260912-215555-audit/remediation.md +102 -0
- package/.torusguard/runs/run-20260912-215555-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-215731-audit/apply_plan.md +6 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-client-001-7-587129/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-client-001-7-587129/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-client-001-7-587129/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-db-002-9-5f7850/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-db-002-9-5f7850/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-db-002-9-5f7850/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-input-001-27-2486f1/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-input-001-27-2486f1/minimal_patch_plan.md +22 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-input-001-27-2486f1/patch.diff +10 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-001-12-cf8156/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-001-12-cf8156/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-001-12-cf8156/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-17-876973/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-17-876973/minimal_patch_plan.md +23 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-17-876973/patch.diff +11 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-5-40c794/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-5-40c794/minimal_patch_plan.md +23 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-5-40c794/patch.diff +11 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-001-26-affcfa/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-001-26-affcfa/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-001-26-affcfa/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-002-54-0b38d2/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-002-54-0b38d2/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-002-54-0b38d2/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-18-a3c1e8/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-18-a3c1e8/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-18-a3c1e8/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-9-e22e50/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-9-e22e50/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-9-e22e50/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-28-a1a0a1/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-28-a1a0a1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-28-a1a0a1/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-30-00569e/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-30-00569e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-30-00569e/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-ssrf-004-9-9803ad/metadata.json +17 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-ssrf-004-9-9803ad/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-ssrf-004-9-9803ad/patch.diff +9 -0
- package/.torusguard/runs/run-20260912-215731-audit/diff_summary.md +186 -0
- package/.torusguard/runs/run-20260912-215731-audit/findings.json +497 -0
- package/.torusguard/runs/run-20260912-215731-audit/findings.md +218 -0
- package/.torusguard/runs/run-20260912-215731-audit/manifest.json +14 -0
- package/.torusguard/runs/run-20260912-215731-audit/recheck.md +76 -0
- package/.torusguard/runs/run-20260912-215731-audit/remediation.md +234 -0
- package/.torusguard/runs/run-20260912-215731-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-220134-audit/findings.json +68 -0
- package/.torusguard/runs/run-20260912-220134-audit/findings.md +36 -0
- package/.torusguard/runs/run-20260912-220134-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260912-220134-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-220200-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260912-220200-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260912-220200-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260912-220200-audit/recheck.md +6 -0
- package/.torusguard/runs/run-20260912-220200-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260912-220227-audit/findings.json +1 -0
- package/.torusguard/runs/run-20260912-220227-audit/findings.md +8 -0
- package/.torusguard/runs/run-20260912-220227-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260912-220227-audit/recheck.md +6 -0
- package/.torusguard/runs/run-20260912-220227-audit/summary.md +5 -0
- package/.torusguard/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/diff_guard.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/html_reporter.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/report_sync.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/rules_sync.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/term_ui.cpython-311.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +383 -339
- package/.torusguard/scripts/audit_runner.py +1306 -550
- package/.torusguard/scripts/finding_scorer.py +14 -2
- package/.torusguard/scripts/harden_runner.py +628 -375
- package/.torusguard/scripts/recheck_runner.py +248 -221
- package/.torusguard/scripts/recipes_runner.py +137 -130
- package/.torusguard/scripts/report_sync.py +423 -0
- package/.torusguard/scripts/sarif_exporter.py +116 -116
- package/.torusguard/scripts/term_ui.py +162 -0
- package/.torusguard/skills/torusguard/SKILL.md +61 -31
- package/.torusguard/skills/torusguard-apply/SKILL.md +80 -46
- package/.torusguard/skills/torusguard-audit/SKILL.md +83 -70
- package/.torusguard/skills/torusguard-authorize/SKILL.md +5 -4
- package/.torusguard/skills/torusguard-exploit-check/SKILL.md +6 -5
- package/.torusguard/skills/torusguard-full/SKILL.md +1 -1
- package/.torusguard/skills/torusguard-harden/SKILL.md +94 -63
- package/.torusguard/skills/torusguard-init/SKILL.md +64 -52
- package/.torusguard/skills/torusguard-recheck/SKILL.md +77 -53
- package/.torusguard/skills/torusguard-report/SKILL.md +72 -54
- package/.torusguard/skills/torusguard-status/SKILL.md +58 -42
- package/.torusguard/skills/torusguard-verify/SKILL.md +8 -7
- package/.torusguard/skills/torusguard-web-validate/SKILL.md +8 -7
- package/.torusguard/snapshots/run-20260912-215731-audit/demo/playground/vulnerable_nextjs/actions.ts.bak +24 -0
- package/.torusguard/snapshots/run-20260912-215731-audit/examples/hardened-react-express/server/index.js.bak +121 -0
- package/.torusguard/snapshots/run-20260912-215731-audit/examples/python/fastapi-vuln/main.py.bak +20 -0
- package/.torusguard/snapshots/run-20260912-215731-audit/examples/vulnerable-react-express/client/src/App.jsx.bak +63 -0
- package/.torusguard/snapshots/run-20260912-215731-audit/examples/vulnerable-react-express/client/vite.config.js.bak +12 -0
- package/.torusguard/snapshots/run-20260912-215731-audit/examples/vulnerable-react-express/server/index.js.bak +82 -0
- package/.torusguard/workflows/apply.md +11 -4
- package/.torusguard/workflows/audit.md +7 -1
- package/.torusguard/workflows/authorize.md +2 -1
- package/.torusguard/workflows/exploit-check.md +2 -1
- package/.torusguard/workflows/harden.md +7 -1
- package/.torusguard/workflows/init.md +6 -1
- package/.torusguard/workflows/memory.md +2 -1
- package/.torusguard/workflows/recheck.md +7 -1
- package/.torusguard/workflows/report.md +7 -1
- package/.torusguard/workflows/status.md +6 -1
- package/.torusguard/workflows/verify.md +6 -1
- package/.torusguard/workflows/web-validate.md +2 -1
- package/README.md +470 -344
- package/bin/torusguard.js +209 -97
- package/package.json +1 -1
- package/skills/torusguard/SKILL.md +73 -42
- package/skills/torusguard/payload/.manifest.json +66 -63
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +30 -14
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +33 -16
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +31 -15
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +26 -16
- package/skills/torusguard/payload/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +24 -16
- package/skills/torusguard/payload/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +32 -18
- package/skills/torusguard/payload/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +24 -17
- package/skills/torusguard/payload/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +31 -18
- package/skills/torusguard/payload/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +28 -17
- package/skills/torusguard/payload/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +33 -17
- package/skills/torusguard/payload/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +31 -16
- package/skills/torusguard/payload/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +25 -16
- package/skills/torusguard/payload/rules/secrets/TG-SEC-005-secret-in-git-history.md +24 -19
- package/skills/torusguard/payload/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +36 -19
- package/skills/torusguard/payload/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +21 -16
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +45 -18
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +20 -16
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +28 -19
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +25 -18
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +29 -19
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +23 -18
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +23 -18
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +36 -16
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +26 -17
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +30 -16
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +25 -16
- package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +28 -17
- package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +31 -17
- package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +31 -17
- package/skills/torusguard/payload/rules_catalog.json +520 -0
- package/skills/torusguard/payload/scripts/apply_runner.py +383 -339
- package/skills/torusguard/payload/scripts/audit_runner.py +1306 -550
- package/skills/torusguard/payload/scripts/finding_scorer.py +14 -2
- package/skills/torusguard/payload/scripts/harden_runner.py +628 -375
- package/skills/torusguard/payload/scripts/recheck_runner.py +248 -221
- package/skills/torusguard/payload/scripts/recipes_runner.py +137 -130
- package/skills/torusguard/payload/scripts/report_sync.py +423 -0
- package/skills/torusguard/payload/scripts/sarif_exporter.py +116 -116
- package/skills/torusguard/payload/scripts/term_ui.py +162 -0
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +75 -42
- package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +63 -25
- package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +62 -45
- package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +11 -5
- package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +12 -6
- package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +7 -2
- package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +71 -36
- package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +45 -29
- package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +59 -31
- package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +52 -30
- package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +40 -20
- package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +14 -8
- package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +14 -8
- package/skills/torusguard/payload/workflows/apply.md +11 -4
- package/skills/torusguard/payload/workflows/audit.md +7 -1
- package/skills/torusguard/payload/workflows/authorize.md +2 -1
- package/skills/torusguard/payload/workflows/exploit-check.md +2 -1
- package/skills/torusguard/payload/workflows/harden.md +7 -1
- package/skills/torusguard/payload/workflows/init.md +6 -1
- package/skills/torusguard/payload/workflows/memory.md +2 -1
- package/skills/torusguard/payload/workflows/recheck.md +7 -1
- package/skills/torusguard/payload/workflows/report.md +7 -1
- package/skills/torusguard/payload/workflows/status.md +6 -1
- package/skills/torusguard/payload/workflows/verify.md +6 -1
- package/skills/torusguard/payload/workflows/web-validate.md +2 -1
- package/skills/torusguard-apply/SKILL.md +63 -27
- package/skills/torusguard-audit/SKILL.md +62 -50
- package/skills/torusguard-authorize/SKILL.md +7 -2
- package/skills/torusguard-exploit-check/SKILL.md +7 -2
- package/skills/torusguard-full/SKILL.md +7 -2
- package/skills/torusguard-harden/SKILL.md +71 -40
- package/skills/torusguard-init/SKILL.md +45 -30
- package/skills/torusguard-recheck/SKILL.md +59 -32
- package/skills/torusguard-report/SKILL.md +52 -31
- package/skills/torusguard-status/SKILL.md +40 -21
- package/skills/torusguard-verify/SKILL.md +7 -2
- package/skills/torusguard-web-validate/SKILL.md +7 -2
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# TorusGuard Security Audit Findings: run-20260912-214813-audit
|
|
2
|
+
- Target Root: `C:\Users\Admin\Desktop\TorusGuard`
|
|
3
|
+
- Total Scored Findings: `30`
|
|
4
|
+
- Identified Clusters: `8`
|
|
5
|
+
- Generated At: `2026-09-12 21:48:13 IST`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
## Summary of Findings
|
|
9
|
+
|
|
10
|
+
### [Critical] TG-SEC-001 - Hardcoded Secret or API Key in Tracked Source
|
|
11
|
+
- **Finding ID:** `TG-SEC-001-bb5e4b77`
|
|
12
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:9`
|
|
13
|
+
- **Confidence Score:** `80/100` (High Confidence)
|
|
14
|
+
- **Cluster:** `cluster-credentials-exposure`
|
|
15
|
+
- **Description:** Hardcoded JWT signing secret
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
// TG-SEC-001: Hardcoded JWT secret
|
|
19
|
+
const JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';
|
|
20
|
+
|
|
21
|
+
// TG-PLATFORM-001: Wildcard CORS with credentials
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### [Critical] TG-SEC-001 - Hardcoded Secret or API Key in Tracked Source
|
|
25
|
+
- **Finding ID:** `TG-SEC-001-c393d596`
|
|
26
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:18`
|
|
27
|
+
- **Confidence Score:** `80/100` (High Confidence)
|
|
28
|
+
- **Cluster:** `cluster-credentials-exposure`
|
|
29
|
+
- **Description:** Hardcoded credential or API secret string
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
const users = [
|
|
33
|
+
{ id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },
|
|
34
|
+
{ id: '2', email: 'bob@demo.local', password: 'secret456', name: 'Bob' },
|
|
35
|
+
];
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
39
|
+
- **Finding ID:** `TG-SSRF-002-8378a839`
|
|
40
|
+
- **Location:** `core/clustering.py:53`
|
|
41
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
42
|
+
- **Cluster:** `cluster-ssrf`
|
|
43
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
44
|
+
```
|
|
45
|
+
"cluster_id": "cluster-ssrf-network",
|
|
46
|
+
"title": "Unvalidated Outbound HTTP Requests & Network Boundary Leakage",
|
|
47
|
+
"shared_remediation_path": "Validate destination URLs against strict allowlists and block internal IP ranges (127.0.0.1, 169.254.169.254).",
|
|
48
|
+
"shared_verification_plan": "Attempt outbound requests to loopback and link-local metadata endpoints."
|
|
49
|
+
},
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### [Critical] TG-DB-002 - Privileged Database Credential in Browser Context
|
|
53
|
+
- **Finding ID:** `TG-DB-002-d9bd69df`
|
|
54
|
+
- **Location:** `demo/playground/vulnerable_nextjs/actions.ts:9`
|
|
55
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
56
|
+
- **Cluster:** `cluster-client-leak`
|
|
57
|
+
- **Description:** Service role key or raw database connection string reference in frontend code
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
// Finding 1: TG-CLIENT-001 - Backend admin key exposed in client-accessible code
|
|
61
|
+
export const SUPABASE_SERVICE_ROLE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo_secret_token_1234567890";
|
|
62
|
+
|
|
63
|
+
interface UserRecord {
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
67
|
+
- **Finding ID:** `TG-SSRF-002-d08ed1ca`
|
|
68
|
+
- **Location:** `examples/hardened-react-express/client/vite.config.js:7`
|
|
69
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
70
|
+
- **Cluster:** `cluster-ssrf`
|
|
71
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
72
|
+
```
|
|
73
|
+
plugins: [react()],
|
|
74
|
+
build: { sourcemap: false },
|
|
75
|
+
server: { port: 5173, proxy: { '/api': 'http://localhost:3001' } },
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
80
|
+
- **Finding ID:** `TG-SSRF-002-a79cf464`
|
|
81
|
+
- **Location:** `examples/hardened-react-express/server/index.js:121`
|
|
82
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
83
|
+
- **Cluster:** `cluster-ssrf`
|
|
84
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
85
|
+
```
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
seed().then(() => app.listen(PORT, () => console.log(`Hardened demo http://localhost:${PORT}`)));
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### [Critical] TG-SSRF-004 - Unbounded Outbound Request Without Timeout
|
|
92
|
+
- **Finding ID:** `TG-SSRF-004-dcf3f71e`
|
|
93
|
+
- **Location:** `examples/python/fastapi-hardened/main.py:30`
|
|
94
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
95
|
+
- **Cluster:** `cluster-ssrf`
|
|
96
|
+
- **Description:** Python requests call without explicit timeout parameter
|
|
97
|
+
```
|
|
98
|
+
if not is_safe_url(url):
|
|
99
|
+
raise HTTPException(status_code=400, detail="Invalid destination address")
|
|
100
|
+
response = requests.get(url, timeout=5)
|
|
101
|
+
return {"status": response.status_code, "content": response.text}
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### [Critical] TG-SSRF-004 - Unbounded Outbound Request Without Timeout
|
|
106
|
+
- **Finding ID:** `TG-SSRF-004-d8472223`
|
|
107
|
+
- **Location:** `examples/python/fastapi-vuln/main.py:9`
|
|
108
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
109
|
+
- **Cluster:** `cluster-ssrf`
|
|
110
|
+
- **Description:** Python requests call without explicit timeout parameter
|
|
111
|
+
```
|
|
112
|
+
@app.get("/fetch")
|
|
113
|
+
def fetch_url(url: str):
|
|
114
|
+
response = requests.get(url)
|
|
115
|
+
return {"status": response.status_code, "content": response.text}
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
120
|
+
- **Finding ID:** `TG-SSRF-002-3c5a7c3c`
|
|
121
|
+
- **Location:** `examples/vulnerable-react-express/client/src/App.jsx:42`
|
|
122
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
123
|
+
- **Cluster:** `cluster-ssrf`
|
|
124
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
125
|
+
```
|
|
126
|
+
<div style={{ maxWidth: 560, margin: '2rem auto', fontFamily: 'sans-serif' }}>
|
|
127
|
+
<h1>Vulnerable Demo</h1>
|
|
128
|
+
<p style={{ color: 'crimson' }}>Intentionally insecure — localhost lab only</p>
|
|
129
|
+
|
|
130
|
+
<form onSubmit={login}>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
134
|
+
- **Finding ID:** `TG-SSRF-002-13c81e3a`
|
|
135
|
+
- **Location:** `examples/vulnerable-react-express/client/src/config.js:5`
|
|
136
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
137
|
+
- **Cluster:** `cluster-ssrf`
|
|
138
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
139
|
+
```
|
|
140
|
+
apiUrl: import.meta.env.VITE_API_URL,
|
|
141
|
+
// FAKE DEMO ONLY — never put real database URLs in client code
|
|
142
|
+
demoDbUrl: 'postgresql://demo:FAKE_PASSWORD@localhost:5432/demo',
|
|
143
|
+
};
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
147
|
+
- **Finding ID:** `TG-SSRF-002-b0f87c06`
|
|
148
|
+
- **Location:** `examples/vulnerable-react-express/client/vite.config.js:10`
|
|
149
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
150
|
+
- **Cluster:** `cluster-ssrf`
|
|
151
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
152
|
+
```
|
|
153
|
+
server: {
|
|
154
|
+
port: 5173,
|
|
155
|
+
proxy: { '/api': 'http://localhost:3001' },
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
161
|
+
- **Finding ID:** `TG-SSRF-002-ee77c629`
|
|
162
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:82`
|
|
163
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
164
|
+
- **Cluster:** `cluster-ssrf`
|
|
165
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
166
|
+
```
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
app.listen(PORT, () => console.log(`Vulnerable demo server http://localhost:${PORT}`));
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### [Critical] TG-SSRF-002 - Missing Internal Network Protection
|
|
173
|
+
- **Finding ID:** `TG-SSRF-002-a0d1eac8`
|
|
174
|
+
- **Location:** `skills/torusguard/payload/config/scope.json:4`
|
|
175
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
176
|
+
- **Cluster:** `cluster-ssrf`
|
|
177
|
+
- **Description:** Hardcoded internal loopback or cloud metadata endpoint target
|
|
178
|
+
```
|
|
179
|
+
"$schema": "../schemas/authorization.schema.json",
|
|
180
|
+
"authorization": {
|
|
181
|
+
"target": "localhost",
|
|
182
|
+
"owner_confirmed": false,
|
|
183
|
+
"scope_type": "source_code_only",
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### [Critical] TG-DIFF-001 - Accidental Security Check Bypass in Patch Additions
|
|
187
|
+
- **Finding ID:** `TG-DIFF-001-7db54483`
|
|
188
|
+
- **Location:** `skills/torusguard/payload/scripts/rules_sync.py:180`
|
|
189
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
190
|
+
- **Cluster:** `cluster-transport-security`
|
|
191
|
+
- **Description:** Disabled TLS certificate verification (verify=False)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
if not bypass_guards:
|
|
195
|
+
bypass_rule = "4. **No Security Bypasses:** Never insert `# nosec`, `verify=False`, `@csrf_exempt`, or `bypass_auth=True`."
|
|
196
|
+
else:
|
|
197
|
+
bypass_rule = f"4. **No Security Bypasses:** Never insert `# nosec`, `verify=False`, or {', '.join(bypass_guards[:2])}."
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### [Critical] TG-DIFF-001 - Accidental Security Check Bypass in Patch Additions
|
|
201
|
+
- **Finding ID:** `TG-DIFF-001-77bc2f9b`
|
|
202
|
+
- **Location:** `skills/torusguard/payload/scripts/rules_sync.py:157`
|
|
203
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
204
|
+
- **Cluster:** `cluster-transport-security`
|
|
205
|
+
- **Description:** Disabled Go TLS certificate verification (InsecureSkipVerify: true)
|
|
206
|
+
```
|
|
207
|
+
if "go" in stack_lower:
|
|
208
|
+
sql_guards.append("`db.Query(..., args)` / GORM")
|
|
209
|
+
bypass_guards.append("`InsecureSkipVerify: true`")
|
|
210
|
+
if "rust" in stack_lower:
|
|
211
|
+
sql_guards.append("`sqlx::query!` / Diesel")
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### [Critical] TG-DIFF-001 - Accidental Security Check Bypass in Patch Additions
|
|
215
|
+
- **Finding ID:** `TG-DIFF-001-cb5ae7e9`
|
|
216
|
+
- **Location:** `skills/torusguard/payload/scripts/rules_sync.py:172`
|
|
217
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
218
|
+
- **Cluster:** `cluster-transport-security`
|
|
219
|
+
- **Description:** Disabled Node.js TLS rejectUnauthorized
|
|
220
|
+
```
|
|
221
|
+
if "typescript" in stack_lower or "javascript" in stack_lower or "next" in stack_lower or "express" in stack_lower:
|
|
222
|
+
sql_guards.append("Prisma / Drizzle binders")
|
|
223
|
+
bypass_guards.append("`rejectUnauthorized: false`")
|
|
224
|
+
|
|
225
|
+
if not sql_guards:
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### [Critical] TG-DIFF-001 - Accidental Security Check Bypass in Patch Additions
|
|
229
|
+
- **Finding ID:** `TG-DIFF-001-0e4204af`
|
|
230
|
+
- **Location:** `skills/torusguard/payload/scripts/rules_sync.py:169`
|
|
231
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
232
|
+
- **Cluster:** `cluster-transport-security`
|
|
233
|
+
- **Description:** Disabled PHP curl SSL verification
|
|
234
|
+
```
|
|
235
|
+
if "php" in stack_lower:
|
|
236
|
+
sql_guards.append("PDO prepared statements / Eloquent")
|
|
237
|
+
bypass_guards.append("`CURLOPT_SSL_VERIFYPEER => false`")
|
|
238
|
+
if "typescript" in stack_lower or "javascript" in stack_lower or "next" in stack_lower or "express" in stack_lower:
|
|
239
|
+
sql_guards.append("Prisma / Drizzle binders")
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### [High] TG-INPUT-003 - Unsafe Dynamic Code or HTML Execution
|
|
243
|
+
- **Finding ID:** `TG-INPUT-003-fea9421e`
|
|
244
|
+
- **Location:** `examples/vulnerable-react-express/client/src/App.jsx:53`
|
|
245
|
+
- **Confidence Score:** `80/100` (High Confidence)
|
|
246
|
+
- **Cluster:** `cluster-injection`
|
|
247
|
+
- **Description:** React dangerouslySetInnerHTML rendering raw unescaped HTML
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
{/* TG-INPUT-003: Unsafe HTML rendering */}
|
|
251
|
+
<div dangerouslySetInnerHTML={{ __html: bio }} />
|
|
252
|
+
|
|
253
|
+
<button onClick={fetchUser}>Fetch user (IDOR demo)</button>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### [High] TG-PLATFORM-001 - Wildcard CORS With Credentials
|
|
257
|
+
- **Finding ID:** `TG-PLATFORM-001-7dd35cb4`
|
|
258
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:12`
|
|
259
|
+
- **Confidence Score:** `80/100` (High Confidence)
|
|
260
|
+
- **Cluster:** `cluster-auth-bypass`
|
|
261
|
+
- **Description:** Wildcard CORS origin configured in Express middleware
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
// TG-PLATFORM-001: Wildcard CORS with credentials
|
|
265
|
+
app.use(cors({ origin: '*', credentials: true }));
|
|
266
|
+
|
|
267
|
+
// TG-PLATFORM-004: No explicit JSON body size limit
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### [High] TG-INPUT-001 - Missing Server-Side Request Validation
|
|
271
|
+
- **Finding ID:** `TG-INPUT-001-c7457f38`
|
|
272
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:27`
|
|
273
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
274
|
+
- **Cluster:** `cluster-injection`
|
|
275
|
+
- **Description:** Destructuring unvalidated req.body without schema validation
|
|
276
|
+
```
|
|
277
|
+
// TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)
|
|
278
|
+
app.post('/api/login', (req, res) => {
|
|
279
|
+
const { email, password } = req.body;
|
|
280
|
+
console.log('Login attempt:', { email, password }); // TG-SEC-004
|
|
281
|
+
const user = users.find((u) => u.email === email && u.password === password);
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### [High] TG-RATE-001 - Unlimited Authentication Endpoint
|
|
285
|
+
- **Finding ID:** `TG-RATE-001-dcd0a3c7`
|
|
286
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:26`
|
|
287
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
288
|
+
- **Cluster:** `cluster-rate-limiting`
|
|
289
|
+
- **Description:** Authentication POST endpoint defined without rate-limiting middleware
|
|
290
|
+
```
|
|
291
|
+
// TG-SEC-004: Logs sensitive data
|
|
292
|
+
// TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)
|
|
293
|
+
app.post('/api/login', (req, res) => {
|
|
294
|
+
const { email, password } = req.body;
|
|
295
|
+
console.log('Login attempt:', { email, password }); // TG-SEC-004
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### [High] TG-AUTH-004 - Insecure Session Cookie Configuration
|
|
299
|
+
- **Finding ID:** `TG-AUTH-004-f60870ef`
|
|
300
|
+
- **Location:** `skills/torusguard/payload/scripts/rules_sync.py:180`
|
|
301
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
302
|
+
- **Cluster:** `cluster-auth-bypass`
|
|
303
|
+
- **Description:** Decorator disabling route-level authentication or CSRF protection
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
if not bypass_guards:
|
|
307
|
+
bypass_rule = "4. **No Security Bypasses:** Never insert `# nosec`, `verify=False`, `@csrf_exempt`, or `bypass_auth=True`."
|
|
308
|
+
else:
|
|
309
|
+
bypass_rule = f"4. **No Security Bypasses:** Never insert `# nosec`, `verify=False`, or {', '.join(bypass_guards[:2])}."
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### [High] TG-AUTH-004 - Insecure Session Cookie Configuration
|
|
313
|
+
- **Finding ID:** `TG-AUTH-004-6b0c7ebf`
|
|
314
|
+
- **Location:** `skills/torusguard/payload/scripts/rules_sync.py:166`
|
|
315
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
316
|
+
- **Cluster:** `cluster-auth-bypass`
|
|
317
|
+
- **Description:** Attribute disabling ASP.NET authentication
|
|
318
|
+
```
|
|
319
|
+
if "c#" in stack_lower or "dotnet" in stack_lower:
|
|
320
|
+
sql_guards.append("EF Core LINQ / `FromSqlInterpolated`")
|
|
321
|
+
bypass_guards.append("`[AllowAnonymous]`")
|
|
322
|
+
if "php" in stack_lower:
|
|
323
|
+
sql_guards.append("PDO prepared statements / Eloquent")
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### [High] TG-AUTH-003 - Missing Object-Level Authorization (IDOR)
|
|
327
|
+
- **Finding ID:** `TG-AUTH-003-6a05e509`
|
|
328
|
+
- **Location:** `examples/hardened-react-express/server/index.js:49`
|
|
329
|
+
- **Confidence Score:** `55/100` (Medium Confidence)
|
|
330
|
+
- **Cluster:** `cluster-auth-bypass`
|
|
331
|
+
- **Description:** JWT verification missing explicit algorithms restriction parameter
|
|
332
|
+
```
|
|
333
|
+
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
|
334
|
+
try {
|
|
335
|
+
req.user = jwt.verify(token, process.env.JWT_SECRET);
|
|
336
|
+
next();
|
|
337
|
+
} catch {
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### [Medium] TG-PLATFORM-002 - Missing Security Headers
|
|
341
|
+
- **Finding ID:** `TG-PLATFORM-002-1f383dcf`
|
|
342
|
+
- **Location:** `examples/hardened-react-express/server/index.js:17`
|
|
343
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
344
|
+
- **Cluster:** `cluster-platform`
|
|
345
|
+
- **Description:** Express application initialized without helmet security headers middleware
|
|
346
|
+
```
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const app = express();
|
|
350
|
+
const PORT = 3001;
|
|
351
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### [Medium] TG-SEC-004 - Sensitive Information in Logs
|
|
355
|
+
- **Finding ID:** `TG-SEC-004-dbbc17f7`
|
|
356
|
+
- **Location:** `examples/vulnerable-react-express/client/src/App.jsx:30`
|
|
357
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
358
|
+
- **Cluster:** `cluster-credentials-exposure`
|
|
359
|
+
- **Description:** Plaintext credential or token logged to output sink
|
|
360
|
+
```
|
|
361
|
+
const data = await res.json();
|
|
362
|
+
// TG-CLIENT-002: Sensitive console logging
|
|
363
|
+
console.log('Login token:', data.token, 'config:', clientConfig);
|
|
364
|
+
setMessage(JSON.stringify(data));
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### [Medium] TG-CLIENT-001 - Public Production Source Maps
|
|
369
|
+
- **Finding ID:** `TG-CLIENT-001-1ba4789e`
|
|
370
|
+
- **Location:** `examples/vulnerable-react-express/client/vite.config.js:7`
|
|
371
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
372
|
+
- **Cluster:** `cluster-client-leak`
|
|
373
|
+
- **Description:** Build config emitting unminified source maps in production output
|
|
374
|
+
```
|
|
375
|
+
export default defineConfig({
|
|
376
|
+
plugins: [react()],
|
|
377
|
+
build: { sourcemap: true },
|
|
378
|
+
server: {
|
|
379
|
+
port: 5173,
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### [Medium] TG-SEC-004 - Sensitive Information in Logs
|
|
383
|
+
- **Finding ID:** `TG-SEC-004-08753da5`
|
|
384
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:28`
|
|
385
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
386
|
+
- **Cluster:** `cluster-credentials-exposure`
|
|
387
|
+
- **Description:** Plaintext credential or token logged to output sink
|
|
388
|
+
```
|
|
389
|
+
app.post('/api/login', (req, res) => {
|
|
390
|
+
const { email, password } = req.body;
|
|
391
|
+
console.log('Login attempt:', { email, password }); // TG-SEC-004
|
|
392
|
+
const user = users.find((u) => u.email === email && u.password === password);
|
|
393
|
+
if (!user) return res.status(401).json({ error: 'User not found' }); // enumeration
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### [Medium] TG-RATE-002 - Unlimited Public Write Endpoint
|
|
397
|
+
- **Finding ID:** `TG-RATE-002-d67d7c98`
|
|
398
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:54`
|
|
399
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
400
|
+
- **Cluster:** `cluster-rate-limiting`
|
|
401
|
+
- **Description:** Public submission endpoint defined without rate-limiting or captcha defense
|
|
402
|
+
```
|
|
403
|
+
// TG-INPUT-001: No validation
|
|
404
|
+
// TG-RATE-002: Unlimited contact endpoint
|
|
405
|
+
app.post('/api/contact', (req, res) => {
|
|
406
|
+
res.json({ received: req.body });
|
|
407
|
+
});
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
### [Medium] TG-PLATFORM-002 - Missing Security Headers
|
|
411
|
+
- **Finding ID:** `TG-PLATFORM-002-eef342ec`
|
|
412
|
+
- **Location:** `examples/vulnerable-react-express/server/index.js:5`
|
|
413
|
+
- **Confidence Score:** `70/100` (High Confidence)
|
|
414
|
+
- **Cluster:** `cluster-platform`
|
|
415
|
+
- **Description:** Express application initialized without helmet security headers middleware
|
|
416
|
+
```
|
|
417
|
+
const jwt = require('jsonwebtoken');
|
|
418
|
+
|
|
419
|
+
const app = express();
|
|
420
|
+
const PORT = 3001;
|
|
421
|
+
|
|
422
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"run_id": "run-20260912-214813-audit",
|
|
3
|
+
"command": "audit",
|
|
4
|
+
"target_name": "TorusGuard",
|
|
5
|
+
"created_at": "2026-09-12 21:48:13 IST",
|
|
6
|
+
"created_at_iso": "2026-09-12T21:48:13.470732+05:30",
|
|
7
|
+
"status": "completed",
|
|
8
|
+
"torusguard_version": "1.3.0",
|
|
9
|
+
"findings_count": 30,
|
|
10
|
+
"confirmed_fixed_count": 0,
|
|
11
|
+
"regressed_count": 0
|
|
12
|
+
}
|
package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-auth-003-49-7c96f3/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-auth-003-49-7c96f3",
|
|
3
|
+
"finding_id": "TG-AUTH-003-6a05e509",
|
|
4
|
+
"rule_id": "TG-AUTH-003",
|
|
5
|
+
"title": "Missing Object-Level Authorization (IDOR)",
|
|
6
|
+
"target_file": "examples/hardened-react-express/server/index.js",
|
|
7
|
+
"line_number": 49,
|
|
8
|
+
"target_line": " req.user = jwt.verify(token, process.env.JWT_SECRET);",
|
|
9
|
+
"replacement_line": " req.user = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });",
|
|
10
|
+
"what_is_wrong": "JWT verification missing explicit algorithms restriction parameter",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Restricted JWT verification to explicit algorithm list ['HS256']",
|
|
13
|
+
"proposed_diff": "--- a/examples/hardened-react-express/server/index.js\n+++ b/examples/hardened-react-express/server/index.js\n@@ -47,5 +47,5 @@\n if (!token) return res.status(401).json({ error: 'Unauthorized' });\n try {\n- req.user = jwt.verify(token, process.env.JWT_SECRET);\n+ req.user = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });\n next();\n } catch {\n",
|
|
14
|
+
"additions": 1,
|
|
15
|
+
"deletions": 1,
|
|
16
|
+
"patched_content": "require('dotenv').config();\nconst express = require('express');\nconst helmet = require('helmet');\nconst cors = require('cors');\nconst cookieParser = require('cookie-parser');\nconst rateLimit = require('express-rate-limit');\nconst bcrypt = require('bcrypt');\nconst jwt = require('jsonwebtoken');\nconst crypto = require('crypto');\nconst { z } = require('zod');\n\nif (!process.env.JWT_SECRET) {\n console.error('Missing JWT_SECRET');\n process.exit(1);\n}\n\nconst app = express();\nconst PORT = 3001;\nconst isProd = process.env.NODE_ENV === 'production';\n\napp.use(helmet());\napp.use(cors({ origin: process.env.CLIENT_ORIGIN, credentials: true }));\napp.use(express.json({ limit: '100kb' }));\napp.use(cookieParser());\n\nconst loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5 });\nconst resetLimiter = rateLimit({ windowMs: 60 * 60 * 1000, max: 3 });\nconst publicWriteLimiter = rateLimit({ windowMs: 60 * 60 * 1000, max: 10 });\n\nconst users = [];\nconst resetTokens = new Map();\n\nasync function seed() {\n if (users.length) return;\n const hash = await bcrypt.hash('DemoPass123!', 12);\n users.push({ id: '1', email: 'alice@demo.local', passwordHash: hash, name: 'Alice', role: 'user' });\n users.push({ id: '2', email: 'bob@demo.local', passwordHash: hash, name: 'Bob', role: 'user' });\n}\n\nconst loginSchema = z.object({\n email: z.string().email().max(255),\n password: z.string().min(8).max(128),\n});\n\nfunction auth(req, res, next) {\n const token = req.cookies.token;\n if (!token) return res.status(401).json({ error: 'Unauthorized' });\n try {\n req.user = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });\n next();\n } catch {\n return res.status(401).json({ error: 'Unauthorized' });\n }\n}\n\napp.post('/api/login', loginLimiter, async (req, res) => {\n const parsed = loginSchema.safeParse(req.body);\n if (!parsed.success) return res.status(400).json({ error: 'Invalid input' });\n const { email, password } = parsed.data;\n const user = users.find((u) => u.email === email);\n if (!user || !(await bcrypt.compare(password, user.passwordHash))) {\n return res.status(401).json({ error: 'Invalid email or password' });\n }\n const token = jwt.sign({ id: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1h' });\n res.cookie('token', token, {\n httpOnly: true,\n secure: isProd,\n sameSite: 'lax',\n maxAge: 3600000,\n });\n res.json({ message: 'Login successful' });\n});\n\napp.get('/api/users/me', auth, (req, res) => {\n const user = users.find((u) => u.id === req.user.id);\n if (!user) return res.status(404).json({ error: 'Not found' });\n res.json({ id: user.id, email: user.email, name: user.name });\n});\n\napp.get('/api/search', auth, (req, res) => {\n const q = String(req.query.q || '').slice(0, 100);\n const results = users\n .filter((u) => u.email.includes(q))\n .slice(0, 20)\n .map(({ id, email, name }) => ({ id, email, name }));\n res.json({ results });\n});\n\nconst contactSchema = z.object({ message: z.string().min(1).max(2000) });\napp.post('/api/contact', publicWriteLimiter, (req, res) => {\n const parsed = contactSchema.safeParse(req.body);\n if (!parsed.success) return res.status(400).json({ error: 'Invalid input' });\n res.json({ ok: true });\n});\n\napp.post('/api/ai', auth, publicWriteLimiter, (req, res) => {\n const prompt = String(req.body.prompt || '').slice(0, 4000);\n res.json({ reply: 'demo response', length: prompt.length });\n});\n\napp.post('/api/reset', resetLimiter, (req, res) => {\n const email = String(req.body.email || '');\n const user = users.find((u) => u.email === email);\n if (user) {\n const token = crypto.randomBytes(32).toString('hex');\n resetTokens.set(token, { userId: user.id, expires: Date.now() + 900000 });\n }\n res.json({ message: 'If an account exists, a reset link was sent.' });\n});\n\napp.get('/api/admin/stats', auth, (req, res) => {\n if (req.user.role !== 'admin') return res.status(403).json({ error: 'Forbidden' });\n res.json({ users: users.length });\n});\n\napp.use((err, req, res, next) => {\n console.error('Error', { message: err.message });\n res.status(500).json({ error: isProd ? 'Internal server error' : err.message });\n});\n\nseed().then(() => app.listen(PORT, () => console.log(`Hardened demo http://localhost:${PORT}`)));"
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-auth-003-49-7c96f3
|
|
2
|
+
- **Rule ID:** `TG-AUTH-003`
|
|
3
|
+
- **Target File:** `examples/hardened-react-express/server/index.js:49`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Restricted JWT verification to explicit algorithm list ['HS256']
|
|
8
|
+
|
|
9
|
+
## Unified Diff Preview
|
|
10
|
+
```diff
|
|
11
|
+
--- a/examples/hardened-react-express/server/index.js
|
|
12
|
+
+++ b/examples/hardened-react-express/server/index.js
|
|
13
|
+
@@ -47,5 +47,5 @@
|
|
14
|
+
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
|
15
|
+
try {
|
|
16
|
+
- req.user = jwt.verify(token, process.env.JWT_SECRET);
|
|
17
|
+
+ req.user = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });
|
|
18
|
+
next();
|
|
19
|
+
} catch {
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-auth-003-49-7c96f3/patch.diff
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
--- a/examples/hardened-react-express/server/index.js
|
|
2
|
+
+++ b/examples/hardened-react-express/server/index.js
|
|
3
|
+
@@ -47,5 +47,5 @@
|
|
4
|
+
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
|
5
|
+
try {
|
|
6
|
+
- req.user = jwt.verify(token, process.env.JWT_SECRET);
|
|
7
|
+
+ req.user = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'] });
|
|
8
|
+
next();
|
|
9
|
+
} catch {
|
package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-input-003-53-d167b4",
|
|
3
|
+
"finding_id": "TG-INPUT-003-fea9421e",
|
|
4
|
+
"rule_id": "TG-INPUT-003",
|
|
5
|
+
"title": "Unsafe Dynamic Code or HTML Execution",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/client/src/App.jsx",
|
|
7
|
+
"line_number": 53,
|
|
8
|
+
"target_line": " <div dangerouslySetInnerHTML={{ __html: bio }} />",
|
|
9
|
+
"replacement_line": " <div>{bio}</div>",
|
|
10
|
+
"what_is_wrong": "React dangerouslySetInnerHTML rendering raw unescaped HTML",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Replaced raw dangerouslySetInnerHTML injection with safe React text interpolation",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/client/src/App.jsx\n+++ b/examples/vulnerable-react-express/client/src/App.jsx\n@@ -51,5 +51,5 @@\n \n {/* TG-INPUT-003: Unsafe HTML rendering */}\n- <div dangerouslySetInnerHTML={{ __html: bio }} />\n+ <div>{bio}</div>\n \n <button onClick={fetchUser}>Fetch user (IDOR demo)</button>\n",
|
|
14
|
+
"additions": 1,
|
|
15
|
+
"deletions": 1,
|
|
16
|
+
"patched_content": "import { useState } from 'react';\nimport { clientConfig } from './config';\n\n// TG-DB-001: SQL query construction in frontend (never do this)\nfunction buildSearchQuery(email) {\n return `SELECT id, email FROM users WHERE email LIKE '%${email}%'`;\n}\n\n// TG-DB-003: Documented anti-pattern \u2014 Prisma must never run in browser\n// import { PrismaClient } from '@prisma/client'; // FORBIDDEN in client\n\nexport default function App() {\n const [email, setEmail] = useState('');\n const [password, setPassword] = useState('');\n const [bio, setBio] = useState('<img src=x onerror=alert(1)>');\n const [userId, setUserId] = useState('1');\n const [isAdmin] = useState(localStorage.getItem('role') === 'admin'); // TG-AUTH-002\n const [message, setMessage] = useState('');\n\n async function login(e) {\n e.preventDefault();\n const res = await fetch('/api/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({ email, password }),\n });\n const data = await res.json();\n // TG-CLIENT-002: Sensitive console logging\n console.log('Login token:', data.token, 'config:', clientConfig);\n setMessage(JSON.stringify(data));\n }\n\n async function fetchUser() {\n const res = await fetch(`/api/users/${userId}`);\n setMessage(await res.text());\n }\n\n return (\n <div style={{ maxWidth: 560, margin: '2rem auto', fontFamily: 'sans-serif' }}>\n <h1>Vulnerable Demo</h1>\n <p style={{ color: 'crimson' }}>Intentionally insecure \u2014 localhost lab only</p>\n\n <form onSubmit={login}>\n <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder=\"email\" />\n <input value={password} onChange={(e) => setPassword(e.target.value)} placeholder=\"password\" type=\"password\" />\n <button type=\"submit\">Login</button>\n </form>\n\n <p>Frontend SQL preview: {buildSearchQuery(email)}</p>\n\n {/* TG-INPUT-003: Unsafe HTML rendering */}\n <div>{bio}</div>\n\n <button onClick={fetchUser}>Fetch user (IDOR demo)</button>\n\n {/* TG-AUTH-002: Client-only admin gate */}\n {isAdmin && <section><h2>Admin Panel</h2><p>Visible if localStorage role=admin \u2014 not real security</p></section>}\n\n {message && <pre>{message}</pre>}\n </div>\n );\n}"
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-input-003-53-d167b4
|
|
2
|
+
- **Rule ID:** `TG-INPUT-003`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/client/src/App.jsx:53`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Replaced raw dangerouslySetInnerHTML injection with safe React text interpolation
|
|
8
|
+
|
|
9
|
+
## Unified Diff Preview
|
|
10
|
+
```diff
|
|
11
|
+
--- a/examples/vulnerable-react-express/client/src/App.jsx
|
|
12
|
+
+++ b/examples/vulnerable-react-express/client/src/App.jsx
|
|
13
|
+
@@ -51,5 +51,5 @@
|
|
14
|
+
|
|
15
|
+
{/* TG-INPUT-003: Unsafe HTML rendering */}
|
|
16
|
+
- <div dangerouslySetInnerHTML={{ __html: bio }} />
|
|
17
|
+
+ <div>{bio}</div>
|
|
18
|
+
|
|
19
|
+
<button onClick={fetchUser}>Fetch user (IDOR demo)</button>
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
--- a/examples/vulnerable-react-express/client/src/App.jsx
|
|
2
|
+
+++ b/examples/vulnerable-react-express/client/src/App.jsx
|
|
3
|
+
@@ -51,5 +51,5 @@
|
|
4
|
+
|
|
5
|
+
{/* TG-INPUT-003: Unsafe HTML rendering */}
|
|
6
|
+
- <div dangerouslySetInnerHTML={{ __html: bio }} />
|
|
7
|
+
+ <div>{bio}</div>
|
|
8
|
+
|
|
9
|
+
<button onClick={fetchUser}>Fetch user (IDOR demo)</button>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-platform-001-12-cf8156",
|
|
3
|
+
"finding_id": "TG-PLATFORM-001-7dd35cb4",
|
|
4
|
+
"rule_id": "TG-PLATFORM-001",
|
|
5
|
+
"title": "Wildcard CORS With Credentials",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 12,
|
|
8
|
+
"target_line": "app.use(cors({ origin: '*', credentials: true }));",
|
|
9
|
+
"replacement_line": "app.use(cors({ origin: process.env.ALLOWED_ORIGIN || 'http://localhost:5173', credentials: true }));",
|
|
10
|
+
"what_is_wrong": "Wildcard CORS origin configured in Express middleware",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Constrained wildcard CORS origin to process.env.ALLOWED_ORIGIN with secure fallback",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -10,5 +10,5 @@\n \n // TG-PLATFORM-001: Wildcard CORS with credentials\n-app.use(cors({ origin: '*', credentials: true }));\n+app.use(cors({ origin: process.env.ALLOWED_ORIGIN || 'http://localhost:5173', credentials: true }));\n \n // TG-PLATFORM-004: No explicit JSON body size limit\n",
|
|
14
|
+
"additions": 1,
|
|
15
|
+
"deletions": 1,
|
|
16
|
+
"patched_content": "const express = require('express');\nconst cors = require('cors');\nconst jwt = require('jsonwebtoken');\n\nconst app = express();\nconst PORT = 3001;\n\n// TG-SEC-001: Hardcoded JWT secret\nconst JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';\n\n// TG-PLATFORM-001: Wildcard CORS with credentials\napp.use(cors({ origin: process.env.ALLOWED_ORIGIN || 'http://localhost:5173', credentials: true }));\n\n// TG-PLATFORM-004: No explicit JSON body size limit\napp.use(express.json());\n\nconst users = [\n { id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },\n { id: '2', email: 'bob@demo.local', password: 'secret456', name: 'Bob' },\n];\n\n// TG-RATE-001: No rate limit on login\n// TG-AUTH-001: Plaintext password comparison\n// TG-SEC-004: Logs sensitive data\n// TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)\napp.post('/api/login', (req, res) => {\n const { email, password } = req.body;\n console.log('Login attempt:', { email, password }); // TG-SEC-004\n const user = users.find((u) => u.email === email && u.password === password);\n if (!user) return res.status(401).json({ error: 'User not found' }); // enumeration\n const token = jwt.sign({ id: user.id }, JWT_SECRET);\n res.cookie('token', token);\n res.json({ message: 'ok', token, user });\n});\n\n// TG-AUTH-003: IDOR \u2014 no ownership check\napp.get('/api/users/:id', (req, res) => {\n const user = users.find((u) => u.id === req.params.id);\n if (!user) return res.status(404).json({ error: 'Not found' });\n res.json(user);\n});\n\n// TG-INPUT-002: SQL concatenation (simulated query string)\n// TG-RATE-003: Unbounded results\napp.get('/api/search', (req, res) => {\n const q = req.query.q || '';\n const fakeSql = `SELECT * FROM users WHERE email LIKE '%${q}%'`;\n const results = users.filter((u) => u.email.includes(q));\n res.json({ query: fakeSql, results });\n});\n\n// TG-INPUT-001: No validation\n// TG-RATE-002: Unlimited contact endpoint\napp.post('/api/contact', (req, res) => {\n res.json({ received: req.body });\n});\n\n// TG-RATE-002: Unlimited AI endpoint\napp.post('/api/ai', (req, res) => {\n res.json({ reply: 'demo', prompt: req.body.prompt });\n});\n\n// TG-INPUT-004: Unrestricted upload (stub)\napp.post('/api/upload', (req, res) => {\n res.json({ saved: req.body.filename });\n});\n\n// TG-AUTH-005: Unsafe password reset\napp.post('/api/reset', (req, res) => {\n const { email } = req.body;\n const user = users.find((u) => u.email === email);\n if (!user) return res.status(404).json({ error: 'Email not registered' }); // enumeration\n const token = `reset-${user.id}-12345`; // predictable\n res.json({ resetToken: token });\n});\n\napp.use((err, req, res, next) => {\n // TG-PLATFORM-003: Stack trace exposed\n res.status(500).json({ error: err.message, stack: err.stack });\n});\n\napp.listen(PORT, () => console.log(`Vulnerable demo server http://localhost:${PORT}`));"
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-platform-001-12-cf8156
|
|
2
|
+
- **Rule ID:** `TG-PLATFORM-001`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:12`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Constrained wildcard CORS origin to process.env.ALLOWED_ORIGIN with secure fallback
|
|
8
|
+
|
|
9
|
+
## Unified Diff Preview
|
|
10
|
+
```diff
|
|
11
|
+
--- a/examples/vulnerable-react-express/server/index.js
|
|
12
|
+
+++ b/examples/vulnerable-react-express/server/index.js
|
|
13
|
+
@@ -10,5 +10,5 @@
|
|
14
|
+
|
|
15
|
+
// TG-PLATFORM-001: Wildcard CORS with credentials
|
|
16
|
+
-app.use(cors({ origin: '*', credentials: true }));
|
|
17
|
+
+app.use(cors({ origin: process.env.ALLOWED_ORIGIN || 'http://localhost:5173', credentials: true }));
|
|
18
|
+
|
|
19
|
+
// TG-PLATFORM-004: No explicit JSON body size limit
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-platform-001-12-cf8156/patch.diff
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
--- a/examples/vulnerable-react-express/server/index.js
|
|
2
|
+
+++ b/examples/vulnerable-react-express/server/index.js
|
|
3
|
+
@@ -10,5 +10,5 @@
|
|
4
|
+
|
|
5
|
+
// TG-PLATFORM-001: Wildcard CORS with credentials
|
|
6
|
+
-app.use(cors({ origin: '*', credentials: true }));
|
|
7
|
+
+app.use(cors({ origin: process.env.ALLOWED_ORIGIN || 'http://localhost:5173', credentials: true }));
|
|
8
|
+
|
|
9
|
+
// TG-PLATFORM-004: No explicit JSON body size limit
|
package/.torusguard/runs/run-20260912-215555-audit/bundles/bnd-tg-rate-001-26-affcfa/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-rate-001-26-affcfa",
|
|
3
|
+
"finding_id": "TG-RATE-001-dcd0a3c7",
|
|
4
|
+
"rule_id": "TG-RATE-001",
|
|
5
|
+
"title": "Unlimited Authentication Endpoint",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 26,
|
|
8
|
+
"target_line": "app.post('/api/login', (req, res) => {",
|
|
9
|
+
"replacement_line": "app.post('/api/login', authLimiter, (req, res) => {",
|
|
10
|
+
"what_is_wrong": "Authentication POST endpoint defined without rate-limiting middleware",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Injected authLimiter rate-limiting middleware to protect authentication endpoint from brute force",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -24,5 +24,5 @@\n // TG-SEC-004: Logs sensitive data\n // TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)\n-app.post('/api/login', (req, res) => {\n+app.post('/api/login', authLimiter, (req, res) => {\n const { email, password } = req.body;\n console.log('Login attempt:', { email, password }); // TG-SEC-004\n",
|
|
14
|
+
"additions": 1,
|
|
15
|
+
"deletions": 1,
|
|
16
|
+
"patched_content": "const express = require('express');\nconst cors = require('cors');\nconst jwt = require('jsonwebtoken');\n\nconst app = express();\nconst PORT = 3001;\n\n// TG-SEC-001: Hardcoded JWT secret\nconst JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';\n\n// TG-PLATFORM-001: Wildcard CORS with credentials\napp.use(cors({ origin: '*', credentials: true }));\n\n// TG-PLATFORM-004: No explicit JSON body size limit\napp.use(express.json());\n\nconst users = [\n { id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },\n { id: '2', email: 'bob@demo.local', password: 'secret456', name: 'Bob' },\n];\n\n// TG-RATE-001: No rate limit on login\n// TG-AUTH-001: Plaintext password comparison\n// TG-SEC-004: Logs sensitive data\n// TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)\napp.post('/api/login', authLimiter, (req, res) => {\n const { email, password } = req.body;\n console.log('Login attempt:', { email, password }); // TG-SEC-004\n const user = users.find((u) => u.email === email && u.password === password);\n if (!user) return res.status(401).json({ error: 'User not found' }); // enumeration\n const token = jwt.sign({ id: user.id }, JWT_SECRET);\n res.cookie('token', token);\n res.json({ message: 'ok', token, user });\n});\n\n// TG-AUTH-003: IDOR \u2014 no ownership check\napp.get('/api/users/:id', (req, res) => {\n const user = users.find((u) => u.id === req.params.id);\n if (!user) return res.status(404).json({ error: 'Not found' });\n res.json(user);\n});\n\n// TG-INPUT-002: SQL concatenation (simulated query string)\n// TG-RATE-003: Unbounded results\napp.get('/api/search', (req, res) => {\n const q = req.query.q || '';\n const fakeSql = `SELECT * FROM users WHERE email LIKE '%${q}%'`;\n const results = users.filter((u) => u.email.includes(q));\n res.json({ query: fakeSql, results });\n});\n\n// TG-INPUT-001: No validation\n// TG-RATE-002: Unlimited contact endpoint\napp.post('/api/contact', (req, res) => {\n res.json({ received: req.body });\n});\n\n// TG-RATE-002: Unlimited AI endpoint\napp.post('/api/ai', (req, res) => {\n res.json({ reply: 'demo', prompt: req.body.prompt });\n});\n\n// TG-INPUT-004: Unrestricted upload (stub)\napp.post('/api/upload', (req, res) => {\n res.json({ saved: req.body.filename });\n});\n\n// TG-AUTH-005: Unsafe password reset\napp.post('/api/reset', (req, res) => {\n const { email } = req.body;\n const user = users.find((u) => u.email === email);\n if (!user) return res.status(404).json({ error: 'Email not registered' }); // enumeration\n const token = `reset-${user.id}-12345`; // predictable\n res.json({ resetToken: token });\n});\n\napp.use((err, req, res, next) => {\n // TG-PLATFORM-003: Stack trace exposed\n res.status(500).json({ error: err.message, stack: err.stack });\n});\n\napp.listen(PORT, () => console.log(`Vulnerable demo server http://localhost:${PORT}`));"
|
|
17
|
+
}
|