fix: preserve Markdown code fences by escaping backticks instead of removing them (fixes #6)

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>
This commit is contained in:
2026-04-28 12:15:28 -05:00
parent edd445f8ae
commit 3922056b25
2 changed files with 10 additions and 6 deletions

View File

@@ -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}"`;
}

View File

@@ -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