Back to skill

Security audit

Obsidian Daily Log

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent purpose, but its updater script can be steered to modify Markdown files outside the intended daily-notes folder if unsafe arguments are passed.

Review before installing. This appears to be a personal Obsidian logging helper, not an exfiltration or persistence tool, but the updater should validate dates and constrain writes to the daily-notes directory before use, especially in shared-chat workflows where unexpected input may influence logging commands.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/update_daily_log.py:157
Finding
Unvalidated Date Argument Enables Path Traversal and Arbitrary Markdown File Modification## Vulnerability Details **File Location**: `scripts/update_daily_log.py`, lines 157 and 170-178 **Vulnerability Type**: Path traversal caused by insufficient input validation **Risk Level**: Medium ### Vulnerable Code ```python def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Append timestamped entries to an Obsidian daily note.") parser.add_argument("--date", required=True, help="Date in YYYY-MM-DD") parser.add_argument("--time", action="append", required=True, help="Time for one entry (repeat for multiple entries)") parser.add_argument("--text", action="append", required=True, help="Activity text for one entry (repeat in same order as --time)") parser.add_argument("--location", action="append", help="Optional location for one entry (repeat in same order)") parser.add_argument("--tags", action="append", help="Optional tags for one entry (repeat in same order)") parser.add_argument("--mode", choices=["bullets", "table"], default="bullets") parser.add_argument("--daily-dir", default=str(DEFAULT_DAILY_DIR)) parser.add_argument("--template", default=str(DEFAULT_TEMPLATE)) return parser.parse_args() ``` ```python def main() -> int: args = parse_args() entries = build_entries(args) note_path = Path(args.daily_dir) / f"{args.date}.md" template_path = Path(args.template) ensure_note(note_path, args.date, template_path) content = note_path.read_text(encoding="utf-8") updated = update_timeline(content, entries, args.mode) note_path.write_text(updated, encoding="utf-8") print(str(note_path)) return 0 ``` The validation bypass is enabled by `scripts/update_daily_log.py`, lines 92-95: ```python def ensure_note(note_path: Path, date_str: str, template_path: Path) -> None: if note_path.exists(): return note_path.parent.mkdir(parents=True, exist_ok=True) note_path.write_text(load_template(date_str, template_path), encoding="utf-8") ` ...[truncated 2882 chars]
Remediation
## Remediation Suggestions 1. Validate the date unconditionally before any filesystem operation: ```python parsed_date = datetime.strptime(args.date, "%Y-%m-%d") safe_date = parsed_date.strftime("%Y-%m-%d") ``` 2. Construct the filename only from the normalized value: ```python note_path = Path(args.daily_dir) / f"{safe_date}.md" ``` 3. Resolve the base directory and destination and enforce containment: ```python daily_dir = Path(args.daily_dir).resolve() note_path = (daily_dir / f"{safe_date}.md").resolve() if note_path.parent != daily_dir: raise ValueError("Daily note path must remain inside the daily-note directory") ``` 4. Reject values containing path separators, absolute paths, parent-directory components, or any input that does not exactly match the required date representation. 5. Perform validation before checking whether the destination exists so an existing file cannot bypass validation. 6. If callers do not need configurable paths, remove or restrict `--daily-dir` and `--template`. Otherwise, validate them against an explicit allowlisted vault root. 7. Add regression tests covering: - Valid `YYYY-MM-DD` dates. - `../` and `..\` traversal attempts. - Absolute-path input. - Traversal to existing and nonexistent files. - Encoded or mixed-separator path variants. - Verification that the resolved destination is a direct child of the configured daily-note directory.
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill clearly instructs the agent to read and write files in a local Obsidian vault and to run a local update script, but it declares no explicit tool scope or allowed-tools restriction. That mismatch creates an overprivilege and transparency problem: the runtime may permit broader file operations than intended, and reviewers or policy systems cannot reliably constrain the skill to the minimum necessary access.

Static analysis

No suspicious patterns detected.