torusguard 1.3.0 → 1.3.1

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.
Files changed (377) hide show
  1. package/.torusguard/.manifest.json +112 -8
  2. package/.torusguard/rules/README.md +93 -62
  3. package/.torusguard/rules/TG-AUTH-001-weak-password-storage.md +103 -0
  4. package/.torusguard/rules/TG-AUTH-002-client-only-authorization.md +85 -0
  5. package/.torusguard/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
  6. package/.torusguard/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
  7. package/.torusguard/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
  8. package/.torusguard/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
  9. package/.torusguard/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  10. package/.torusguard/rules/TG-DB-001-frontend-database-query.md +83 -0
  11. package/.torusguard/rules/TG-DB-002-privileged-database-credential.md +86 -0
  12. package/.torusguard/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
  13. package/.torusguard/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  14. package/.torusguard/rules/TG-INPUT-001-missing-server-validation.md +98 -0
  15. package/.torusguard/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  16. package/.torusguard/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  17. package/.torusguard/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  18. package/.torusguard/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  19. package/.torusguard/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  20. package/.torusguard/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  21. package/.torusguard/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
  22. package/.torusguard/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  23. package/.torusguard/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  24. package/.torusguard/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  25. package/.torusguard/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  26. package/.torusguard/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  27. package/.torusguard/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
  28. package/.torusguard/rules/TG-SEC-002-public-environment-secrets.md +83 -0
  29. package/.torusguard/rules/TG-SEC-003-tracked-env-file.md +79 -0
  30. package/.torusguard/rules/TG-SEC-004-sensitive-logging.md +83 -0
  31. package/.torusguard/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
  32. package/.torusguard/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
  33. package/.torusguard/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
  34. package/.torusguard/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
  35. package/.torusguard/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
  36. package/.torusguard/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
  37. package/.torusguard/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  38. package/.torusguard/rules/active/TG-DB-001-frontend-database-query.md +83 -0
  39. package/.torusguard/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
  40. package/.torusguard/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
  41. package/.torusguard/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  42. package/.torusguard/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
  43. package/.torusguard/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  44. package/.torusguard/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  45. package/.torusguard/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  46. package/.torusguard/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  47. package/.torusguard/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  48. package/.torusguard/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  49. package/.torusguard/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
  50. package/.torusguard/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  51. package/.torusguard/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  52. package/.torusguard/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  53. package/.torusguard/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  54. package/.torusguard/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  55. package/.torusguard/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
  56. package/.torusguard/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
  57. package/.torusguard/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
  58. package/.torusguard/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
  59. package/.torusguard/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
  60. package/.torusguard/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
  61. package/.torusguard/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
  62. package/.torusguard/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
  63. package/.torusguard/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
  64. package/.torusguard/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
  65. package/.torusguard/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
  66. package/.torusguard/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
  67. package/.torusguard/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
  68. package/.torusguard/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
  69. package/.torusguard/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
  70. package/.torusguard/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
  71. package/.torusguard/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
  72. package/.torusguard/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
  73. package/.torusguard/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
  74. package/.torusguard/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
  75. package/.torusguard/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
  76. package/.torusguard/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
  77. package/.torusguard/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
  78. package/.torusguard/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
  79. package/.torusguard/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
  80. package/.torusguard/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
  81. package/.torusguard/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
  82. package/.torusguard/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
  83. package/.torusguard/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
  84. package/.torusguard/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
  85. package/.torusguard/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
  86. package/.torusguard/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
  87. package/.torusguard/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
  88. package/.torusguard/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
  89. package/.torusguard/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
  90. package/.torusguard/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
  91. package/.torusguard/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
  92. package/.torusguard/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
  93. package/.torusguard/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
  94. package/.torusguard/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
  95. package/.torusguard/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
  96. package/.torusguard/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
  97. package/.torusguard/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
  98. package/.torusguard/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
  99. package/.torusguard/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
  100. package/.torusguard/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
  101. package/.torusguard/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
  102. package/.torusguard/runs/report-latest.html +62 -20
  103. package/.torusguard/runs/run-20260908-112648-audit/findings.json +1520 -0
  104. package/.torusguard/runs/run-20260908-112648-audit/findings.md +560 -0
  105. package/.torusguard/runs/run-20260908-112648-audit/manifest.json +12 -0
  106. package/.torusguard/runs/run-20260908-112648-audit/summary.md +5 -0
  107. package/.torusguard/runs/run-20260908-112722-audit/findings.json +1520 -0
  108. package/.torusguard/runs/run-20260908-112722-audit/findings.md +560 -0
  109. package/.torusguard/runs/run-20260908-112722-audit/manifest.json +12 -0
  110. package/.torusguard/runs/run-20260908-112722-audit/summary.md +5 -0
  111. package/.torusguard/runs/run-20260908-113004-audit/findings.json +1520 -0
  112. package/.torusguard/runs/run-20260908-113004-audit/findings.md +560 -0
  113. package/.torusguard/runs/run-20260908-113004-audit/manifest.json +12 -0
  114. package/.torusguard/runs/run-20260908-113004-audit/summary.md +5 -0
  115. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
  116. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
  117. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
  118. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
  119. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
  120. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
  121. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
  122. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
  123. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
  124. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
  125. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
  126. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
  127. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
  128. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
  129. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
  130. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
  131. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
  132. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
  133. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
  134. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
  135. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
  136. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
  137. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
  138. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
  139. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
  140. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
  141. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
  142. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
  143. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
  144. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
  145. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
  146. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
  147. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
  148. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
  149. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
  150. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
  151. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
  152. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
  153. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
  154. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
  155. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
  156. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
  157. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
  158. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
  159. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
  160. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
  161. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
  162. package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
  163. package/.torusguard/runs/run-20260908-113127-audit/findings.json +1520 -0
  164. package/.torusguard/runs/run-20260908-113127-audit/findings.md +560 -0
  165. package/.torusguard/runs/run-20260908-113127-audit/manifest.json +13 -0
  166. package/.torusguard/runs/run-20260908-113127-audit/remediation.md +262 -0
  167. package/.torusguard/runs/run-20260908-113127-audit/summary.md +5 -0
  168. package/.torusguard/runs/run-20260908-115240-audit/apply_plan.md +6 -0
  169. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
  170. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
  171. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
  172. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
  173. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
  174. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
  175. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
  176. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
  177. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
  178. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
  179. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
  180. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
  181. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
  182. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
  183. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
  184. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
  185. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
  186. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
  187. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
  188. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
  189. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
  190. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
  191. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
  192. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
  193. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
  194. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
  195. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
  196. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
  197. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
  198. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
  199. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/metadata.json +15 -0
  200. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/minimal_patch_plan.md +21 -0
  201. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/patch.diff +9 -0
  202. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
  203. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
  204. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
  205. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
  206. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
  207. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
  208. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
  209. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
  210. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
  211. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
  212. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
  213. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
  214. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
  215. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
  216. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
  217. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
  218. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
  219. package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
  220. package/.torusguard/runs/run-20260908-115240-audit/diff_summary.md +221 -0
  221. package/.torusguard/runs/run-20260908-115240-audit/findings.json +1553 -0
  222. package/.torusguard/runs/run-20260908-115240-audit/findings.md +572 -0
  223. package/.torusguard/runs/run-20260908-115240-audit/manifest.json +14 -0
  224. package/.torusguard/runs/run-20260908-115240-audit/recheck.md +91 -0
  225. package/.torusguard/runs/run-20260908-115240-audit/remediation.md +278 -0
  226. package/.torusguard/runs/run-20260908-115240-audit/summary.md +5 -0
  227. package/.torusguard/scripts/__pycache__/audit_runner.cpython-311.pyc +0 -0
  228. package/.torusguard/scripts/__pycache__/finding_scorer.cpython-311.pyc +0 -0
  229. package/.torusguard/scripts/__pycache__/memory_engine.cpython-311.pyc +0 -0
  230. package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
  231. package/.torusguard/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
  232. package/.torusguard/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
  233. package/.torusguard/scripts/apply_runner.py +332 -0
  234. package/.torusguard/scripts/audit_runner.py +550 -0
  235. package/.torusguard/scripts/diff_guard.py +52 -4
  236. package/.torusguard/scripts/finding_scorer.py +58 -0
  237. package/.torusguard/scripts/harden_runner.py +353 -0
  238. package/.torusguard/scripts/html_reporter.py +25 -10
  239. package/.torusguard/scripts/manifest_builder.py +2 -0
  240. package/.torusguard/scripts/memory_engine.py +4 -0
  241. package/.torusguard/scripts/recheck_runner.py +221 -0
  242. package/.torusguard/scripts/recipes_runner.py +130 -0
  243. package/.torusguard/scripts/run_manager.py +17 -5
  244. package/.torusguard/skills/torusguard/SKILL.md +42 -42
  245. package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/client/src/App.jsx.bak +63 -0
  246. package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/server/index.js.bak +82 -0
  247. package/.torusguard/snapshots/run-20260908-115240-audit/harness/engine/fixture_manager.py.bak +245 -0
  248. package/.torusguard/snapshots/run-20260908-115240-audit/harness/master_validation.py.bak +698 -0
  249. package/.torusguard/snapshots/run-20260908-115240-audit/harness/runner.py.bak +551 -0
  250. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_e2e.py.bak +498 -0
  251. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_qa_v0_6_0.py.bak +572 -0
  252. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_1_scale.py.bak +371 -0
  253. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_2_modern_stacks.py.bak +462 -0
  254. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_3_hardening.py.bak +444 -0
  255. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_0_0_memory.py.bak +302 -0
  256. package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_1_0_advanced_memory.py.bak +342 -0
  257. package/.torusguard/snapshots/run-20260908-115240-audit/skills/torusguard/payload/scripts/harden_runner.py.bak +353 -0
  258. package/.torusguard/snapshots/run-20260908-115240-audit/tests/test_v0_6_0_governed_remediation.py.bak +353 -0
  259. package/README.md +70 -33
  260. package/bin/torusguard.js +89 -19
  261. package/package.json +1 -1
  262. package/skills/torusguard/SKILL.md +42 -42
  263. package/skills/torusguard/bootstrap.py +147 -68
  264. package/skills/torusguard/payload/.manifest.json +113 -9
  265. package/skills/torusguard/payload/rules/README.md +93 -62
  266. package/skills/torusguard/payload/rules/TG-AUTH-001-weak-password-storage.md +103 -0
  267. package/skills/torusguard/payload/rules/TG-AUTH-002-client-only-authorization.md +85 -0
  268. package/skills/torusguard/payload/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
  269. package/skills/torusguard/payload/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
  270. package/skills/torusguard/payload/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
  271. package/skills/torusguard/payload/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
  272. package/skills/torusguard/payload/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  273. package/skills/torusguard/payload/rules/TG-DB-001-frontend-database-query.md +83 -0
  274. package/skills/torusguard/payload/rules/TG-DB-002-privileged-database-credential.md +86 -0
  275. package/skills/torusguard/payload/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
  276. package/skills/torusguard/payload/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  277. package/skills/torusguard/payload/rules/TG-INPUT-001-missing-server-validation.md +98 -0
  278. package/skills/torusguard/payload/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  279. package/skills/torusguard/payload/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  280. package/skills/torusguard/payload/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  281. package/skills/torusguard/payload/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  282. package/skills/torusguard/payload/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  283. package/skills/torusguard/payload/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  284. package/skills/torusguard/payload/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
  285. package/skills/torusguard/payload/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  286. package/skills/torusguard/payload/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  287. package/skills/torusguard/payload/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  288. package/skills/torusguard/payload/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  289. package/skills/torusguard/payload/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  290. package/skills/torusguard/payload/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
  291. package/skills/torusguard/payload/rules/TG-SEC-002-public-environment-secrets.md +83 -0
  292. package/skills/torusguard/payload/rules/TG-SEC-003-tracked-env-file.md +79 -0
  293. package/skills/torusguard/payload/rules/TG-SEC-004-sensitive-logging.md +83 -0
  294. package/skills/torusguard/payload/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
  295. package/skills/torusguard/payload/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
  296. package/skills/torusguard/payload/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
  297. package/skills/torusguard/payload/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
  298. package/skills/torusguard/payload/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
  299. package/skills/torusguard/payload/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
  300. package/skills/torusguard/payload/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
  301. package/skills/torusguard/payload/rules/active/TG-DB-001-frontend-database-query.md +83 -0
  302. package/skills/torusguard/payload/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
  303. package/skills/torusguard/payload/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
  304. package/skills/torusguard/payload/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
  305. package/skills/torusguard/payload/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
  306. package/skills/torusguard/payload/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
  307. package/skills/torusguard/payload/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
  308. package/skills/torusguard/payload/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
  309. package/skills/torusguard/payload/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
  310. package/skills/torusguard/payload/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
  311. package/skills/torusguard/payload/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
  312. package/skills/torusguard/payload/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
  313. package/skills/torusguard/payload/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
  314. package/skills/torusguard/payload/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
  315. package/skills/torusguard/payload/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
  316. package/skills/torusguard/payload/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
  317. package/skills/torusguard/payload/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
  318. package/skills/torusguard/payload/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
  319. package/skills/torusguard/payload/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
  320. package/skills/torusguard/payload/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
  321. package/skills/torusguard/payload/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
  322. package/skills/torusguard/payload/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
  323. package/skills/torusguard/payload/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
  324. package/skills/torusguard/payload/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
  325. package/skills/torusguard/payload/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
  326. package/skills/torusguard/payload/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
  327. package/skills/torusguard/payload/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
  328. package/skills/torusguard/payload/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
  329. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
  330. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
  331. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
  332. package/skills/torusguard/payload/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
  333. package/skills/torusguard/payload/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
  334. package/skills/torusguard/payload/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
  335. package/skills/torusguard/payload/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
  336. package/skills/torusguard/payload/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
  337. package/skills/torusguard/payload/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
  338. package/skills/torusguard/payload/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
  339. package/skills/torusguard/payload/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
  340. package/skills/torusguard/payload/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
  341. package/skills/torusguard/payload/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
  342. package/skills/torusguard/payload/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
  343. package/skills/torusguard/payload/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
  344. package/skills/torusguard/payload/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
  345. package/skills/torusguard/payload/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
  346. package/skills/torusguard/payload/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
  347. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
  348. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
  349. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
  350. package/skills/torusguard/payload/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
  351. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
  352. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
  353. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
  354. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
  355. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
  356. package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
  357. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
  358. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
  359. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
  360. package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
  361. package/skills/torusguard/payload/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
  362. package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
  363. package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
  364. package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
  365. package/skills/torusguard/payload/scripts/apply_runner.py +332 -0
  366. package/skills/torusguard/payload/scripts/audit_runner.py +550 -0
  367. package/skills/torusguard/payload/scripts/diff_guard.py +52 -4
  368. package/skills/torusguard/payload/scripts/finding_scorer.py +58 -0
  369. package/skills/torusguard/payload/scripts/harden_runner.py +353 -0
  370. package/skills/torusguard/payload/scripts/html_reporter.py +25 -10
  371. package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
  372. package/skills/torusguard/payload/scripts/memory_engine.py +4 -0
  373. package/skills/torusguard/payload/scripts/recheck_runner.py +221 -0
  374. package/skills/torusguard/payload/scripts/recipes_runner.py +130 -0
  375. package/skills/torusguard/payload/scripts/run_manager.py +17 -5
  376. package/skills/torusguard/payload/skills/torusguard/SKILL.md +42 -42
  377. package/skills/torusguard/payload/skills/torusguard/bootstrap.py +147 -68
