From 3922056b2569ece6b90e92d30397021e5a251dc7 Mon Sep 17 00:00:00 2001 From: "Peter.Morton" Date: Tue, 28 Apr 2026 12:15:28 -0500 Subject: [PATCH] fix: preserve Markdown code fences by escaping backticks instead of removing them (fixes #6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backticks were being stripped entirely by the sanitizer, destroying Markdown code fences (```) in note content. The real injection risk is backtick command substitution inside double-quoted shell strings (e.g. content=`rm -rf /`). The fix is to escape backticks as \` in formatParam — exactly as we already do for double quotes — so the shell never interprets them while the content is preserved intact. Changes: - sanitizer.ts: remove ` from DANGEROUS_CHARS and the backtick command substitution pattern from COMMAND_INJECTION_PATTERNS (now handled at the quoting layer, not the stripping layer) - cli-helpers.ts: escape backticks as \` in formatParam alongside the existing double-quote escaping Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/utils/cli-helpers.ts | 9 ++++++--- src/validation/sanitizer.ts | 7 ++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/utils/cli-helpers.ts b/src/utils/cli-helpers.ts index f68dcbe..d0f2de1 100644 --- a/src/utils/cli-helpers.ts +++ b/src/utils/cli-helpers.ts @@ -14,9 +14,12 @@ export function formatParam(key: string, value: string | number): string { // Always quote string values to handle spaces and special characters safely // Note: Obsidian CLI docs say: "Quote values with spaces: name="My Note"" - // Escape any double quotes in the value to prevent shell interpretation issues - // This prevents truncation when content contains quotes like "Bot QM" - const escapedValue = String(value).replace(/"/g, '\\"'); + // Escape double quotes and backticks to prevent shell interpretation inside double-quoted strings. + // In bash double-quoted strings: \" prevents quote termination, \` prevents command substitution. + // This preserves Markdown code fences (``` ` ```) while blocking injection via backticks. + const escapedValue = String(value) + .replace(/"/g, '\\"') + .replace(/`/g, '\\`'); return `${key}="${escapedValue}"`; } diff --git a/src/validation/sanitizer.ts b/src/validation/sanitizer.ts index d7bff0c..3c38636 100644 --- a/src/validation/sanitizer.ts +++ b/src/validation/sanitizer.ts @@ -11,13 +11,14 @@ import { logger } from '../utils/logger.js'; * Note: Brackets [], parentheses (), and braces {} are safe because values are quoted and passed as array args * They're essential for Obsidian markdown (wikilinks [[link]], tasks - [ ] Task, templates {{...}}, etc.) * Note: Single & is safe in quoted args (filenames like "Research & Development.md") - * We only block: ; | ` $ < > (command separators, pipes, substitution, redirects) + * Note: Backticks are safe because formatParam escapes them as \` inside double-quoted strings, + * preventing shell command substitution while preserving Markdown code fences (``` ```) + * We only block: ; | $ < > (command separators, pipes, substitution, redirects) * Command injection patterns (&&, ||, etc.) are handled separately */ -const DANGEROUS_CHARS = /[;|`$<>]/g; +const DANGEROUS_CHARS = /[;|$<>]/g; const COMMAND_INJECTION_PATTERNS = [ /\$\(/g, // Command substitution $(...) - /`[^`]*`/g, // Command substitution `...` /\|\|/g, // OR operator /&&/g, // AND operator /;/g, // Command separator