torusguard 1.3.4 → 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-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__/finding_scorer.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/report_sync.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/term_ui.cpython-311.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +383 -377
- package/.torusguard/scripts/audit_runner.py +1306 -653
- package/.torusguard/scripts/finding_scorer.py +14 -2
- package/.torusguard/scripts/harden_runner.py +628 -455
- package/.torusguard/scripts/recheck_runner.py +248 -238
- package/.torusguard/scripts/recipes_runner.py +137 -137
- package/.torusguard/scripts/report_sync.py +423 -0
- package/.torusguard/scripts/sarif_exporter.py +116 -116
- package/.torusguard/scripts/term_ui.py +162 -162
- 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 -345
- package/bin/torusguard.js +550 -545
- package/package.json +1 -1
- package/skills/torusguard/SKILL.md +73 -72
- 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 -377
- package/skills/torusguard/payload/scripts/audit_runner.py +1306 -653
- package/skills/torusguard/payload/scripts/finding_scorer.py +14 -2
- package/skills/torusguard/payload/scripts/harden_runner.py +628 -455
- package/skills/torusguard/payload/scripts/recheck_runner.py +248 -238
- package/skills/torusguard/payload/scripts/recipes_runner.py +137 -137
- 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 -162
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +75 -72
- package/skills/torusguard/payload/skills/torusguard-apply/SKILL.md +84 -80
- package/skills/torusguard/payload/skills/torusguard-audit/SKILL.md +87 -83
- package/skills/torusguard/payload/skills/torusguard-authorize/SKILL.md +7 -2
- package/skills/torusguard/payload/skills/torusguard-exploit-check/SKILL.md +7 -2
- package/skills/torusguard/payload/skills/torusguard-full/SKILL.md +7 -2
- package/skills/torusguard/payload/skills/torusguard-harden/SKILL.md +98 -94
- package/skills/torusguard/payload/skills/torusguard-init/SKILL.md +68 -64
- package/skills/torusguard/payload/skills/torusguard-recheck/SKILL.md +81 -77
- package/skills/torusguard/payload/skills/torusguard-report/SKILL.md +76 -72
- package/skills/torusguard/payload/skills/torusguard-status/SKILL.md +62 -58
- package/skills/torusguard/payload/skills/torusguard-verify/SKILL.md +7 -2
- package/skills/torusguard/payload/skills/torusguard-web-validate/SKILL.md +7 -2
- 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 +84 -80
- package/skills/torusguard-audit/SKILL.md +87 -83
- 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 +98 -94
- package/skills/torusguard-init/SKILL.md +68 -64
- package/skills/torusguard-recheck/SKILL.md +81 -77
- package/skills/torusguard-report/SKILL.md +76 -72
- package/skills/torusguard-status/SKILL.md +62 -58
- package/skills/torusguard-verify/SKILL.md +7 -2
- package/skills/torusguard-web-validate/SKILL.md +7 -2
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
# TG-SUPPLY-005: Unsafe Dependency Install Script
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
|
|
4
|
+
Critical. Piping remote scripts directly from `curl` or `wget` into `bash` or `sh` without checksum verification or cryptographic signature checking creates an immediate Remote Code Execution (RCE) vulnerability.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- CI/CD Workflows, Setup Scripts, Dockerfiles, Provisioning Scripts
|
|
8
|
+
- Shell, Bash, Dockerfile
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
If the remote server is compromised, the DNS hijacked, or a CDN man-in-the-middle occurs, arbitrary malicious code is executed directly in your environment. Furthermore, partial network downloads can cause truncated execution of dangerous shell commands.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- Shell patterns piping `curl -s ... | bash` or `wget -O- ... | sh`.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
|
-
```
|
|
17
|
-
|
|
17
|
+
```bash
|
|
18
|
+
# UNSAFE: Piping remote URL directly into shell execution
|
|
19
|
+
curl -sSL https://install.vendor.com/setup.sh | bash
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
## Safe Example
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
+
```bash
|
|
24
|
+
# SAFE: Downloading script, verifying SHA-256 checksum, and executing
|
|
25
|
+
EXPECTED_SHA="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
26
|
+
curl -sSL -o install.sh https://install.vendor.com/setup.sh
|
|
27
|
+
echo "${EXPECTED_SHA} install.sh" | sha256sum --check -
|
|
28
|
+
bash install.sh
|
|
23
29
|
```
|
|
24
30
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
2
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
31
|
+
## Ponytail Remediation Budget
|
|
32
|
+
- Additions: <= 5 lines
|
|
33
|
+
- Deletions: <= 2 lines
|
|
32
34
|
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
+
## Remediation
|
|
36
|
+
1. Avoid piping remote URLs directly into shell execution.
|
|
37
|
+
2. Download the installation script to a file and verify its SHA-256 checksum before execution.
|
|
38
|
+
3. Package dependencies through verified package managers (npm, pip, cargo, apt) rather than curl scripts.
|
|
35
39
|
|
|
36
40
|
## Related Rules
|
|
37
|
-
- TG-
|
|
41
|
+
- `TG-INPUT-004`: Command Injection via Shell Execution
|
|
42
|
+
- `TG-SUPPLY-004`: Unpinned CI Action
|
|
@@ -1,37 +1,57 @@
|
|
|
1
1
|
# TG-WEBHOOK-001: Missing Webhook Signature Verification
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
|
|
4
|
+
Critical. Webhook ingestion endpoints (Stripe, GitHub, Shopify) that process events without verifying HMAC cryptographic signatures allow external attackers to forge events (e.g. spoofing a `payment_intent.succeeded` event).
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- Webhook Listeners (Express, FastAPI, Django, Flask, Next.js)
|
|
8
|
+
- Node.js, Python, Go, Java, C#
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
Webhook endpoints are public HTTP endpoints. Without signature verification, anyone who discovers the webhook URL can send forged JSON payloads mimicking payment success, account activation, or repository merges.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- Public webhook routes (`/api/webhooks/stripe`, `/api/github-webhook`) that parse payloads without calling provider signature verification methods (`stripe.webhooks.constructEvent`, `crypto.createHmac`).
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Trusting incoming webhook payload without verifying signature
|
|
19
|
+
app.post('/api/webhook/stripe', express.json(), async (req, res) => {
|
|
20
|
+
const event = req.body;
|
|
21
|
+
if (event.type === 'payment_intent.succeeded') {
|
|
22
|
+
await fulfillOrder(event.data.object.metadata.orderId);
|
|
23
|
+
}
|
|
24
|
+
res.json({ received: true });
|
|
25
|
+
});
|
|
18
26
|
```
|
|
19
27
|
|
|
20
28
|
## Safe Example
|
|
21
29
|
```javascript
|
|
22
|
-
//
|
|
30
|
+
// SAFE: Verifying Stripe HMAC signature using raw request body
|
|
31
|
+
app.post('/api/webhook/stripe', express.raw({ type: 'application/json' }), (req, res) => {
|
|
32
|
+
const sig = req.headers['stripe-signature'];
|
|
33
|
+
let event;
|
|
34
|
+
try {
|
|
35
|
+
event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return res.status(400).send(`Webhook Error: ${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
if (event.type === 'payment_intent.succeeded') {
|
|
40
|
+
fulfillOrder(event.data.object.metadata.orderId);
|
|
41
|
+
}
|
|
42
|
+
res.json({ received: true });
|
|
43
|
+
});
|
|
23
44
|
```
|
|
24
45
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
46
|
+
## Ponytail Remediation Budget
|
|
47
|
+
- Additions: <= 12 lines
|
|
48
|
+
- Deletions: <= 4 lines
|
|
32
49
|
|
|
33
|
-
##
|
|
34
|
-
|
|
50
|
+
## Remediation
|
|
51
|
+
1. Use raw request body buffer for signature computation.
|
|
52
|
+
2. Verify signatures using provider SDKs or timing-safe HMAC comparison (`crypto.timingSafeEqual`).
|
|
53
|
+
3. Store webhook signing secrets in environment variables (`STRIPE_WEBHOOK_SECRET`).
|
|
35
54
|
|
|
36
55
|
## Related Rules
|
|
37
|
-
- TG-
|
|
56
|
+
- `TG-WEBHOOK-002`: Replayable Webhook Without Timestamp Validation
|
|
57
|
+
- `TG-WEBHOOK-003`: Missing Webhook Idempotency
|
|
@@ -1,37 +1,46 @@
|
|
|
1
|
-
# TG-WEBHOOK-002: Replayable Webhook
|
|
1
|
+
# TG-WEBHOOK-002: Replayable Webhook Without Timestamp Validation
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
|
|
4
|
+
Critical. Processing webhook events without verifying timestamp freshness allows an attacker with access to network logs to replay old captured webhook payloads to duplicate orders or events.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- Webhook Handlers (Stripe, Slack, Custom Webhooks)
|
|
8
|
+
- Node.js, Python, Go, Java
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
Even if an attacker cannot forge a cryptographic signature, they may be able to capture a valid signed request and replay it days later. Enforcing timestamp freshness (e.g. rejecting requests older than 5 minutes) neutralizes replay attacks.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- Custom signature validation routines that verify hashes but do not check timestamp tolerances.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Checking signature without timestamp tolerance check
|
|
19
|
+
function verifySignature(payload, signature, secret) {
|
|
20
|
+
const expected = crypto.createHmac('sha256', secret).update(payload).digest('hex');
|
|
21
|
+
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
22
|
+
}
|
|
18
23
|
```
|
|
19
24
|
|
|
20
25
|
## Safe Example
|
|
21
26
|
```javascript
|
|
22
|
-
//
|
|
27
|
+
// SAFE: Asserting timestamp freshness within a 5-minute tolerance window
|
|
28
|
+
function verifySignature(payload, signature, timestamp, secret) {
|
|
29
|
+
const now = Math.floor(Date.now() / 1000);
|
|
30
|
+
if (Math.abs(now - Number(timestamp)) > 300) return false; // 5-minute tolerance
|
|
31
|
+
const expected = crypto.createHmac('sha256', secret).update(`${timestamp}.${payload}`).digest('hex');
|
|
32
|
+
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
33
|
+
}
|
|
23
34
|
```
|
|
24
35
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
2
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
36
|
+
## Ponytail Remediation Budget
|
|
37
|
+
- Additions: <= 6 lines
|
|
38
|
+
- Deletions: <= 2 lines
|
|
32
39
|
|
|
33
|
-
##
|
|
34
|
-
|
|
40
|
+
## Remediation
|
|
41
|
+
1. Include timestamp in signature computation payload (`${timestamp}.${payload}`).
|
|
42
|
+
2. Verify that timestamp is within a 300-second window of current server time.
|
|
35
43
|
|
|
36
44
|
## Related Rules
|
|
37
|
-
- TG-
|
|
45
|
+
- `TG-WEBHOOK-001`: Missing Webhook Signature Verification
|
|
46
|
+
- `TG-WEBHOOK-003`: Missing Webhook Idempotency
|
package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md
CHANGED
|
@@ -1,37 +1,51 @@
|
|
|
1
1
|
# TG-WEBHOOK-003: Missing Webhook Idempotency
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
High
|
|
4
|
+
High. Processing incoming webhook events without recording event IDs allows duplicate webhook delivery to trigger duplicate fulfillments, charges, or database entries.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- Webhook Event Handlers
|
|
8
|
+
- Node.js, Python, Go, Java, C#
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
Webhook providers (Stripe, GitHub, PayPal) employ retry mechanisms and guarantee *at-least-once* delivery. If a network blip causes your server to respond slowly, the provider resends the webhook. Without idempotency checks, actions execute multiple times.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- Event handlers executing side-effects immediately without checking if `event.id` was already processed.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Handling event without deduplicating by event ID
|
|
19
|
+
app.post('/api/webhook', async (req, res) => {
|
|
20
|
+
const event = req.event;
|
|
21
|
+
await creditUserAccount(event.userId, event.amount); // Executed on every retry
|
|
22
|
+
res.sendStatus(200);
|
|
23
|
+
});
|
|
18
24
|
```
|
|
19
25
|
|
|
20
26
|
## Safe Example
|
|
21
27
|
```javascript
|
|
22
|
-
//
|
|
28
|
+
// SAFE: Recording processed event IDs to guarantee idempotency
|
|
29
|
+
app.post('/api/webhook', async (req, res) => {
|
|
30
|
+
const event = req.event;
|
|
31
|
+
const exists = await db.processedEvent.findUnique({ where: { id: event.id } });
|
|
32
|
+
if (exists) return res.status(200).json({ status: 'already_processed' });
|
|
33
|
+
await db.$transaction([
|
|
34
|
+
db.processedEvent.create({ data: { id: event.id } }),
|
|
35
|
+
creditUserAccount(event.userId, event.amount)
|
|
36
|
+
]);
|
|
37
|
+
res.sendStatus(200);
|
|
38
|
+
});
|
|
23
39
|
```
|
|
24
40
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
41
|
+
## Ponytail Remediation Budget
|
|
42
|
+
- Additions: <= 8 lines
|
|
43
|
+
- Deletions: <= 3 lines
|
|
32
44
|
|
|
33
|
-
##
|
|
34
|
-
|
|
45
|
+
## Remediation
|
|
46
|
+
1. Store processed event IDs in a persistent table with unique constraints.
|
|
47
|
+
2. Return 200 OK immediately if an event ID has already been recorded.
|
|
35
48
|
|
|
36
49
|
## Related Rules
|
|
37
|
-
- TG-
|
|
50
|
+
- `TG-BIZ-002`: Replayable One-Time Operation
|
|
51
|
+
- `TG-WEBHOOK-001`: Missing Webhook Signature Verification
|
package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md
CHANGED
|
@@ -1,37 +1,46 @@
|
|
|
1
1
|
# TG-WEBHOOK-004: Unvalidated Webhook Event Type
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
High
|
|
4
|
+
High. Dynamically dispatching webhook handlers using unsanitized `event.type` strings from payloads can lead to object prototype pollution, unintended method invocation, or unhandled exceptions.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- Dynamic Webhook Event Dispatchers
|
|
8
|
+
- Node.js, Python, Ruby
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
Using `handlers[event.type](event)` where `event.type` is controlled by the payload allows attackers to invoke object prototype properties like `toString`, `constructor`, or `__proto__`, causing crashes or prototype pollution.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- Bracket indexing into handler objects with untrusted event type strings without allowlist validation.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Dynamic object lookup using unsanitized event.type
|
|
19
|
+
const handlers = { 'order.created': handleOrder };
|
|
20
|
+
app.post('/webhook', (req, res) => {
|
|
21
|
+
handlers[req.body.type](req.body); // Attacker passes type: '__proto__' or 'constructor'
|
|
22
|
+
});
|
|
18
23
|
```
|
|
19
24
|
|
|
20
25
|
## Safe Example
|
|
21
26
|
```javascript
|
|
22
|
-
//
|
|
27
|
+
// SAFE: Explicit switch-case or Object.hasOwn allowlist validation
|
|
28
|
+
const ALLOWED_TYPES = new Set(['order.created', 'order.refunded']);
|
|
29
|
+
app.post('/webhook', (req, res) => {
|
|
30
|
+
const { type } = req.body;
|
|
31
|
+
if (!ALLOWED_TYPES.has(type)) return res.status(400).json({ error: 'Unsupported event type' });
|
|
32
|
+
if (type === 'order.created') handleOrder(req.body);
|
|
33
|
+
});
|
|
23
34
|
```
|
|
24
35
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
2
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
36
|
+
## Ponytail Remediation Budget
|
|
37
|
+
- Additions: <= 6 lines
|
|
38
|
+
- Deletions: <= 2 lines
|
|
32
39
|
|
|
33
|
-
##
|
|
34
|
-
|
|
40
|
+
## Remediation
|
|
41
|
+
1. Validate event types against an explicit `Set` or `switch` statement.
|
|
42
|
+
2. Never dynamically execute object methods via unvetted user-controlled keys.
|
|
35
43
|
|
|
36
44
|
## Related Rules
|
|
37
|
-
- TG-
|
|
45
|
+
- `TG-WEBHOOK-001`: Missing Webhook Signature Verification
|
|
46
|
+
- `TG-INPUT-001`: Missing Server-Side Request Validation
|
package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md
CHANGED
|
@@ -1,37 +1,48 @@
|
|
|
1
|
-
# TG-WS-002: Missing Channel-Level Authorization
|
|
1
|
+
# TG-WS-002: Missing Channel-Level WebSocket Authorization
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
|
|
4
|
+
Critical. Allowing WebSocket clients to subscribe to rooms, topics, or channels (`socket.join(...)`) without verifying that the client has permission to view that channel leaks real-time private messages across tenants.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- Real-Time Sockets (Socket.io, ws, ActionCable, Django Channels)
|
|
8
|
+
- Node.js, Python, Go
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
In real-time chat or multi-tenant collaboration applications, joining a room grants immediate broadcast reception. If a client can emit `join_room("tenant_123_finance")` and the server joins them without verifying membership, all private room broadcasts leak.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- Socket event listeners (`socket.on('join')`) that join rooms based on client input without permissions checks.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Joining channel directly from client parameter without auth check
|
|
19
|
+
io.on('connection', (socket) => {
|
|
20
|
+
socket.on('join_channel', (channelId) => {
|
|
21
|
+
socket.join(channelId); // Attacker joins other tenants' private channels
|
|
22
|
+
});
|
|
23
|
+
});
|
|
18
24
|
```
|
|
19
25
|
|
|
20
26
|
## Safe Example
|
|
21
27
|
```javascript
|
|
22
|
-
//
|
|
28
|
+
// SAFE: Verifying tenant membership before allowing channel join
|
|
29
|
+
io.on('connection', (socket) => {
|
|
30
|
+
socket.on('join_channel', async (channelId) => {
|
|
31
|
+
const isMember = await checkChannelAccess(socket.data.user.id, channelId);
|
|
32
|
+
if (!isMember) return socket.emit('error', 'Unauthorized channel access');
|
|
33
|
+
socket.join(channelId);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
23
36
|
```
|
|
24
37
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
2
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
38
|
+
## Ponytail Remediation Budget
|
|
39
|
+
- Additions: <= 6 lines
|
|
40
|
+
- Deletions: <= 2 lines
|
|
32
41
|
|
|
33
|
-
##
|
|
34
|
-
|
|
42
|
+
## Remediation
|
|
43
|
+
1. Attach authenticated user session data to the socket during handshake (`socket.data.user`).
|
|
44
|
+
2. Verify user channel membership against database before calling `socket.join(channelId)`.
|
|
35
45
|
|
|
36
46
|
## Related Rules
|
|
37
|
-
- TG-
|
|
47
|
+
- `TG-WS-001`: Unauthenticated WebSocket Handshake
|
|
48
|
+
- `TG-DB-004`: Missing Multi-Tenant Query Isolation
|
package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md
CHANGED
|
@@ -1,37 +1,51 @@
|
|
|
1
|
-
# TG-WS-003: Unvalidated WebSocket Message
|
|
1
|
+
# TG-WS-003: Unvalidated WebSocket Message Payload
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
High
|
|
4
|
+
High. Ingesting and processing incoming WebSocket message frames without schema validation or input sanitization exposes real-time backend handlers to SQL injection, XSS broadcasting, and command execution.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- WebSocket Message Handlers (Socket.io, ws, native WebSockets)
|
|
8
|
+
- Node.js, Python, Go
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
Unlike HTTP routes which typically have middleware validation (Zod, Joi, Pydantic), WebSocket messages frequently bypass standard middleware pipelines and pass raw client JSON directly into database queries or broadcast sinks.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- WebSocket message event handlers directly consuming message payloads without validation schemas.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Consuming raw WebSocket message without schema validation
|
|
19
|
+
socket.on('send_message', async (data) => {
|
|
20
|
+
await db.message.create({ data: { text: data.text, room: data.room } });
|
|
21
|
+
io.to(data.room).emit('new_message', data);
|
|
22
|
+
});
|
|
18
23
|
```
|
|
19
24
|
|
|
20
25
|
## Safe Example
|
|
21
26
|
```javascript
|
|
22
|
-
//
|
|
27
|
+
// SAFE: Validating WebSocket payload with Zod schema before processing
|
|
28
|
+
const MessageSchema = z.object({
|
|
29
|
+
text: z.string().min(1).max(2000),
|
|
30
|
+
room: z.string().uuid()
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
socket.on('send_message', async (rawData) => {
|
|
34
|
+
const result = MessageSchema.safeParse(rawData);
|
|
35
|
+
if (!result.success) return socket.emit('error', 'Invalid payload schema');
|
|
36
|
+
await db.message.create({ data: result.data });
|
|
37
|
+
io.to(result.data.room).emit('new_message', result.data);
|
|
38
|
+
});
|
|
23
39
|
```
|
|
24
40
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
2
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
41
|
+
## Ponytail Remediation Budget
|
|
42
|
+
- Additions: <= 8 lines
|
|
43
|
+
- Deletions: <= 2 lines
|
|
32
44
|
|
|
33
|
-
##
|
|
34
|
-
|
|
45
|
+
## Remediation
|
|
46
|
+
1. Enforce validation schemas (Zod, Pydantic) on all incoming WebSocket message handlers.
|
|
47
|
+
2. Sanitize text fields before broadcasting to other connected clients.
|
|
35
48
|
|
|
36
49
|
## Related Rules
|
|
37
|
-
- TG-
|
|
50
|
+
- `TG-INPUT-001`: Missing Server-Side Request Validation
|
|
51
|
+
- `TG-INPUT-003`: Unsafe Dynamic Code or HTML Execution
|
package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md
CHANGED
|
@@ -1,37 +1,51 @@
|
|
|
1
|
-
# TG-WS-004: Unbounded WebSocket Connections
|
|
1
|
+
# TG-WS-004: Unbounded WebSocket Connections & Rate Limiting
|
|
2
2
|
|
|
3
3
|
## Severity
|
|
4
|
-
|
|
4
|
+
Medium. Permitting unlimited concurrent WebSocket connections per IP address or user allows attackers to exhaust file descriptors, socket memory pools, and server CPU via connection flood attacks.
|
|
5
5
|
|
|
6
6
|
## Applies To
|
|
7
|
-
-
|
|
7
|
+
- WebSocket Servers (ws, Socket.io, Django Channels, Gorilla WebSocket)
|
|
8
|
+
- Node.js, Python, Go
|
|
8
9
|
|
|
9
10
|
## Why It Matters
|
|
10
|
-
|
|
11
|
+
WebSocket connections are persistent TCP connections that remain open. Without connection throttling or message rate limits, a single client can open 10,000 idle sockets, consuming all available file descriptors and denying service to legitimate users.
|
|
11
12
|
|
|
12
13
|
## What TorusGuard Looks For
|
|
13
|
-
-
|
|
14
|
+
- WebSocket server configurations lacking maximum connection limits, per-IP socket caps, or message throttling.
|
|
14
15
|
|
|
15
16
|
## Unsafe Example
|
|
16
17
|
```javascript
|
|
17
|
-
//
|
|
18
|
+
// UNSAFE: Accepting unbounded WebSocket connections without rate limiting
|
|
19
|
+
const wss = new WebSocketServer({ port: 8080 });
|
|
18
20
|
```
|
|
19
21
|
|
|
20
22
|
## Safe Example
|
|
21
23
|
```javascript
|
|
22
|
-
//
|
|
24
|
+
// SAFE: Enforcing per-IP connection limits and message rate bounds
|
|
25
|
+
const ipConnections = new Map();
|
|
26
|
+
const MAX_CONNS_PER_IP = 10;
|
|
27
|
+
|
|
28
|
+
server.on('upgrade', (req, socket, head) => {
|
|
29
|
+
const ip = req.socket.remoteAddress;
|
|
30
|
+
const count = ipConnections.get(ip) || 0;
|
|
31
|
+
if (count >= MAX_CONNS_PER_IP) {
|
|
32
|
+
socket.destroy();
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
ipConnections.set(ip, count + 1);
|
|
36
|
+
socket.on('close', () => ipConnections.set(ip, Math.max(0, (ipConnections.get(ip) || 1) - 1)));
|
|
37
|
+
});
|
|
23
38
|
```
|
|
24
39
|
|
|
25
|
-
## Remediation
|
|
26
|
-
|
|
27
|
-
2
|
|
28
|
-
|
|
29
|
-
## Verification
|
|
30
|
-
- Test case 1
|
|
31
|
-
- Test case 2
|
|
40
|
+
## Ponytail Remediation Budget
|
|
41
|
+
- Additions: <= 10 lines
|
|
42
|
+
- Deletions: <= 2 lines
|
|
32
43
|
|
|
33
|
-
##
|
|
34
|
-
|
|
44
|
+
## Remediation
|
|
45
|
+
1. Enforce per-IP connection limits in the HTTP `upgrade` request listener.
|
|
46
|
+
2. Implement heartbeat ping/pong timeouts to terminate dead or idle sockets.
|
|
47
|
+
3. Throttle inbound message rates using token bucket or sliding window algorithms.
|
|
35
48
|
|
|
36
49
|
## Related Rules
|
|
37
|
-
- TG-
|
|
50
|
+
- `TG-RATE-003`: Unbounded Resource Consumption
|
|
51
|
+
- `TG-WS-001`: Unauthenticated WebSocket Handshake
|