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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-platform-002-17-876973",
|
|
3
|
+
"finding_id": "TG-PLATFORM-002-1f383dcf",
|
|
4
|
+
"rule_id": "TG-PLATFORM-002",
|
|
5
|
+
"title": "Missing Security Headers",
|
|
6
|
+
"target_file": "examples/hardened-react-express/server/index.js",
|
|
7
|
+
"line_number": 17,
|
|
8
|
+
"target_line": "const app = express();",
|
|
9
|
+
"replacement_line": "const helmet = require(\"helmet\");\nconst app = express();\napp.use(helmet());",
|
|
10
|
+
"what_is_wrong": "Express application initialized without helmet security headers middleware",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Injected helmet security headers middleware into Express application",
|
|
13
|
+
"proposed_diff": "--- a/examples/hardened-react-express/server/index.js\n+++ b/examples/hardened-react-express/server/index.js\n@@ -15,5 +15,5 @@\n }\n \n-const app = express();\n+const helmet = require(\"helmet\");\nconst app = express();\napp.use(helmet());\n const PORT = 3001;\n const isProd = process.env.NODE_ENV === 'production';\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 helmet = require(\"helmet\");\nconst app = express();\napp.use(helmet());\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,23 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-platform-002-17-876973
|
|
2
|
+
- **Rule ID:** `TG-PLATFORM-002`
|
|
3
|
+
- **Target File:** `examples/hardened-react-express/server/index.js:17`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Injected helmet security headers middleware into Express application
|
|
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
|
+
@@ -15,5 +15,5 @@
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
-const app = express();
|
|
17
|
+
+const helmet = require("helmet");
|
|
18
|
+
const app = express();
|
|
19
|
+
app.use(helmet());
|
|
20
|
+
const PORT = 3001;
|
|
21
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
22
|
+
|
|
23
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-17-876973/patch.diff
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
--- a/examples/hardened-react-express/server/index.js
|
|
2
|
+
+++ b/examples/hardened-react-express/server/index.js
|
|
3
|
+
@@ -15,5 +15,5 @@
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
-const app = express();
|
|
7
|
+
+const helmet = require("helmet");
|
|
8
|
+
const app = express();
|
|
9
|
+
app.use(helmet());
|
|
10
|
+
const PORT = 3001;
|
|
11
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-platform-002-5-40c794",
|
|
3
|
+
"finding_id": "TG-PLATFORM-002-eef342ec",
|
|
4
|
+
"rule_id": "TG-PLATFORM-002",
|
|
5
|
+
"title": "Missing Security Headers",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 5,
|
|
8
|
+
"target_line": "const app = express();",
|
|
9
|
+
"replacement_line": "const helmet = require(\"helmet\");\nconst app = express();\napp.use(helmet());",
|
|
10
|
+
"what_is_wrong": "Express application initialized without helmet security headers middleware",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Injected helmet security headers middleware into Express application",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -3,5 +3,5 @@\n const jwt = require('jsonwebtoken');\n \n-const app = express();\n+const helmet = require(\"helmet\");\nconst app = express();\napp.use(helmet());\n const PORT = 3001;\n \n",
|
|
14
|
+
"additions": 1,
|
|
15
|
+
"deletions": 1,
|
|
16
|
+
"patched_content": "const express = require('express');\nconst cors = require('cors');\nconst jwt = require('jsonwebtoken');\n\nconst helmet = require(\"helmet\");\nconst app = express();\napp.use(helmet());\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', (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,23 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-platform-002-5-40c794
|
|
2
|
+
- **Rule ID:** `TG-PLATFORM-002`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:5`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Injected helmet security headers middleware into Express application
|
|
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
|
+
@@ -3,5 +3,5 @@
|
|
14
|
+
const jwt = require('jsonwebtoken');
|
|
15
|
+
|
|
16
|
+
-const app = express();
|
|
17
|
+
+const helmet = require("helmet");
|
|
18
|
+
const app = express();
|
|
19
|
+
app.use(helmet());
|
|
20
|
+
const PORT = 3001;
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-platform-002-5-40c794/patch.diff
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
--- a/examples/vulnerable-react-express/server/index.js
|
|
2
|
+
+++ b/examples/vulnerable-react-express/server/index.js
|
|
3
|
+
@@ -3,5 +3,5 @@
|
|
4
|
+
const jwt = require('jsonwebtoken');
|
|
5
|
+
|
|
6
|
+
-const app = express();
|
|
7
|
+
+const helmet = require("helmet");
|
|
8
|
+
const app = express();
|
|
9
|
+
app.use(helmet());
|
|
10
|
+
const PORT = 3001;
|
|
11
|
+
|
package/.torusguard/runs/run-20260912-215731-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
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-rate-001-26-affcfa
|
|
2
|
+
- **Rule ID:** `TG-RATE-001`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:26`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Injected authLimiter rate-limiting middleware to protect authentication endpoint from brute force
|
|
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
|
+
@@ -24,5 +24,5 @@
|
|
14
|
+
// TG-SEC-004: Logs sensitive data
|
|
15
|
+
// TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)
|
|
16
|
+
-app.post('/api/login', (req, res) => {
|
|
17
|
+
+app.post('/api/login', authLimiter, (req, res) => {
|
|
18
|
+
const { email, password } = req.body;
|
|
19
|
+
console.log('Login attempt:', { email, password }); // TG-SEC-004
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-001-26-affcfa/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
|
+
@@ -24,5 +24,5 @@
|
|
4
|
+
// TG-SEC-004: Logs sensitive data
|
|
5
|
+
// TG-AUTH-004: Insecure cookie (no httpOnly/Secure/SameSite)
|
|
6
|
+
-app.post('/api/login', (req, res) => {
|
|
7
|
+
+app.post('/api/login', authLimiter, (req, res) => {
|
|
8
|
+
const { email, password } = req.body;
|
|
9
|
+
console.log('Login attempt:', { email, password }); // TG-SEC-004
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-002-54-0b38d2/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-rate-002-54-0b38d2",
|
|
3
|
+
"finding_id": "TG-RATE-002-d67d7c98",
|
|
4
|
+
"rule_id": "TG-RATE-002",
|
|
5
|
+
"title": "Unlimited Public Write Endpoint",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 54,
|
|
8
|
+
"target_line": "app.post('/api/contact', (req, res) => {",
|
|
9
|
+
"replacement_line": "app.post('/api/contact', writeLimiter, (req, res) => {",
|
|
10
|
+
"what_is_wrong": "Public submission endpoint defined without rate-limiting or captcha defense",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Injected writeLimiter rate-limiting middleware to public write endpoint",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -52,5 +52,5 @@\n // TG-INPUT-001: No validation\n // TG-RATE-002: Unlimited contact endpoint\n-app.post('/api/contact', (req, res) => {\n+app.post('/api/contact', writeLimiter, (req, res) => {\n res.json({ received: req.body });\n });\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', (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', writeLimiter, (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-rate-002-54-0b38d2
|
|
2
|
+
- **Rule ID:** `TG-RATE-002`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:54`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Injected writeLimiter rate-limiting middleware to public write endpoint
|
|
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
|
+
@@ -52,5 +52,5 @@
|
|
14
|
+
// TG-INPUT-001: No validation
|
|
15
|
+
// TG-RATE-002: Unlimited contact endpoint
|
|
16
|
+
-app.post('/api/contact', (req, res) => {
|
|
17
|
+
+app.post('/api/contact', writeLimiter, (req, res) => {
|
|
18
|
+
res.json({ received: req.body });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-rate-002-54-0b38d2/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
|
+
@@ -52,5 +52,5 @@
|
|
4
|
+
// TG-INPUT-001: No validation
|
|
5
|
+
// TG-RATE-002: Unlimited contact endpoint
|
|
6
|
+
-app.post('/api/contact', (req, res) => {
|
|
7
|
+
+app.post('/api/contact', writeLimiter, (req, res) => {
|
|
8
|
+
res.json({ received: req.body });
|
|
9
|
+
});
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-18-a3c1e8/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-sec-001-18-a3c1e8",
|
|
3
|
+
"finding_id": "TG-SEC-001-c393d596",
|
|
4
|
+
"rule_id": "TG-SEC-001",
|
|
5
|
+
"title": "Hardcoded Secret or API Key in Tracked Source",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 18,
|
|
8
|
+
"target_line": " { id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },",
|
|
9
|
+
"replacement_line": " { id: '1', email: 'alice@demo.local', password: process.env.DEMO_USER_PASSWORD || \"REDACTED_PASSWORD\", name: 'Alice' },",
|
|
10
|
+
"what_is_wrong": "Hardcoded credential or API secret string",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Replaced hardcoded password with environment variable process.env.DEMO_USER_PASSWORD",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -16,5 +16,5 @@\n \n const users = [\n- { id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },\n+ { id: '1', email: 'alice@demo.local', password: process.env.DEMO_USER_PASSWORD || \"REDACTED_PASSWORD\", name: 'Alice' },\n { id: '2', email: 'bob@demo.local', password: 'secret456', name: 'Bob' },\n ];\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: process.env.DEMO_USER_PASSWORD || \"REDACTED_PASSWORD\", 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-sec-001-18-a3c1e8
|
|
2
|
+
- **Rule ID:** `TG-SEC-001`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:18`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Replaced hardcoded password with environment variable process.env.DEMO_USER_PASSWORD
|
|
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
|
+
@@ -16,5 +16,5 @@
|
|
14
|
+
|
|
15
|
+
const users = [
|
|
16
|
+
- { id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },
|
|
17
|
+
+ { id: '1', email: 'alice@demo.local', password: process.env.DEMO_USER_PASSWORD || "REDACTED_PASSWORD", name: 'Alice' },
|
|
18
|
+
{ id: '2', email: 'bob@demo.local', password: 'secret456', name: 'Bob' },
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-18-a3c1e8/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
|
+
@@ -16,5 +16,5 @@
|
|
4
|
+
|
|
5
|
+
const users = [
|
|
6
|
+
- { id: '1', email: 'alice@demo.local', password: 'password123', name: 'Alice' },
|
|
7
|
+
+ { id: '1', email: 'alice@demo.local', password: process.env.DEMO_USER_PASSWORD || "REDACTED_PASSWORD", name: 'Alice' },
|
|
8
|
+
{ id: '2', email: 'bob@demo.local', password: 'secret456', name: 'Bob' },
|
|
9
|
+
];
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-001-9-e22e50/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-sec-001-9-e22e50",
|
|
3
|
+
"finding_id": "TG-SEC-001-bb5e4b77",
|
|
4
|
+
"rule_id": "TG-SEC-001",
|
|
5
|
+
"title": "Hardcoded Secret or API Key in Tracked Source",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 9,
|
|
8
|
+
"target_line": "const JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';",
|
|
9
|
+
"replacement_line": "const JWT_SECRET = process.env.JWT_SECRET || \"\";",
|
|
10
|
+
"what_is_wrong": "Hardcoded JWT signing secret",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Migrated hardcoded JWT secret to environment variable process.env.JWT_SECRET",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -7,5 +7,5 @@\n \n // TG-SEC-001: Hardcoded JWT secret\n-const JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';\n+const JWT_SECRET = process.env.JWT_SECRET || \"\";\n \n // TG-PLATFORM-001: Wildcard CORS with credentials\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 = process.env.JWT_SECRET || \"\";\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', (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-sec-001-9-e22e50
|
|
2
|
+
- **Rule ID:** `TG-SEC-001`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:9`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Migrated hardcoded JWT secret to environment variable process.env.JWT_SECRET
|
|
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
|
+
@@ -7,5 +7,5 @@
|
|
14
|
+
|
|
15
|
+
// TG-SEC-001: Hardcoded JWT secret
|
|
16
|
+
-const JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';
|
|
17
|
+
+const JWT_SECRET = process.env.JWT_SECRET || "";
|
|
18
|
+
|
|
19
|
+
// TG-PLATFORM-001: Wildcard CORS with credentials
|
|
20
|
+
|
|
21
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
--- a/examples/vulnerable-react-express/server/index.js
|
|
2
|
+
+++ b/examples/vulnerable-react-express/server/index.js
|
|
3
|
+
@@ -7,5 +7,5 @@
|
|
4
|
+
|
|
5
|
+
// TG-SEC-001: Hardcoded JWT secret
|
|
6
|
+
-const JWT_SECRET = 'FAKE_DEMO_JWT_SECRET_NOT_FOR_PRODUCTION';
|
|
7
|
+
+const JWT_SECRET = process.env.JWT_SECRET || "";
|
|
8
|
+
|
|
9
|
+
// TG-PLATFORM-001: Wildcard CORS with credentials
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-28-a1a0a1/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-sec-004-28-a1a0a1",
|
|
3
|
+
"finding_id": "TG-SEC-004-08753da5",
|
|
4
|
+
"rule_id": "TG-SEC-004",
|
|
5
|
+
"title": "Sensitive Information in Logs",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/server/index.js",
|
|
7
|
+
"line_number": 28,
|
|
8
|
+
"target_line": " console.log('Login attempt:', { email, password }); // TG-SEC-004",
|
|
9
|
+
"replacement_line": " // Security: Sensitive credential log removed per TG-SEC-004",
|
|
10
|
+
"what_is_wrong": "Plaintext credential or token logged to output sink",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Redacted console logging of sensitive token or credential",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/server/index.js\n+++ b/examples/vulnerable-react-express/server/index.js\n@@ -26,5 +26,5 @@\n app.post('/api/login', (req, res) => {\n const { email, password } = req.body;\n- console.log('Login attempt:', { email, password }); // TG-SEC-004\n+ // Security: Sensitive credential log removed per 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",
|
|
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', (req, res) => {\n const { email, password } = req.body;\n // Security: Sensitive credential log removed per 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-sec-004-28-a1a0a1
|
|
2
|
+
- **Rule ID:** `TG-SEC-004`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/server/index.js:28`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Redacted console logging of sensitive token or credential
|
|
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
|
+
@@ -26,5 +26,5 @@
|
|
14
|
+
app.post('/api/login', (req, res) => {
|
|
15
|
+
const { email, password } = req.body;
|
|
16
|
+
- console.log('Login attempt:', { email, password }); // TG-SEC-004
|
|
17
|
+
+ // Security: Sensitive credential log removed per TG-SEC-004
|
|
18
|
+
const user = users.find((u) => u.email === email && u.password === password);
|
|
19
|
+
if (!user) return res.status(401).json({ error: 'User not found' }); // enumeration
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-28-a1a0a1/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
|
+
@@ -26,5 +26,5 @@
|
|
4
|
+
app.post('/api/login', (req, res) => {
|
|
5
|
+
const { email, password } = req.body;
|
|
6
|
+
- console.log('Login attempt:', { email, password }); // TG-SEC-004
|
|
7
|
+
+ // Security: Sensitive credential log removed per TG-SEC-004
|
|
8
|
+
const user = users.find((u) => u.email === email && u.password === password);
|
|
9
|
+
if (!user) return res.status(401).json({ error: 'User not found' }); // enumeration
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-30-00569e/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-sec-004-30-00569e",
|
|
3
|
+
"finding_id": "TG-SEC-004-dbbc17f7",
|
|
4
|
+
"rule_id": "TG-SEC-004",
|
|
5
|
+
"title": "Sensitive Information in Logs",
|
|
6
|
+
"target_file": "examples/vulnerable-react-express/client/src/App.jsx",
|
|
7
|
+
"line_number": 30,
|
|
8
|
+
"target_line": " console.log('Login token:', data.token, 'config:', clientConfig);",
|
|
9
|
+
"replacement_line": " // Security: Sensitive credential log removed per TG-SEC-004",
|
|
10
|
+
"what_is_wrong": "Plaintext credential or token logged to output sink",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Redacted console logging of sensitive token or credential",
|
|
13
|
+
"proposed_diff": "--- a/examples/vulnerable-react-express/client/src/App.jsx\n+++ b/examples/vulnerable-react-express/client/src/App.jsx\n@@ -28,5 +28,5 @@\n const data = await res.json();\n // TG-CLIENT-002: Sensitive console logging\n- console.log('Login token:', data.token, 'config:', clientConfig);\n+ // Security: Sensitive credential log removed per TG-SEC-004\n setMessage(JSON.stringify(data));\n }\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 // Security: Sensitive credential log removed per TG-SEC-004\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 dangerouslySetInnerHTML={{ __html: bio }} />\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-sec-004-30-00569e
|
|
2
|
+
- **Rule ID:** `TG-SEC-004`
|
|
3
|
+
- **Target File:** `examples/vulnerable-react-express/client/src/App.jsx:30`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Redacted console logging of sensitive token or credential
|
|
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
|
+
@@ -28,5 +28,5 @@
|
|
14
|
+
const data = await res.json();
|
|
15
|
+
// TG-CLIENT-002: Sensitive console logging
|
|
16
|
+
- console.log('Login token:', data.token, 'config:', clientConfig);
|
|
17
|
+
+ // Security: Sensitive credential log removed per TG-SEC-004
|
|
18
|
+
setMessage(JSON.stringify(data));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-sec-004-30-00569e/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
|
+
@@ -28,5 +28,5 @@
|
|
4
|
+
const data = await res.json();
|
|
5
|
+
// TG-CLIENT-002: Sensitive console logging
|
|
6
|
+
- console.log('Login token:', data.token, 'config:', clientConfig);
|
|
7
|
+
+ // Security: Sensitive credential log removed per TG-SEC-004
|
|
8
|
+
setMessage(JSON.stringify(data));
|
|
9
|
+
}
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-ssrf-004-9-9803ad/metadata.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bundle_id": "bnd-tg-ssrf-004-9-9803ad",
|
|
3
|
+
"finding_id": "TG-SSRF-004-d8472223",
|
|
4
|
+
"rule_id": "TG-SSRF-004",
|
|
5
|
+
"title": "Unbounded Outbound Request Without Timeout",
|
|
6
|
+
"target_file": "examples/python/fastapi-vuln/main.py",
|
|
7
|
+
"line_number": 9,
|
|
8
|
+
"target_line": " response = requests.get(url)",
|
|
9
|
+
"replacement_line": " response = requests.get(url, timeout=10)",
|
|
10
|
+
"what_is_wrong": "Python requests call without explicit timeout parameter",
|
|
11
|
+
"why_it_matters": "Security vulnerability violating TorusGuard strict production safety invariant.",
|
|
12
|
+
"what_should_change": "Injected explicit 10-second request timeout to prevent resource exhaustion",
|
|
13
|
+
"proposed_diff": "--- a/examples/python/fastapi-vuln/main.py\n+++ b/examples/python/fastapi-vuln/main.py\n@@ -7,5 +7,5 @@\n @app.get(\"/fetch\")\n def fetch_url(url: str):\n- response = requests.get(url)\n+ response = requests.get(url, timeout=10)\n return {\"status\": response.status_code, \"content\": response.text}\n \n",
|
|
14
|
+
"additions": 1,
|
|
15
|
+
"deletions": 1,
|
|
16
|
+
"patched_content": "from fastapi import FastAPI\nimport requests\n\napp = FastAPI()\n\n# \u274c TG-SSRF-001: Unvalidated outbound URL fetching\n@app.get(\"/fetch\")\ndef fetch_url(url: str):\n response = requests.get(url, timeout=10)\n return {\"status\": response.status_code, \"content\": response.text}\n\n# \u274c TG-WEBHOOK-001: Unverified webhook payload\n@app.post(\"/webhook\")\ndef receive_webhook(payload: dict):\n return {\"status\": \"success\", \"data\": payload}\n\n# \u274c TG-AUTH-006: Unfiltered dict mass assignment\n@app.post(\"/update_profile\")\ndef update_profile(user_id: int, updates: dict):\n return {\"status\": \"updated\", \"user_id\": user_id, \"updates\": updates}"
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Remediation Plan: bnd-tg-ssrf-004-9-9803ad
|
|
2
|
+
- **Rule ID:** `TG-SSRF-004`
|
|
3
|
+
- **Target File:** `examples/python/fastapi-vuln/main.py:9`
|
|
4
|
+
- **Ponytail Churn:** `+1 / -1` (Compliant <=35/<=25)
|
|
5
|
+
|
|
6
|
+
## Proposed Change
|
|
7
|
+
Injected explicit 10-second request timeout to prevent resource exhaustion
|
|
8
|
+
|
|
9
|
+
## Unified Diff Preview
|
|
10
|
+
```diff
|
|
11
|
+
--- a/examples/python/fastapi-vuln/main.py
|
|
12
|
+
+++ b/examples/python/fastapi-vuln/main.py
|
|
13
|
+
@@ -7,5 +7,5 @@
|
|
14
|
+
@app.get("/fetch")
|
|
15
|
+
def fetch_url(url: str):
|
|
16
|
+
- response = requests.get(url)
|
|
17
|
+
+ response = requests.get(url, timeout=10)
|
|
18
|
+
return {"status": response.status_code, "content": response.text}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
```
|
package/.torusguard/runs/run-20260912-215731-audit/bundles/bnd-tg-ssrf-004-9-9803ad/patch.diff
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
--- a/examples/python/fastapi-vuln/main.py
|
|
2
|
+
+++ b/examples/python/fastapi-vuln/main.py
|
|
3
|
+
@@ -7,5 +7,5 @@
|
|
4
|
+
@app.get("/fetch")
|
|
5
|
+
def fetch_url(url: str):
|
|
6
|
+
- response = requests.get(url)
|
|
7
|
+
+ response = requests.get(url, timeout=10)
|
|
8
|
+
return {"status": response.status_code, "content": response.text}
|
|
9
|
+
|