diff --git a/front/assets/js/report/index.tsx b/front/assets/js/report/index.tsx index ed07c5702..02f71bc12 100644 --- a/front/assets/js/report/index.tsx +++ b/front/assets/js/report/index.tsx @@ -9,7 +9,7 @@ import DOMPurify from 'dompurify'; import * as toolbox from "js/toolbox"; import { useEffect, useState } from "preact/hooks"; -Mermaid.initialize({ startOnLoad: false, theme: `default`, securityLevel: `strict` }); +Mermaid.initialize({ startOnLoad: false, theme: `default`, securityLevel: `sandbox` }); const md = MarkdownIt({ html: true, linkify: false, @@ -83,6 +83,21 @@ const MarkdownBody = (props: { markdown: string, }) => { }, [props.markdown]); const renderedHtml = md.render(props.markdown); + // Note: Sanitization is applied here before mermaid rendering. Some mermaid-specific tags + // (like those generated by markdown-it-textual-uml) are intentionally not included in ALLOWED_TAGS + // because they're processed by Mermaid.run() after sanitization. + // Additionally, Mermaid provides two more security layers: + // 1. It uses DOMPurify internally for sanitizing diagram content + // 2. With securityLevel: 'sandbox' configured above, it renders each diagram in a sandboxed iframe + // First, configure DOMPurify hooks + DOMPurify.addHook(`afterSanitizeAttributes`, function(node) { + // Force all links to open in new tab with security attributes + if (`tagName` in node && node.tagName === `A`) { + node.setAttribute(`target`, `_blank`); + node.setAttribute(`rel`, `noopener noreferrer nofollow`); + } + }); + const sanitizedHtml = DOMPurify.sanitize(renderedHtml, { ALLOWED_TAGS: [ // Basic @@ -98,17 +113,29 @@ const MarkdownBody = (props: { markdown: string, }) => { `mark`, `ins`, `small`, - `abbr` + `abbr`, + // Links (safe with DOMPurify's URL sanitization) + `a` ], ALLOWED_ATTR: [ `title`, - `open` + `open`, + `class`, + `href`, // DOMPurify by default blocks dangerous protocols (javascript:, data:, vbscript:) and only allows safe ones (http:, https:, mailto:, etc.) + `target`, + `rel` ], - FORBID_TAGS: [`a`, `img`, `script`, `object`, `embed`, `iframe`, `link`], - FORBID_ATTR: [`href`, `src`, `class`, `id`, `style`, `target`], - ALLOW_DATA_ATTR: false + // Critical: Keep blocking dangerous tags that were part of the original vulnerability + FORBID_TAGS: [`img`, `script`, `object`, `embed`, `iframe`, `link`, `form`, `input`, `style`, `meta`, `base`], + FORBID_ATTR: [`src`, `id`, `style`, `onclick`, `onload`, `onerror`, `action`, `method`], + ALLOW_DATA_ATTR: false, + // Force secure link attributes + ADD_ATTR: [`target`, `rel`] }); + // Clean up the hook after sanitization to avoid memory leaks + DOMPurify.removeHook(`afterSanitizeAttributes`); + return (
=14" @@ -9650,13 +9661,13 @@ } }, "node_modules/mermaid": { - "version": "11.6.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.6.0.tgz", - "integrity": "sha512-PE8hGUy1LDlWIHWBP05SFdqUHGmRcCcK4IzpOKPE35eOw+G9zZgcnMpyunJVUEOgb//KBORPjysKndw8bFLuRg==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.12.0.tgz", + "integrity": "sha512-ZudVx73BwrMJfCFmSSJT84y6u5brEoV8DOItdHomNLz32uBjNrelm7mg95X7g+C6UoQH/W6mBLGDEDv73JdxBg==", "dependencies": { - "@braintree/sanitize-url": "^7.0.4", - "@iconify/utils": "^2.1.33", - "@mermaid-js/parser": "^0.4.0", + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.1", + "@mermaid-js/parser": "^0.6.2", "@types/d3": "^7.4.3", "cytoscape": "^3.29.3", "cytoscape-cose-bilkent": "^4.1.0", @@ -9664,12 +9675,12 @@ "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.11", - "dayjs": "^1.11.13", - "dompurify": "^3.2.4", - "katex": "^0.16.9", + "dayjs": "^1.11.18", + "dompurify": "^3.2.5", + "katex": "^0.16.22", "khroma": "^2.1.0", "lodash-es": "^4.17.21", - "marked": "^15.0.7", + "marked": "^16.2.1", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", @@ -9677,14 +9688,14 @@ } }, "node_modules/mermaid/node_modules/marked": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.8.tgz", - "integrity": "sha512-rli4l2LyZqpQuRve5C0rkn6pj3hT8EWPC+zkAxFTAJLxRbENfTAhEQq9itrmf1Y81QtAX5D/MYlGlIomNgj9lA==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.3.0.tgz", + "integrity": "sha512-K3UxuKu6l6bmA5FUwYho8CfJBlsUWAooKtdGgMcERSpF7gcBUrCGsLH7wDaaNOzwq18JzSUDyoEb/YsrqMac3w==", "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 18" + "node": ">= 20" } }, "node_modules/mermaid/node_modules/uuid": { @@ -10206,20 +10217,20 @@ } }, "node_modules/mlly": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", - "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dependencies": { - "acorn": "^8.14.0", - "pathe": "^2.0.1", - "pkg-types": "^1.3.0", - "ufo": "^1.5.4" + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" } }, "node_modules/mlly/node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "bin": { "acorn": "bin/acorn" }, @@ -11181,12 +11192,9 @@ } }, "node_modules/package-manager-detector": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.11.tgz", - "integrity": "sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==", - "dependencies": { - "quansync": "^0.2.7" - } + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", + "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==" }, "node_modules/pako": { "version": "2.1.0", @@ -11340,12 +11348,12 @@ } }, "node_modules/pkg-types": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", - "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", "dependencies": { - "confbox": "^0.2.1", - "exsolve": "^1.0.1", + "confbox": "^0.2.2", + "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, @@ -12118,11 +12126,11 @@ } }, "node_modules/posthog-js": { - "version": "1.261.6", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.261.6.tgz", - "integrity": "sha512-tson+4i+T2YkGYlj/oGjFwKRpBFqhM7Xr9ZmXGEtNFkZc6ZQHYCzObeeHT6BbKc5d/dAfMCPtvPCKssARaK6eQ==", + "version": "1.268.8", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.268.8.tgz", + "integrity": "sha512-BJiKK4MlUvs7ybnQcy1KkwAz+SZkE/wRLotetIoank5kbqZs8FLbeyozFvmmgx4aoMmaVymYBSmYphYjYQeidw==", "dependencies": { - "@posthog/core": "1.0.2", + "@posthog/core": "1.2.2", "core-js": "^3.38.1", "fflate": "^0.4.8", "preact": "^10.19.3", @@ -12315,9 +12323,9 @@ } }, "node_modules/quansync": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", - "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", "funding": [ { "type": "individual", @@ -13252,9 +13260,9 @@ "dev": true }, "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==" }, "node_modules/tinyglobby": { "version": "0.2.14", diff --git a/front/assets/package.json b/front/assets/package.json index 10a42a737..ef99bf15f 100644 --- a/front/assets/package.json +++ b/front/assets/package.json @@ -43,7 +43,7 @@ "markdown-it": "^14.1.0", "markdown-it-textual-uml": "^0.17.1", "marked": "^9.1.2", - "mermaid": "^11.6.0", + "mermaid": "^11.12.0", "moment": "^2.29.4", "moment-duration-format": "^2.3.2", "monaco-yaml": "^5.2.3", @@ -68,6 +68,7 @@ "@types/chai": "^4.3.1", "@types/d3": "^7.4.0", "@types/d3-time-format": "^4.0.0", + "@types/dompurify": "^3.0.5", "@types/jquery": "^3.5.14", "@types/jsdom": "^21.1.5", "@types/lodash": "^4.14.182", diff --git a/front/priv/storage/reports/job_report.md b/front/priv/storage/reports/job_report.md index cb7950d64..d23b8f151 100644 --- a/front/priv/storage/reports/job_report.md +++ b/front/priv/storage/reports/job_report.md @@ -1,21 +1,46 @@ -# Job Report +## 🎯 System Metrics Summary -This is a test job report. +**Total datapoints:** `40` +**🕒 Time Range:** `Tue Sep 23 08:57:29 UTC 2025` → `Tue Sep 23 08:58:10 UTC 2025` + +- **🔥 CPU:** `min: 3.40%`, `max: 135.80%` +- **🧠Memory:** `min: 3.94%`, `max: 5.76%` +- **💽 System Disk:** `min: 31.60%`, `max: 37.09%` +- **🐳 Docker Disk:** `min: 27.93%`, `max: 27.93%` --- ```mermaid -gitGraph: - commit "Ashish" - branch newbranch - checkout newbranch - commit id:"1111" - commit tag:"tessst" - checkout main - commit type: HIGHLIGHT - commit - merge newbranch - commit - branch b2 - commit +xychart-beta +title "CPU Usage" +x-axis ["00:00", "00:01", "00:02", "00:04", "00:05", "00:06", "00:07", "00:08", "00:09", "00:10", "00:11", "00:12", "00:13", "00:14", "00:15", "00:16", "00:17", "00:18", "00:19", "00:20", "00:21", "00:22", "00:23", "00:24", "00:25", "00:26", "00:27", "00:29", "00:30", "00:31", "00:32", "00:33", "00:34", "00:35", "00:36", "00:37", "00:38", "00:39", "00:40", "00:41"] +y-axis "Usage (%)" +line [6.90, 12.00, 8.40, 25.10, 39.50, 44.30, 46.20, 47.90, 48.30, 43.50, 44.50, 46.40, 47.30, 47.90, 47.90, 10.20, 66.70, 3.70, 129.70, 135.80, 131.70, 129.70, 130.70, 129.70, 126.50, 122.40, 124.40, 126.50, 127.40, 128.40, 129.30, 130.30, 122.40, 123.30, 3.40, 3.40, 35.40, 23.40, 23.90, 3.40] +bar [6.90, 12.00, 8.40, 25.10, 39.50, 44.30, 46.20, 47.90, 48.30, 43.50, 44.50, 46.40, 47.30, 47.90, 47.90, 10.20, 66.70, 3.70, 129.70, 135.80, 131.70, 129.70, 130.70, 129.70, 126.50, 122.40, 124.40, 126.50, 127.40, 128.40, 129.30, 130.30, 122.40, 123.30, 3.40, 3.40, 35.40, 23.40, 23.90, 3.40] +``` + +```mermaid +xychart-beta +title "Memory Usage" +x-axis ["00:00", "00:01", "00:02", "00:04", "00:05", "00:06", "00:07", "00:08", "00:09", "00:10", "00:11", "00:12", "00:13", "00:14", "00:15", "00:16", "00:17", "00:18", "00:19", "00:20", "00:21", "00:22", "00:23", "00:24", "00:25", "00:26", "00:27", "00:29", "00:30", "00:31", "00:32", "00:33", "00:34", "00:35", "00:36", "00:37", "00:38", "00:39", "00:40", "00:41"] +y-axis "Usage (%)" +line [4.35, 4.36, 4.35, 4.34, 4.06, 4.22, 4.20, 4.21, 4.39, 4.72, 4.62, 4.75, 4.76, 4.65, 4.58, 5.76, 5.46, 5.35, 4.52, 4.51, 3.98, 4.08, 4.21, 3.96, 3.94, 4.11, 4.23, 4.07, 4.44, 4.15, 4.29, 4.05, 4.37, 4.57, 4.24, 4.72, 4.83, 4.81, 4.99, 4.84] +bar [4.35, 4.36, 4.35, 4.34, 4.06, 4.22, 4.20, 4.21, 4.39, 4.72, 4.62, 4.75, 4.76, 4.65, 4.58, 5.76, 5.46, 5.35, 4.52, 4.51, 3.98, 4.08, 4.21, 3.96, 3.94, 4.11, 4.23, 4.07, 4.44, 4.15, 4.29, 4.05, 4.37, 4.57, 4.24, 4.72, 4.83, 4.81, 4.99, 4.84] ``` + +```mermaid +xychart-beta +title "System Disk Usage" +x-axis ["00:00", "00:01", "00:02", "00:04", "00:05", "00:06", "00:07", "00:08", "00:09", "00:10", "00:11", "00:12", "00:13", "00:14", "00:15", "00:16", "00:17", "00:18", "00:19", "00:20", "00:21", "00:22", "00:23", "00:24", "00:25", "00:26", "00:27", "00:29", "00:30", "00:31", "00:32", "00:33", "00:34", "00:35", "00:36", "00:37", "00:38", "00:39", "00:40", "00:41"] +y-axis "Disk Usage (%)" +line [31.60, 31.60, 31.60, 31.61, 31.65, 31.69, 31.73, 31.77, 31.81, 31.85, 31.89, 31.93, 31.97, 32.01, 32.05, 32.43, 32.68, 32.68, 32.86, 33.09, 33.24, 33.31, 33.65, 34.07, 33.70, 33.92, 34.44, 34.44, 34.73, 35.18, 35.68, 35.73, 36.05, 36.48, 36.78, 37.04, 37.05, 37.05, 37.05, 37.09] +bar [31.60, 31.60, 31.60, 31.61, 31.65, 31.69, 31.73, 31.77, 31.81, 31.85, 31.89, 31.93, 31.97, 32.01, 32.05, 32.43, 32.68, 32.68, 32.86, 33.09, 33.24, 33.31, 33.65, 34.07, 33.70, 33.92, 34.44, 34.44, 34.73, 35.18, 35.68, 35.73, 36.05, 36.48, 36.78, 37.04, 37.05, 37.05, 37.05, 37.09] +``` +```mermaid +xychart-beta +title "Docker Disk Usage" +x-axis ["00:00", "00:01", "00:02", "00:04", "00:05", "00:06", "00:07", "00:08", "00:09", "00:10", "00:11", "00:12", "00:13", "00:14", "00:15", "00:16", "00:17", "00:18", "00:19", "00:20", "00:21", "00:22", "00:23", "00:24", "00:25", "00:26", "00:27", "00:29", "00:30", "00:31", "00:32", "00:33", "00:34", "00:35", "00:36", "00:37", "00:38", "00:39", "00:40", "00:41"] +y-axis "Disk Usage (%)" +line [27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93] +bar [27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93, 27.93] +``` \ No newline at end of file diff --git a/front/priv/storage/reports/wf_report.md b/front/priv/storage/reports/wf_report.md index e72b25695..af2ac2816 100644 --- a/front/priv/storage/reports/wf_report.md +++ b/front/priv/storage/reports/wf_report.md @@ -1,3 +1,179 @@ -# Workflow Report +# Security requirements +This markdown should be safely rendered to keep compliance with [project-tasks/issues#2650](https://github.com/renderedtext/project-tasks/issues/2650) -This is a test workflow report. +# Domain stats + +## Security Test - Safe Links and Potential XSS Attempts (for testing sanitization) + +These are safe test cases to verify sanitization is working: + +1. [Normal link to GitHub](https://github.com) +2. [Link with onclick attempt](https://example.com" onclick="alert('XSS')) +3. JavaScript protocol test +4. Data URL test +5. [Regular markdown link](https://www.example.com) +6. Link with onclick attribute +7. VBScript protocol test + +## Test - Mermaid Injection Attempts + +### Attempt 1: Breaking out with closing tags +```mermaid +graph TD + A[Start] --> B[Process] + B --> C[End
] +``` + +### Attempt 2: Using mermaid syntax with HTML-like content +```mermaid +graph LR + A[""] --> B[Next] + C[Test] --> D[End] +``` + +### Attempt 3: Classic mermaid escape attempt +mermaid + + +
+ + +
+ + +### Attempt 4: Using click events (valid mermaid syntax) + +```mermaid +graph TD + A[Click me - should be clickable but no XSS] -->|click| B[Process] + click A "javascript:alert('XSS')" + click B href "javascript:void(0)" "Tooltip" + click A "https://example.com" "This safe link should work" +``` + +### Attempt 5: Subgraph with HTML injection +```mermaid +graph TD + subgraph "" + A[Node A] + end + subgraph "Test" + B[Node B] + end + A --> B +``` + +### Attempt 6: Class definitions with malicious content +```mermaid +classDiagram + class BankAccount{ + +String owner + +BigDecimal balance + +deposit(amount) bool + +withdrawal + } + class Evil { + <> + +hack() + } +``` + +### Attempt 7: Sequence diagram with injections +```mermaid +sequenceDiagram + participant A as Alice + participant B as Bob + A->>B: Hello + Note over A,B:
+``` + +### Attempt 8: Gantt chart with HTML +```mermaid +gantt + title A Gantt Diagram + dateFormat YYYY-MM-DD + section Section + A task :a1, 2014-01-01, 30d + Another task :after a1, 20d +``` + + +### Attempt 10: State diagram with onclick +```mermaid +stateDiagram-v2 + [*] --> First: Start + First --> Second: GoClick + Second --> [*]: End +``` +### Attempt 11: The original Cure53 vulnerability pattern +```mermaid +graph TD + A[Start] --> B[Middle] +``` + +```mermaid + + +
+ + +
+
+```
+
+### Attempt 12: Using link styling in flowchart
+```mermaid
+flowchart LR
+    A[Start] --> B{Is it working?}
+    B -->|Yes| C[Great]
+    B -->|No| D[Debug]
+
+    style A fill:#f9f,stroke:#333,stroke-width:4px,onclick:alert('styled')
+
+    click A "javascript:alert('XSS')" _blank
+    click B "data:text/html,"
+```
+
+## Test from https://github.com/renderedtext/project-tasks/issues/2650
+
+```mermaid
+
+ +
+ + +
+``` \ No newline at end of file