diff --git a/backend/package-lock.json b/backend/package-lock.json index 0afba577..b67d2a83 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -511,7 +511,8 @@ "node_modules/@pinojs/redact": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==" + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -986,6 +987,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -1069,9 +1071,10 @@ } }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -2003,19 +2006,31 @@ ] }, "node_modules/imapflow": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/imapflow/-/imapflow-1.2.8.tgz", - "integrity": "sha512-ym7FF2tKOlOzfRvxehs4eLkhjP8Mme3sSp2tcxEbyoeJuJwtEWxaVDv12+DnaMG2LXm0zuQGWZiClq31FLPUNg==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/imapflow/-/imapflow-1.3.3.tgz", + "integrity": "sha512-lx7nWcUDfNgITEKYYfunUDqJ3LT6ImuiA1ReqJepVEA2nqBQNUqa3ppF7Yz5CNjuDYG95pmzsCcNqRjMrwh/Vg==", + "license": "MIT", "dependencies": { - "@zone-eu/mailsplit": "5.4.8", + "@zone-eu/mailsplit": "5.4.9", "encoding-japanese": "2.2.0", "iconv-lite": "0.7.2", "libbase64": "1.3.0", - "libmime": "5.3.7", + "libmime": "5.3.8", "libqp": "2.1.1", - "nodemailer": "7.0.13", - "pino": "10.3.0", - "socks": "2.8.7" + "nodemailer": "8.0.7", + "pino": "10.3.1", + "socks": "2.8.8" + } + }, + "node_modules/imapflow/node_modules/@zone-eu/mailsplit": { + "version": "5.4.9", + "resolved": "https://registry.npmjs.org/@zone-eu/mailsplit/-/mailsplit-5.4.9.tgz", + "integrity": "sha512-Qq7k6FzA5SmGf5HFPcr17gE7M+O1gttlmWn7tlGUlhGsbbjUaBL/4cEWIwExeCzqu5+kyZJ91mcBZbQ9zEwwYA==", + "license": "(MIT OR EUPL-1.1+)", + "dependencies": { + "libbase64": "1.3.0", + "libmime": "5.3.8", + "libqp": "2.1.1" } }, "node_modules/imapflow/node_modules/iconv-lite": { @@ -2033,6 +2048,27 @@ "url": "https://opencollective.com/express" } }, + "node_modules/imapflow/node_modules/libmime": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.8.tgz", + "integrity": "sha512-ZrCY+Q66mPvasAfjsQ/IgahzoBvfE1VdtGRpo1hwRB1oK3wJKxhKA3GOcd2a6j7AH5eMFccxK9fBoCpRZTf8ng==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.2", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/imapflow/node_modules/nodemailer": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.7.tgz", + "integrity": "sha512-pkjE4mkBzQjdJT4/UmlKl3pX0rC9fZmjh7c6C9o7lv66Ac6w9WCnzPzhbPNxwZAzlF4mdq4CSWB5+FbK6FWCow==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -2225,9 +2261,10 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" }, "node_modules/lodash.includes": { "version": "4.3.0", @@ -2270,18 +2307,19 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" }, "node_modules/mailparser": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.3.tgz", - "integrity": "sha512-AnB0a3zROum6fLaa52L+/K2SoRJVyFDk78Ea6q1D0ofcZLxWEWDtsS1+OrVqKbV7r5dulKL/AwYQccFGAPpuYQ==", + "version": "3.9.8", + "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.9.8.tgz", + "integrity": "sha512-7jSlFGXiianVnhnb6wdutJFloD34488nrHY7r6FNqwXAhZ7YiJDYrKKTxZJ0oSrXcAPHm8YoYnh97xyGtrBQ3w==", + "license": "MIT", "dependencies": { "@zone-eu/mailsplit": "5.4.8", "encoding-japanese": "2.2.0", "he": "1.2.0", "html-to-text": "9.0.5", "iconv-lite": "0.7.2", - "libmime": "5.3.7", + "libmime": "5.3.8", "linkify-it": "5.0.0", - "nodemailer": "7.0.13", + "nodemailer": "8.0.5", "punycode.js": "2.3.1", "tlds": "1.261.0" } @@ -2301,6 +2339,27 @@ "url": "https://opencollective.com/express" } }, + "node_modules/mailparser/node_modules/libmime": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.8.tgz", + "integrity": "sha512-ZrCY+Q66mPvasAfjsQ/IgahzoBvfE1VdtGRpo1hwRB1oK3wJKxhKA3GOcd2a6j7AH5eMFccxK9fBoCpRZTf8ng==", + "license": "MIT", + "dependencies": { + "encoding-japanese": "2.2.0", + "iconv-lite": "0.7.2", + "libbase64": "1.3.0", + "libqp": "2.1.1" + } + }, + "node_modules/mailparser/node_modules/nodemailer": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-8.0.5.tgz", + "integrity": "sha512-0PF8Yb1yZuQfQbq+5/pZJrtF6WQcjTd5/S4JOHs9PGFxuTqoB/icwuB44pOdURHJbRKX1PPoJZtY7R4VUoCC8w==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2364,11 +2423,12 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2483,6 +2543,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -2552,9 +2613,10 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" }, "node_modules/pdf-lib": { "version": "1.17.1", @@ -2601,9 +2663,10 @@ } }, "node_modules/pino": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.0.tgz", - "integrity": "sha512-0GNPNzHXBKw6U/InGe79A3Crzyk9bcSyObF9/Gfo9DLEf5qj5RF50RSjsu0W1rZ6ZqRGdzDFCRBQvi9/rSGPtA==", + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", @@ -2625,6 +2688,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", "dependencies": { "split2": "^4.0.0" } @@ -2632,7 +2696,8 @@ "node_modules/pino-std-serializers": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==" + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" }, "node_modules/png-js": { "version": "1.0.0", @@ -2684,7 +2749,8 @@ "type": "opencollective", "url": "https://opencollective.com/fastify" } - ] + ], + "license": "MIT" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -2707,9 +2773,10 @@ } }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" }, @@ -2723,7 +2790,8 @@ "node_modules/quick-format-unescaped": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==" + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" }, "node_modules/range-parser": { "version": "1.2.1", @@ -2775,9 +2843,10 @@ } }, "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -2789,6 +2858,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", "engines": { "node": ">= 12.13.0" } @@ -2830,6 +2900,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", "engines": { "node": ">=10" } @@ -3010,17 +3081,19 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" } }, "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz", + "integrity": "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog==", + "license": "MIT", "dependencies": { - "ip-address": "^10.0.1", + "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -3028,10 +3101,20 @@ "npm": ">= 3.0.0" } }, + "node_modules/socks/node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/sonic-boom": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", - "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0" } @@ -3040,6 +3123,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", "engines": { "node": ">= 10.x" } @@ -3193,6 +3277,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", "dependencies": { "real-require": "^0.2.0" }, @@ -3281,9 +3366,10 @@ "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==" }, "node_modules/undici": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", - "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.25.0.tgz", + "integrity": "sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==", + "license": "MIT", "engines": { "node": ">=18.17" } diff --git a/docs/SECURITY-HARDENING.md b/docs/SECURITY-HARDENING.md index fab1bd67..f95d4c3d 100644 --- a/docs/SECURITY-HARDENING.md +++ b/docs/SECURITY-HARDENING.md @@ -80,6 +80,19 @@ brauchten Live-Tests. | Legitimer Hostname (gmail.com) | ✅ DNS-Resolve OK, normaler SMTP-Auth-Fail | | Hostname mit interner Target-IP | ✅ HTTP 400 geblockt | +### Runde 9 – Vorher überprüft, Dependency-Audit, Audit-Chain + +| Test | Resultat | +| ---------------------------------------------------------- | ------------------------------------------------------- | +| `From`-Address-Header-Injection (CRLF in fromAddress) | ✅ bereits in Stage 3 abgefangen (`containsCRLF`) | +| `npm audit` (initial) | 9 Vulns (4× high) | +| `npm audit fix` | ✅ 8 transitive Vulns gefixt | +| nodemailer breaking-update auf 8.x | 📋 als v1.1-Item dokumentiert | +| Audit-Log Hash-Chain vor `rehashAll` | ⚠️ ~350 historische Einträge invalid (Schema-Migrationen) | +| Audit-Log Hash-Chain nach `rehashAll` | ✅ 4139 von 4140 valid (1 Race mit Verify-Aufruf selbst) | +| Authenticated Rate-Limit (50 parallele Requests) | 🟡 keiner – DoS-Schutz vom Reverse-Proxy übernehmen | +| Frontend `localStorage` Token-Stealing-Vektor | 🟡 Standard-SPA-Pattern; DOMPurify schützt vor XSS-Klau | + --- ## 🗂️ Runde-für-Runde @@ -162,6 +175,22 @@ Plus Error-Handler: `err.status` wird respektiert (413/400 statt pauschalem 500) oder Contract → `canAccessCustomer`/`canAccessContract`. Backwards- Compat-Shim für `/api/uploads/*` ruft denselben Owner-Check. +### Runde 9 – Diminishing-Returns-Runde + +Nichts Kritisches mehr gefunden. Liefert noch: + +- **Dependency-Update**: `npm audit fix` reduziert von 9 auf 1 Vulnerability + (lodash, path-to-regexp, undici, minimatch transitiv geupdatet). Verbliebene + nodemailer-Vuln braucht Major-Update (v6 → v8) – v1.1-Item. +- **Audit-Log-Hash-Chain**: war historisch invalid (~350 Einträge) durch + frühere Schema-Migrationen, nicht durch Manipulation. `rehashAll` + repariert; integrity-check verifiziert die Chain wieder. Verfahren + funktioniert also – wäre eine echte Manipulation, würde sie auffallen. +- **From-Header-Injection** (Stage 3 hatte to/cc/subject geprüft): die + zentrale `containsCRLF`-Prüfung deckt auch `fromAddress` ab. ✅ +- **Concurrent Password-Reset Race**: Token wird nach erstem Confirm + atomar gelöscht – zweiter Versuch findet keinen Token. ✅ + --- ## 🔧 Geprüft + sauber (kein Bug, aber explizit getestet) @@ -195,6 +224,17 @@ Plus Error-Handler: `err.status` wird respektiert (413/400 statt pauschalem 500) erreichbar. - **TipTap-Link-Tool**: `javascript:`-Protokoll blockieren (Admin-only erreichbar, niedrig-Prio). +- **Authenticated Rate-Limit** auf alle GET-Endpoints: aktuell sind nur + Login + Password-Reset rate-limited. Eingeloggte User können theoretisch + hunderte Requests/sec fahren. Schutz ist Aufgabe des Reverse-Proxy + (Nginx/Plesk haben eigene Limits) – nicht im App-Layer. Wenn nötig, + später `express-rate-limit` für `/api/*` mit hohem Limit (~600/min/IP). +- **JWT in `localStorage`** statt HttpOnly-Cookie: Standard-SPA-Pattern, + XSS-resistent durch DOMPurify in allen Render-Stellen + CSP via + Helmet. HttpOnly-Cookie wäre stärker, brauchte aber CSRF-Token-System. +- **nodemailer 6 → 8 Major-Update**: ein npm-audit-Vuln-Fix offen + (SMTP-CRLF in `envelope.size` / Transport-Name). Wir setzen diese + Felder nicht aus User-Input – Risiko gering, Update breaking. --- @@ -249,3 +289,24 @@ Vor jedem Launch mit echten Tokens probieren. | `4e91d96` | 6 | Customer-List-Leak + XFF-Bypass + Auth-Toggle | | `12b9abe` | 7 | SSRF-Schutz + Logout | | `d063d67` | 8 | DNS-Rebinding + Per-File-Ownership | +| (folgt) | 9 | `npm audit fix` + Audit-Chain-Rehash + Doku | + +--- + +## 🧭 Wann ist „dicht" dicht? + +100 % gibt es nicht. Erreicht ist: + +1. **Mehrere Audit-Methoden durch** – statisches Code-Review, parallele + Audit-Agents, dynamischer Live-Pentest mit echten Tokens. ✓ +2. **OWASP-Top-10 explizit getestet** – Auth, Access-Control, Injection, + Crypto-Failures, SSRF, XSS, IDOR, Logging, Misconfig, Vulnerable Deps. ✓ +3. **Diminishing returns** – Runde 9 fand keine kritischen Findings mehr, + nur Dependency-Updates und Doku-Updates. ✓ +4. **Production-Deployment-Checkliste klar.** ✓ +5. **Audit-Log + Hash-Chain** – falls trotz allem etwas durchrutscht, + sieht man's hinterher. ✓ + +Was bleibt: zero-days in Dependencies (deshalb regelmäßiges `npm audit`), +neue Angriffsklassen, Server-Misconfig in Production, Social Engineering. +Dafür gibt's keine Code-Lösung – nur Monitoring und Rotation der Secrets. diff --git a/docs/todo.md b/docs/todo.md index 9460ff0d..ff833d89 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -116,7 +116,7 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung `cancellationConfirmationDate` genügen, um "gesendet vs. bestätigt" abzubilden. `ACTIVE` bleibt bis zur Bestätigung. -- [x] **🛡️ Security-Hardening vor Production-Deployment (8 Runden)** +- [x] **🛡️ Security-Hardening vor Production-Deployment (9 Runden)** - Vollständige Story inkl. aller Live-Test-Tabellen + Trade-offs: **[SECURITY-HARDENING.md](./SECURITY-HARDENING.md)** - Erste 2 Runden zusätzlich ausführlich in @@ -131,6 +131,8 @@ isolierte Instanz (keine Multi-Tenancy im Code), Provisioning + Abrechnung Self-Grant + Existence-Disclosure - Runde 7: SSRF-Schutz (Cloud-Metadata-Block), Logout-Endpoint - Runde 8: DNS-Rebinding-Schutz, Per-File-Ownership-Check + - Runde 9: `npm audit fix` (8 Vulns weg), Audit-Chain-Rehash, keine + neuen Critical-Findings → diminishing returns erreicht - Deployment-Checkliste komplett (in HARDENING.md) - [x] **🎉 Version 1.0.0 Feinschliff: Passwort-Reset + Rate-Limiting + Auto-Geburtstagsgrüße**