From ea66e6c9c71e6316b79335d879f2c07623281aae Mon Sep 17 00:00:00 2001 From: Pouzor Date: Tue, 9 Jun 2026 16:29:52 +0200 Subject: [PATCH 1/2] chore: bump hono to 4.12.21+ and ignore versioned db backups Add npm override forcing hono>=4.12.21 to resolve 4 Dependabot alerts (transitive via shadcn CLI, dev-only). Add *.db.back-* to .gitignore to exclude versioned database backups. ha-relevant: no --- .gitignore | 1 + frontend/package-lock.json | 6 +++--- frontend/package.json | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 252f8e0..70c818c 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ htmlcov/ *.db-shm *.db-wal *.db.back +*.db.back-* # Docker .docker/ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 787af1c..1ce9089 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6196,9 +6196,9 @@ } }, "node_modules/hono": { - "version": "4.12.18", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", - "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", + "version": "4.12.25", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", + "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", "license": "MIT", "engines": { "node": ">=16.9.0" diff --git a/frontend/package.json b/frontend/package.json index 4661af3..80ac42d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,6 +37,9 @@ "tw-animate-css": "^1.4.0", "zustand": "^5.0.11" }, + "overrides": { + "hono": "^4.12.21" + }, "devDependencies": { "@eslint/js": "^9.39.1", "@tailwindcss/vite": "^4.2.1", From 7c2417f5a991a0cafe25d53ea823aafe765d9651 Mon Sep 17 00:00:00 2001 From: Pouzor Date: Tue, 9 Jun 2026 16:51:32 +0200 Subject: [PATCH 2/2] fix(security): resolve code scanning alerts Add least-privilege 'permissions: contents: read' to quality, security and docker-ci workflows (actions/missing-workflow-permissions). Harden markdown table cell escaping in exportMarkdown: escape backslash before pipe and collapse newlines so untrusted values can't break the table (js/incomplete-sanitization). Add regression tests. ha-relevant: maybe --- .github/workflows/docker-ci.yml | 3 +++ .github/workflows/quality.yml | 3 +++ .github/workflows/security.yml | 3 +++ .../utils/__tests__/exportMarkdown.test.ts | 27 +++++++++++++++++++ frontend/src/utils/exportMarkdown.ts | 9 ++++--- 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-ci.yml b/.github/workflows/docker-ci.yml index 227be16..dde50c0 100644 --- a/.github/workflows/docker-ci.yml +++ b/.github/workflows/docker-ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: smoke-and-integration: runs-on: ubuntu-latest diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index b6a2bd4..6c8ded2 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: lint-scripts: runs-on: ubuntu-latest diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 043efac..3118aec 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -8,6 +8,9 @@ on: schedule: - cron: '0 9 * * 1' # Weekly on Monday +permissions: + contents: read + jobs: secrets-scan: runs-on: ubuntu-latest diff --git a/frontend/src/utils/__tests__/exportMarkdown.test.ts b/frontend/src/utils/__tests__/exportMarkdown.test.ts index 6da24f4..edd52a1 100644 --- a/frontend/src/utils/__tests__/exportMarkdown.test.ts +++ b/frontend/src/utils/__tests__/exportMarkdown.test.ts @@ -53,6 +53,33 @@ describe('generateMarkdownTable', () => { expect(md).toContain('A\\|B') }) + it('escapes backslashes before pipes so the escape char is not ambiguous', () => { + const nodes = [makeNode({ label: 'A\\|B' })] + const md = generateMarkdownTable(nodes) + // backslash doubled, then the literal pipe escaped + expect(md).toContain('A\\\\\\|B') + }) + + it('collapses newlines in cell values so they do not break the table', () => { + const nodes = [makeNode({ label: 'line1\nline2', hostname: 'a\r\nb' })] + const lines = generateMarkdownTable(nodes).split('\n') + // header + separator + exactly one data row (no extra line from the value) + expect(lines).toHaveLength(3) + expect(lines[2]).toContain('line1 line2') + expect(lines[2]).toContain('a b') + }) + + it('escapes pipe characters inside service names', () => { + const nodes = [makeNode({ + label: 'Server', + services: [{ port: 80, protocol: 'tcp', service_name: 'web|proxy' }], + })] + const lines = generateMarkdownTable(nodes).split('\n') + // header + separator + exactly one data row — the pipe must not add a column + expect(lines).toHaveLength(3) + expect(lines[2]).toContain('web\\|proxy') + }) + it('generates one row per non-groupRect node', () => { const nodes = [ makeNode({ type: 'server', label: 'A' }, '1'), diff --git a/frontend/src/utils/exportMarkdown.ts b/frontend/src/utils/exportMarkdown.ts index 4dfef69..7205b9f 100644 --- a/frontend/src/utils/exportMarkdown.ts +++ b/frontend/src/utils/exportMarkdown.ts @@ -5,8 +5,11 @@ const EMPTY = '—' function cell(v: string | null | undefined): string { if (!v) return EMPTY - // Escape pipe chars so they don't break the table - return v.replace(/\|/g, '\\|') + // Escape backslashes first, then pipes, and collapse newlines so they don't break the table + return v + .replace(/\\/g, '\\\\') + .replace(/\|/g, '\\|') + .replace(/\r?\n/g, ' ') } export function generateMarkdownTable(nodes: Node[]): string { @@ -27,7 +30,7 @@ export function generateMarkdownTable(nodes: Node[]): string { cell(d.ip), cell(d.hostname), cell(d.status), - services, + cell(services), ] })