@@ -0,0 +1,86 @@
1
+ # TG-DB-002: Privileged Database Credential in Browser Context
2
+
3
+ ## Severity
4
+ Critical
5
+
6
+ ## Applies To
7
+ - Browser-executed code in frontend apps and static assets
8
+ - Public environment variables consumed by client bundles
9
+ - Mobile web, desktop web, and embedded webview clients
10
+ - Shared modules imported into client-side runtime
11
+
12
+ ## Why It Matters
13
+ Privileged database credentials in browser-accessible code grant attackers direct or indirect control over sensitive data stores.
14
+ Service-role keys and admin database URLs typically bypass row-level access controls and can expose full datasets.
15
+ Because frontend artifacts are publicly retrievable, embedded privileged credentials should be treated as compromised.
16
+
17
+ ## What TorusGuard Looks For
18
+ - Service-role keys and admin tokens referenced in frontend code
19
+ - Database URLs containing usernames/passwords in browser-executed modules
20
+ - Public env variables with names such as:
21
+ - `NEXT_PUBLIC_DATABASE_URL`
22
+ - `VITE_SUPABASE_SERVICE_ROLE_KEY`
23
+ - `REACT_APP_ADMIN_DB_TOKEN`
24
+ - Client initialization using elevated credentials intended for server trust zones
25
+ - Fallback credential constants used when env vars are missing
26
+
27
+ ## Unsafe Example
28
+ ```ts
29
+ // src/lib/dbClient.ts
30
+ import { createClient } from "@supabase/supabase-js";
31
+
32
+ const url = process.env.NEXT_PUBLIC_DATABASE_URL!;
33
+ const serviceRole = process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY!;
34
+
35
+ export const db = createClient(url, serviceRole, {
36
+ auth: { persistSession: false },
37
+ });
38
+ ```
39
+
40
+ ## Safe Example
41
+ ```ts
42
+ // src/lib/publicClient.ts
43
+ import { createClient } from "@supabase/supabase-js";
44
+
45
+ const url = process.env.NEXT_PUBLIC_SUPABASE_URL!;
46
+ const anonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
47
+
48
+ export const publicDb = createClient(url, anonKey);
49
+ ```
50
+
51
+ ```ts
52
+ // server/lib/adminDb.ts
53
+ import { createClient } from "@supabase/supabase-js";
54
+
55
+ export const adminDb = createClient(
56
+ process.env.SUPABASE_URL!,
57
+ process.env.SUPABASE_SERVICE_ROLE_KEY!,
58
+ );
59
+ ```
60
+
61
+ ## Remediation (numbered)
62
+ 1. Remove privileged DB credentials from all frontend and public env sources.
63
+ 2. Rotate exposed service-role keys, passwords, and privileged tokens immediately.
64
+ 3. Migrate privileged operations to backend-only services and APIs.
65
+ 4. Use least-privilege client credentials (anonymous/public keys) in browser code.
66
+ 5. Audit access logs for misuse during exposure window.
67
+ 6. Enforce CI policy blocking privileged credential names in public scopes.
68
+ 7. Add architecture documentation defining credential trust boundaries.
69
+
70
+ ## Verification
71
+ - Inspect client bundles and source maps for privileged credential artifacts.
72
+ - Confirm frontend uses only non-privileged credentials and constrained APIs.
73
+ - Validate server-only secrets are loaded from private runtime environments.
74
+ - Test rotated privileged credentials and verify old keys are rejected.
75
+ - Review monitoring for anomalous database access during and after remediation.
76
+
77
+ ## False Positives and Exceptions
78
+ - Public anonymous keys may look secret-like but are intentionally non-privileged.
79
+ - Documentation examples can trigger detections; verify they are non-operational.
80
+ - Local-only sandbox credentials are still risky if bundled into distributed builds.
81
+ - Exceptions require security approval, owner assignment, and expiration date.
82
+
83
+ ## Related Rules
84
+ - [TG-SEC-001](./TG-SEC-001-hardcoded-secrets.md) - Hardcoded secrets in tracked source
85
+ - [TG-SEC-002](./TG-SEC-002-public-environment-secrets.md) - Secrets in public env namespaces
86
+ - [TG-DB-003](./TG-DB-003-frontend-admin-sdk.md) - Admin SDK usage in frontend runtime
@@ -0,0 +1,91 @@
1
+ # TG-DB-003: Frontend Use of Admin or Server-Only Database SDKs
2
+
3
+ ## Severity
4
+ Critical
5
+
6
+ ## Applies To
7
+ - Frontend directories such as `src/`, `app/`, `pages/`, `components/`, `client/`, `public/`
8
+ - Browser bundles in React, Next.js client components, Vite, and CRA
9
+ - Shared package imports consumed by client entry points
10
+ - Build systems that can accidentally include server-only dependencies
11
+
12
+ ## Why It Matters
13
+ Admin SDKs and server drivers are designed for trusted environments and often assume unrestricted credentials and network access.
14
+ Using packages like Firebase Admin, Prisma, or `pg` in frontend paths risks exposing privileged behavior, credentials, and internal data models.
15
+ Even failed browser execution can leak sensitive implementation details and weaken architectural boundaries.
16
+
17
+ ## What TorusGuard Looks For
18
+ - Imports of server-only SDKs in frontend-targeted files:
19
+ - `firebase-admin`
20
+ - `@prisma/client`
21
+ - `pg`
22
+ - Initialization logic for admin clients in UI components or client utilities
23
+ - Conditional imports attempting to bypass bundler checks in browser code
24
+ - Code patterns that create server DB connections in frontend modules
25
+ - Shared files that instantiate privileged clients and are imported by frontend
26
+
27
+ ## Unsafe Example
28
+ ```ts
29
+ // src/app/dashboard/adminMetrics.tsx
30
+ import { PrismaClient } from "@prisma/client";
31
+ import { Client } from "pg";
32
+
33
+ const prisma = new PrismaClient();
34
+ const pgClient = new Client({
35
+ connectionString: process.env.NEXT_PUBLIC_DATABASE_URL,
36
+ });
37
+
38
+ export async function loadMetrics() {
39
+ await pgClient.connect();
40
+ const result = await prisma.user.count();
41
+ return { users: result };
42
+ }
43
+ ```
44
+
45
+ ## Safe Example
46
+ ```ts
47
+ // src/app/dashboard/adminMetrics.tsx
48
+ export async function loadMetrics() {
49
+ const res = await fetch("/api/admin/metrics", { method: "GET" });
50
+ return res.json();
51
+ }
52
+ ```
53
+
54
+ ```ts
55
+ // server/routes/adminMetrics.ts
56
+ import { PrismaClient } from "@prisma/client";
57
+
58
+ const prisma = new PrismaClient();
59
+
60
+ app.get("/api/admin/metrics", async (_req, res) => {
61
+ const users = await prisma.user.count();
62
+ res.json({ users });
63
+ });
64
+ ```
65
+
66
+ ## Remediation (numbered)
67
+ 1. Remove server-only SDK imports from frontend and browser-targeted modules.
68
+ 2. Relocate privileged data access to backend routes, jobs, or server actions.
69
+ 3. Ensure frontend calls authenticated backend endpoints for required data.
70
+ 4. Restrict server-only dependencies to backend package boundaries.
71
+ 5. Configure bundler/lint rules to block admin SDK imports in frontend paths.
72
+ 6. Rotate credentials if admin SDK usage exposed privileged config values.
73
+ 7. Add architecture tests validating strict client/server dependency separation.
74
+
75
+ ## Verification
76
+ - Scan frontend directories for imports of `firebase-admin`, Prisma, and `pg`.
77
+ - Confirm build output excludes server-only database packages in client chunks.
78
+ - Validate admin operations execute only on server infrastructure.
79
+ - Run access-control tests against backend endpoints exposing admin data.
80
+ - Review dependency graphs to ensure no frontend transitive path to admin SDKs.
81
+
82
+ ## False Positives and Exceptions
83
+ - Type-only imports can appear suspicious; verify they are erased at build time.
84
+ - Documentation snippets in markdown are non-runtime and may be acceptable.
85
+ - Server components must be verified carefully to avoid accidental client inclusion.
86
+ - Exceptions require documented risk acceptance and periodic security review.
87
+
88
+ ## Related Rules
89
+ - [TG-DB-001](./TG-DB-001-frontend-database-query.md) - Frontend SQL/query logic anti-pattern
90
+ - [TG-DB-002](./TG-DB-002-privileged-database-credential.md) - Privileged credential exposure in browser
91
+ - [TG-SEC-001](./TG-SEC-001-hardcoded-secrets.md) - Hardcoded sensitive literals in source
@@ -0,0 +1,103 @@
1
+ ---
2
+ id: TG-DB-004
3
+ title: Missing Tenant Query Isolation in Multi-Tenant Models
4
+ category: data-access-orm
5
+ severity: Critical
6
+ confidence: Confirmed
7
+ frameworks:
8
+ - django
9
+ - drf
10
+ - fastapi
11
+ - flask
12
+ - sqlalchemy
13
+ cwe: CWE-284
14
+ asvs_v4: V4.1.3
15
+ nist_ssdf: PW.5.1
16
+ ---
17
+
18
+ # TG-DB-004: Missing Tenant Query Isolation in Multi-Tenant Models
19
+
20
+ ## 🚨 Problem Statement
21
+ Applications built on a multi-tenant architecture often fail to scope database lookups (`SELECT`, `UPDATE`, `DELETE`) by the current authenticated tenant. Allowing a direct primary key (ID) lookup without a composite tenant filter allows Insecure Direct Object Reference (IDOR) attacks, enabling users to access or modify data belonging to other tenants.
22
+
23
+ > **Tuning Guardrails (v0.5.6):**
24
+ > - **DO NOT flag** every primary-key lookup.
25
+ > - **ESCALATE** when tenant-owned data can be loaded or modified without a verified tenant scope.
26
+ > - **DETECT** established tenant-scoped managers, repositories, `get_queryset()`, dependency injection, or parent-resource ownership checks.
27
+ > - **MARK** complex multi-layer scope flows as `Needs Review` instead of `Confirmed` when source-only proof is inadequate.
28
+
29
+ ---
30
+
31
+ ## 💥 Adversarial Threat & Exploitation
32
+ An attacker from Tenant B supplies the record UUID of a confidential document belonging to Tenant A:
33
+ ```http
34
+ GET /api/v1/invoices/9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d HTTP/1.1
35
+ Host: saas.example.com
36
+ Authorization: Bearer <Tenant_B_JWT>
37
+ ```
38
+ If the backend performs `session.get(Invoice, invoice_id)` or `Invoice.objects.get(id=invoice_id)` without scoping to `tenant_id=current_user.tenant_id`, the invoice belonging to Tenant A is returned to the attacker.
39
+
40
+ ---
41
+
42
+ ## 🛠️ Framework-Native Remediations
43
+
44
+ ### 🐍 SQLAlchemy (Scoped Tenant Queries)
45
+
46
+ #### ❌ Unsafe Pattern
47
+ ```python
48
+ # Unsafe: Global primary key lookup without tenant filter
49
+ @app.get("/invoices/{invoice_id}")
50
+ def get_invoice(invoice_id: str, db: Session = Depends(get_db), user: User = Depends(get_current_user)):
51
+ invoice = db.query(Invoice).filter(Invoice.id == invoice_id).first()
52
+ if not invoice:
53
+ raise HTTPException(status_code=404, detail="Invoice not found")
54
+ return invoice
55
+ ```
56
+
57
+ #### ✅ Safe Remediation
58
+ ```python
59
+ # Safe: Enforce tenant scoping on every query filter
60
+ @app.get("/invoices/{invoice_id}")
61
+ def get_invoice(invoice_id: str, db: Session = Depends(get_db), user: User = Depends(get_current_user)):
62
+ invoice = (
63
+ db.query(Invoice)
64
+ .filter(Invoice.id == invoice_id, Invoice.tenant_id == user.tenant_id)
65
+ .first()
66
+ )
67
+ if not invoice:
68
+ raise HTTPException(status_code=404, detail="Invoice not found")
69
+ return invoice
70
+ ```
71
+
72
+ ---
73
+
74
+ ### 🐍 Django ORM (Scoped Manager / ViewSet Queryset)
75
+
76
+ #### ❌ Unsafe Pattern
77
+ ```python
78
+ # Unsafe: Global queryset in DRF ViewSet
79
+ class InvoiceViewSet(viewsets.ModelViewSet):
80
+ queryset = Invoice.objects.all() # Exposes all tenant records
81
+ serializer_class = InvoiceSerializer
82
+ ```
83
+
84
+ #### ✅ Safe Remediation
85
+ ```python
86
+ # Safe: Override get_queryset to enforce tenant boundary on every request
87
+ class InvoiceViewSet(viewsets.ModelViewSet):
88
+ serializer_class = InvoiceSerializer
89
+ permission_classes = [permissions.IsAuthenticated]
90
+
91
+ def get_queryset(self):
92
+ # Strictly scope lookups to authenticated user's organization
93
+ return Invoice.objects.filter(tenant=self.request.user.tenant)
94
+ ```
95
+
96
+ ---
97
+
98
+ ## 🧪 Verification & Reproduction
99
+ 1. Send request with valid Tenant B token requesting Tenant A resource ID:
100
+ ```bash
101
+ curl -H "Authorization: Bearer <Tenant_B_Token>" http://localhost:8000/invoices/<Tenant_A_UUID>
102
+ ```
103
+ 2. **Assertion:** Request must return `404 Not Found`, denying access to cross-tenant data.
@@ -0,0 +1,98 @@
1
+ # TG-INPUT-001: Missing Server-Side Validation
2
+
3
+ ## Severity
4
+ High
5
+
6
+ ## Applies To
7
+ - REST and GraphQL API handlers
8
+ - Form-processing backend endpoints
9
+ - Message queue consumers that accept external payloads
10
+ - Admin/import endpoints that trust UI validation
11
+
12
+ ## Why It Matters
13
+ Client-side checks are easy to bypass because attackers can send crafted requests directly to backend endpoints.
14
+ When the server does not validate required fields, data type, length, format, range, and allowed values, malicious input can trigger account takeover paths, integrity failures, and downstream injection vulnerabilities.
15
+ Server-side validation is also required to keep business rules enforceable when multiple clients, scripts, and integrations call the same APIs.
16
+
17
+ ## What TorusGuard Looks For
18
+ - Request data read from `req.body`, `req.query`, `req.params`, headers, or raw payloads without schema validation.
19
+ - Validation done only in frontend files while backend endpoint accepts the same fields blindly.
20
+ - Direct persistence of user-provided objects with broad spread operators.
21
+ - Type coercion and fallback logic that silently accepts invalid values.
22
+ - Missing allowlists for enum-like fields such as role, status, country code, or operation type.
23
+
24
+ ## Unsafe Example
25
+ ```js
26
+ // Express route that trusts client validation
27
+ app.post("/api/profile", async (req, res) => {
28
+ const { displayName, age, newsletter, role } = req.body;
29
+
30
+ // No server-side validation:
31
+ // - displayName could be extremely long or contain control chars
32
+ // - age could be negative or non-numeric
33
+ // - newsletter could be arbitrary string
34
+ // - role could be escalated to "admin"
35
+ const updated = await db.user.update({
36
+ where: { id: req.user.id },
37
+ data: { displayName, age, newsletter, role }
38
+ });
39
+
40
+ res.json({ ok: true, user: updated });
41
+ });
42
+ ```
43
+
44
+ ## Safe Example
45
+ ```js
46
+ import { z } from "zod";
47
+
48
+ const updateProfileSchema = z.object({
49
+ displayName: z.string().min(2).max(60).regex(/^[a-zA-Z0-9 _.-]+$/),
50
+ age: z.number().int().min(13).max(120),
51
+ newsletter: z.boolean(),
52
+ role: z.enum(["user"]) // client cannot self-assign privileged roles
53
+ });
54
+
55
+ app.post("/api/profile", async (req, res) => {
56
+ const parsed = updateProfileSchema.safeParse(req.body);
57
+ if (!parsed.success) {
58
+ return res.status(400).json({
59
+ ok: false,
60
+ error: "Invalid input",
61
+ details: parsed.error.issues
62
+ });
63
+ }
64
+
65
+ const { displayName, age, newsletter } = parsed.data;
66
+ const updated = await db.user.update({
67
+ where: { id: req.user.id },
68
+ data: { displayName, age, newsletter }
69
+ });
70
+
71
+ res.json({ ok: true, user: updated });
72
+ });
73
+ ```
74
+
75
+ ## Remediation
76
+ 1. Define strict server-side schemas for every externally reachable input surface.
77
+ 2. Validate before business logic, authorization decisions, and database writes.
78
+ 3. Enforce field allowlists; reject unexpected keys rather than silently ignoring them.
79
+ 4. Apply normalization after validation (trim, case-fold, canonical forms) where needed.
80
+ 5. Centralize reusable validators for shared payloads to prevent drift across endpoints.
81
+ 6. Return clear but non-sensitive validation errors, and log rejection metrics for monitoring.
82
+
83
+ ## Verification
84
+ - Send malformed payloads directly with `curl` or API clients, bypassing the web UI.
85
+ - Confirm invalid types, out-of-range values, and unknown fields return `400`.
86
+ - Attempt privilege-related field tampering and verify values are rejected or ignored safely.
87
+ - Run integration tests covering boundary values and negative cases.
88
+ - Ensure validation runs for all entry paths, including batch/import and background worker routes.
89
+
90
+ ## False Positives and Exceptions
91
+ - Internal service-to-service endpoints may appear unvalidated but can be acceptable if strong contract validation is enforced at the gateway and mutual trust boundaries are documented.
92
+ - Auto-generated API frameworks sometimes perform implicit validation; keep explicit schema definitions for auditability.
93
+ - Legacy endpoints under migration can be temporarily exempted only with compensating controls and a tracked deprecation timeline.
94
+
95
+ ## Related Rules
96
+ - [TG-INPUT-002](./TG-INPUT-002-raw-sql-concatenation.md)
97
+ - [TG-INPUT-003](./TG-INPUT-003-unsafe-html-or-code-execution.md)
98
+ - [TG-AUTH-003](./TG-AUTH-003-missing-object-authorization.md)
@@ -0,0 +1,94 @@
1
+ # TG-INPUT-002: Raw SQL Concatenation
2
+
3
+ ## Severity
4
+ Critical
5
+
6
+ ## Applies To
7
+ - Backend services that execute SQL queries
8
+ - Scripts and cron jobs that build dynamic SQL
9
+ - Data export/reporting endpoints with filters and sorting
10
+ - Administrative tooling with direct database access
11
+
12
+ ## Why It Matters
13
+ Concatenating untrusted input into SQL statements allows SQL injection, one of the highest-impact application vulnerabilities.
14
+ Successful exploitation can expose sensitive records, bypass authentication checks, modify or delete data, and in some environments execute database-level administrative operations.
15
+ Even read-only endpoints can become a pivot for full data exfiltration when query construction is unsafe.
16
+
17
+ ## What TorusGuard Looks For
18
+ - String interpolation or concatenation inside SQL query text using request-derived data.
19
+ - Dynamic `WHERE`, `ORDER BY`, `LIMIT`, or table-name fragments assembled from raw user input.
20
+ - Use of low-level query APIs without bind parameters.
21
+ - Sanitization-only approaches (replace/escape) used instead of parameterization.
22
+ - Unsafe helper functions that return query strings rather than query templates plus values.
23
+
24
+ ## Unsafe Example
25
+ ```js
26
+ app.get("/api/orders", async (req, res) => {
27
+ const customerId = req.query.customerId;
28
+ const sort = req.query.sort || "created_at DESC";
29
+
30
+ // Both customerId and sort are attacker-controlled
31
+ const sql =
32
+ "SELECT id, total, created_at FROM orders " +
33
+ "WHERE customer_id = '" + customerId + "' " +
34
+ "ORDER BY " + sort;
35
+
36
+ const rows = await db.query(sql);
37
+ res.json({ ok: true, orders: rows });
38
+ });
39
+ ```
40
+
41
+ ## Safe Example
42
+ ```js
43
+ const SORT_COLUMNS = new Map([
44
+ ["newest", "created_at DESC"],
45
+ ["oldest", "created_at ASC"],
46
+ ["total_high", "total DESC"],
47
+ ["total_low", "total ASC"]
48
+ ]);
49
+
50
+ app.get("/api/orders", async (req, res) => {
51
+ const customerId = String(req.query.customerId || "");
52
+ const sortKey = String(req.query.sort || "newest");
53
+ const sortSql = SORT_COLUMNS.get(sortKey);
54
+
55
+ if (!sortSql || !/^[a-f0-9-]{36}$/.test(customerId)) {
56
+ return res.status(400).json({ ok: false, error: "Invalid query parameters" });
57
+ }
58
+
59
+ const sql = `
60
+ SELECT id, total, created_at
61
+ FROM orders
62
+ WHERE customer_id = $1
63
+ ORDER BY ${sortSql}
64
+ `;
65
+
66
+ const rows = await db.query(sql, [customerId]);
67
+ res.json({ ok: true, orders: rows });
68
+ });
69
+ ```
70
+
71
+ ## Remediation
72
+ 1. Replace all string-built SQL with parameterized queries or prepared statements.
73
+ 2. Bind user input as values, never as SQL syntax fragments.
74
+ 3. For dynamic sorting/filtering, map user options to fixed allowlisted SQL snippets.
75
+ 4. Restrict database account privileges to least privilege to reduce blast radius.
76
+ 5. Add static analysis and code review checks that ban raw concatenated SQL.
77
+ 6. Cover injection payloads in automated tests for every query endpoint.
78
+
79
+ ## Verification
80
+ - Search for query construction using template interpolation with request variables.
81
+ - Attempt payloads such as `' OR '1'='1` and confirm they are treated as literal values.
82
+ - Verify sort/filter options accept only predefined keys.
83
+ - Review database logs for rejected malformed statements and suspicious patterns.
84
+ - Confirm all DB access layers support parameter binding and are consistently used.
85
+
86
+ ## False Positives and Exceptions
87
+ - Hardcoded SQL strings with no untrusted input are generally safe.
88
+ - Migration files may contain dynamic SQL for schema operations; these are acceptable if not user-influenced.
89
+ - Internal ETL code can still be vulnerable if source data is not trusted; do not auto-exempt.
90
+
91
+ ## Related Rules
92
+ - [TG-INPUT-001](./TG-INPUT-001-missing-server-validation.md)
93
+ - [TG-INPUT-003](./TG-INPUT-003-unsafe-html-or-code-execution.md)
94
+ - [TG-AUTH-003](./TG-AUTH-003-missing-object-authorization.md)
@@ -0,0 +1,102 @@
1
+ # TG-INPUT-003: Unsafe HTML Rendering or Code Execution
2
+
3
+ ## Severity
4
+ High
5
+
6
+ ## Applies To
7
+ - Server-side rendering pipelines
8
+ - Rich text/comment rendering features
9
+ - Template engines and markdown-to-HTML converters
10
+ - Dynamic expression evaluators and script execution utilities
11
+
12
+ ## Why It Matters
13
+ When untrusted content is rendered as HTML without sanitization, attackers can inject scripts and trigger stored or reflected XSS.
14
+ When untrusted input reaches evaluators such as `eval`, `Function`, or shell execution helpers, remote code execution and server compromise become possible.
15
+ These flaws frequently lead to session theft, account takeover, and full application compromise.
16
+
17
+ ## What TorusGuard Looks For
18
+ - Use of dangerous rendering APIs such as `innerHTML`, `dangerouslySetInnerHTML`, or unsanitized template output.
19
+ - Markdown or rich text conversion with unsafe options enabled.
20
+ - Invocation of `eval`, `new Function`, VM contexts, or command execution with user-controlled fragments.
21
+ - Security filters that rely only on regex stripping of script tags.
22
+ - User content stored and later rendered in privileged admin views.
23
+
24
+ ## Unsafe Example
25
+ ```js
26
+ app.post("/api/notes/preview", (req, res) => {
27
+ const body = req.body.content;
28
+
29
+ // Stored then rendered unsafely
30
+ const html = `<article>${body}</article>`;
31
+ res.send(html);
32
+ });
33
+
34
+ app.post("/api/calc", (req, res) => {
35
+ const expression = req.body.expression;
36
+
37
+ // User controls executed code
38
+ const result = eval(expression);
39
+ res.json({ ok: true, result });
40
+ });
41
+ ```
42
+
43
+ ## Safe Example
44
+ ```js
45
+ import sanitizeHtml from "sanitize-html";
46
+
47
+ app.post("/api/notes/preview", (req, res) => {
48
+ const content = String(req.body.content || "");
49
+ const safe = sanitizeHtml(content, {
50
+ allowedTags: ["p", "b", "i", "strong", "em", "ul", "ol", "li", "a", "code", "pre"],
51
+ allowedAttributes: { a: ["href", "title"] },
52
+ allowedSchemes: ["http", "https", "mailto"]
53
+ });
54
+
55
+ res.send(`<article>${safe}</article>`);
56
+ });
57
+
58
+ app.post("/api/calc", (req, res) => {
59
+ const op = String(req.body.op || "");
60
+ const left = Number(req.body.left);
61
+ const right = Number(req.body.right);
62
+
63
+ if (!Number.isFinite(left) || !Number.isFinite(right)) {
64
+ return res.status(400).json({ ok: false, error: "Invalid numeric input" });
65
+ }
66
+
67
+ const operations = {
68
+ add: (a, b) => a + b,
69
+ sub: (a, b) => a - b,
70
+ mul: (a, b) => a * b,
71
+ div: (a, b) => (b === 0 ? null : a / b)
72
+ };
73
+
74
+ if (!operations[op]) return res.status(400).json({ ok: false, error: "Unsupported operation" });
75
+ res.json({ ok: true, result: operations[op](left, right) });
76
+ });
77
+ ```
78
+
79
+ ## Remediation
80
+ 1. Treat all user-controlled text as untrusted until sanitized for the target context.
81
+ 2. Use maintained HTML sanitizers with explicit allowlists for tags and attributes.
82
+ 3. Ban runtime code execution functions (`eval`, `Function`, shell interpolation) in request paths.
83
+ 4. Replace expression execution with constrained allowlisted operations.
84
+ 5. Enforce contextual output encoding in templates and frontend rendering layers.
85
+ 6. Add CSP and defense-in-depth controls, but do not treat them as primary mitigation.
86
+
87
+ ## Verification
88
+ - Submit payloads containing event handlers, script tags, and `javascript:` URLs.
89
+ - Confirm rendered output strips unsafe elements and attributes.
90
+ - Attempt expression payloads like `process.env` and verify they are rejected.
91
+ - Run security tests for stored and reflected rendering flows, including admin pages.
92
+ - Ensure static analysis flags prohibited runtime execution APIs.
93
+
94
+ ## False Positives and Exceptions
95
+ - Trusted, static CMS content curated by privileged staff may allow richer HTML if isolated and sanitized by policy.
96
+ - Template literals are not inherently unsafe; only sinks that interpret HTML/code create risk.
97
+ - Sandboxed code execution environments still require strict resource and capability restrictions.
98
+
99
+ ## Related Rules
100
+ - [TG-INPUT-001](./TG-INPUT-001-missing-server-validation.md)
101
+ - [TG-INPUT-002](./TG-INPUT-002-raw-sql-concatenation.md)
102
+ - [TG-AUTH-004](./TG-AUTH-004-insecure-session-cookie.md)
@@ -0,0 +1,92 @@
1
+ # TG-INPUT-004: Unrestricted File Upload
2
+
3
+ ## Severity
4
+ High
5
+
6
+ ## Applies To
7
+ - Profile avatar and document upload endpoints
8
+ - Media management APIs and admin upload tools
9
+ - Import features that accept archives or spreadsheets
10
+ - Object storage presigned upload workflows
11
+
12
+ ## Why It Matters
13
+ Unrestricted uploads let attackers store executable scripts, malware, oversized payloads, and deceptive file types.
14
+ If uploaded files are publicly accessible or processed unsafely, attackers can trigger XSS, remote code execution, SSRF through parsers, or storage exhaustion denial of service.
15
+ Weak upload controls also create legal and compliance risk when sensitive content is mishandled.
16
+
17
+ ## What TorusGuard Looks For
18
+ - Acceptance based only on filename extension or client-provided MIME type.
19
+ - Missing maximum file size, count, or rate limits.
20
+ - Uploading directly to web-served directories without safe naming.
21
+ - Lack of malware scanning or content-type verification by signature.
22
+ - Processing of complex formats without sandboxing and strict parser limits.
23
+
24
+ ## Unsafe Example
25
+ ```js
26
+ app.post("/api/upload", upload.single("file"), async (req, res) => {
27
+ const file = req.file;
28
+
29
+ // Trusts original name and MIME from client
30
+ const destination = path.join(__dirname, "public/uploads", file.originalname);
31
+ await fs.promises.writeFile(destination, file.buffer);
32
+
33
+ // Public URL serves whatever was uploaded
34
+ res.json({ ok: true, url: `/uploads/${file.originalname}` });
35
+ });
36
+ ```
37
+
38
+ ## Safe Example
39
+ ```js
40
+ import crypto from "crypto";
41
+ import FileType from "file-type";
42
+
43
+ const MAX_SIZE = 5 * 1024 * 1024;
44
+ const ALLOWED = new Set(["image/png", "image/jpeg", "application/pdf"]);
45
+
46
+ app.post("/api/upload", upload.single("file"), async (req, res) => {
47
+ const file = req.file;
48
+ if (!file || file.size > MAX_SIZE) {
49
+ return res.status(400).json({ ok: false, error: "Invalid file size" });
50
+ }
51
+
52
+ const detected = await FileType.fromBuffer(file.buffer);
53
+ const mime = detected?.mime || "";
54
+ if (!ALLOWED.has(mime)) {
55
+ return res.status(400).json({ ok: false, error: "Unsupported file type" });
56
+ }
57
+
58
+ const extension = mime === "image/png" ? "png" : mime === "image/jpeg" ? "jpg" : "pdf";
59
+ const storedName = `${crypto.randomUUID()}.${extension}`;
60
+ const storagePath = path.join(__dirname, "private_uploads", storedName);
61
+
62
+ await fs.promises.writeFile(storagePath, file.buffer, { mode: 0o600 });
63
+ await queueForMalwareScan(storagePath);
64
+
65
+ res.json({ ok: true, fileId: storedName });
66
+ });
67
+ ```
68
+
69
+ ## Remediation
70
+ 1. Enforce strict allowlists for file type, extension, and verified signature/MIME.
71
+ 2. Set max size, max count, and upload rate limits per user and per endpoint.
72
+ 3. Store files outside web root with generated names, never original filenames.
73
+ 4. Scan uploaded content with malware detection before making files retrievable.
74
+ 5. Re-validate file safety at retrieval and transformation points (thumbnailing, OCR, parsing).
75
+ 6. Use presigned uploads with constrained policies and short expirations where applicable.
76
+
77
+ ## Verification
78
+ - Upload files with double extensions (`.jpg.php`) and mismatched MIME signatures.
79
+ - Attempt oversized and high-frequency uploads to validate throttling and limits.
80
+ - Confirm stored filenames are non-guessable and not user-controlled.
81
+ - Verify uploaded objects cannot be executed as active content by browsers.
82
+ - Ensure parser pipelines reject malformed archives and nested compression bombs.
83
+
84
+ ## False Positives and Exceptions
85
+ - Internal-only transfer channels with signed artifacts may permit broader file types, but must still enforce size and scanning controls.
86
+ - Some media pipelines rely on asynchronous scanning; temporary quarantine states are acceptable with blocked access until scan completion.
87
+ - Legacy endpoints may need phased migration, but unrestricted direct serving is not acceptable long term.
88
+
89
+ ## Related Rules
90
+ - [TG-INPUT-001](./TG-INPUT-001-missing-server-validation.md)
91
+ - [TG-INPUT-003](./TG-INPUT-003-unsafe-html-or-code-execution.md)
92
+ - [TG-AUTH-004](./TG-AUTH-004-insecure-session-cookie.md)