Back to skill

Security audit

Obsidian Manager

Security checks for vulnerabilities and agentic risk

Overview

This is a local Obsidian note helper, but its scripts do not adequately constrain file paths and can read or write Markdown files outside the intended research vault.

Review before installing. Use this only with a trusted local Obsidian vault, avoid passing absolute paths or '..' in direction/title arguments, and prefer a fixed allowlist of vault subdirectories until the scripts add path containment validation.

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
obsidian_new.py:136
Finding

Path Traversal Enables Filesystem Access Outside the Research Vault

Content
View full analysis

Vulnerability Details

File Location: obsidian_new.py:136-155, 207-209; obsidian_search.py:35-47, 139-145
Vulnerability Type: Unrestricted path traversal and insufficient filesystem boundary validation
Risk Level: Medium

Vulnerable Code

obsidian_new.py:

python
def get_direction_path(direction):
    """获取研究方向目录路径"""
    base = get_research_base_path()
    
    # 如果 direction 是编号(如"01"),转换为完整名称
    if direction in DIRECTIONS:
        direction = DIRECTIONS[direction]
    
    dir_path = base / direction
    if not dir_path.exists():
        print(f"错误:研究方向目录不存在:{dir_path}")
        print(f"可用方向:{', '.join(DIRECTIONS.values())}")
        return None
    
    return dir_path
python
# 生成文件名
filename = f"{title}.md"
file_path = dir_path / filename

# 检查文件是否已存在
if file_path.exists():
    print(f"警告:文件已存在:{file_path}")
    overwrite = input("是否覆盖?(y/n): ")
    if overwrite.lower() != 'y':
        print("已取消")
        return None
python
# 写入文件
with open(file_path, 'w', encoding='utf-8') as f:
    f.write(content)

obsidian_search.py:

python
# 确定搜索目录
search_dirs = [base]
if direction:
    direction_dir = base / direction
    if direction_dir.exists():
        search_dirs = [direction_dir]
    else:
        print(f"警告:研究方向目录不存在:{direction}")
    
# 遍历所有 markdown 文件
for search_dir in search_dirs:
    for md_file in search_dir.rglob('*.md'):
        # 跳过模板文件
        if md_file.name == 'template.md':
            continue
        
        try:
            with open(md_file, 'r', encoding='utf-8') as f:
                content = f.read()
python
if direction:
    direction_dir = base / direction
    if not direction_dir.exists():
        print(f"错误:研究方向目录不存在:{direction}")
        return []
    
    md_files = list(direction_dir.glob('*.md'))
    return [{'title': f.stem, 'file':
...[truncated 3466 chars]
Remediation
View remediation

Remediation Suggestions

  1. Resolve and validate the vault root before using any user-controlled path:

    python
    base = get_research_base_path().resolve(strict=True)
    
  2. Prefer an allowlist for research directions. Accept only keys or exact directory names present in DIRECTIONS rather than arbitrary path strings.

  3. Resolve every candidate directory and verify containment:

    python
    candidate = (base / direction).resolve(strict=True)
    if not candidate.is_relative_to(base):
        raise ValueError("Direction must remain inside the research vault")
    
  4. Reject absolute paths, .. components, path separators, null characters, and platform-reserved filename characters in note titles. A title should be treated as a filename component rather than a path.

  5. Validate the final note path independently after appending the filename:

    python
    file_path = (candidate / f"{safe_title}.md").resolve()
    if not file_path.is_relative_to(base):
        raise ValueError("Note path must remain inside the research vault")
    
  6. Use exclusive creation mode ("x") for new notes. If overwrite support is required, expose an explicit authenticated or deliberate --overwrite option and repeat the containment check immediately before writing.

  7. Apply the same resolved-path containment checks before rglob(), glob(), open(), and relative_to() in all search and listing paths.

  8. Consider rejecting symlinked direction directories or resolving symlinks and confirming that their final targets remain inside the vault.

  9. Add automated tests covering absolute paths, nested traversal, symlink escapes, mixed path separators, crafted titles, and legitimate allowlisted research directories.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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 (4)

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · README.md (reported line 1)May include surrounding context.

md
# Obsidian Manager 鎶€鑳?
**鐗堟湰锛?* v0.1  
**鍒涘缓鏃堕棿锛?* 2026 骞?3 鏈?26 鏃? 
**鐘舵€侊細** 馃攧 寮€鍙戜腑

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file contains user-facing instructions, descriptions, and warnings entirely in Chinese, including the primary description and command guidance. That can violate a language/locale policy when the skill forces a specific language for all users without documenting a choice, opt-in, or region-specific justification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The README discloses a concrete local filesystem path (D:\Personal\OpenClaw\research\), which reveals host-specific environment details and project layout. While not directly exploitable by itself, this kind of information disclosure can aid reconnaissance, expose usernames/project names, and encourage unsafe assumptions that the skill should operate on a fixed local path.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest description only says "Obsidian note management skill," which describes a broad capability but gives no specific trigger phrases, activation scope, or exclusion conditions. In a manifest file, this lack of specificity can lead to overly broad matching and unintended invocation for many general note-related requests.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.