Back to skill

Security audit

Obsidian Ontology Sync 1.0.1

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned, but it continuously centralizes sensitive Obsidian note data into plaintext generated files with limited privacy, permission, and scheduling safeguards.

Review this before installing if your Obsidian vault contains personal, client, employee, financial, or confidential project data. Use a narrow vault path, run dry-run first, avoid enabling cron until outputs are reviewed, restrict filesystem permissions on the ontology and feedback directories, and consider disabling or removing PII extraction if the graph may be backed up, synced, or read by other local users or tools.

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/sync.py:190
Finding
Personal Contact Data Stored in a Plaintext Ontology File with Inherited Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/sync.py:119-127` and `scripts/sync.py:190-205` **Vulnerability Type**: Plaintext sensitive-data storage and insufficient file-permission hardening **Risk Level**: Medium ### Complete Code Snippet ```python # Extract email email_match = re.search(r'\*\*Email:\*\*\s+([^\s\n]+)', content) if email_match: properties['email'] = email_match.group(1) # Extract phone phone_match = re.search(r'\*\*Phone:\*\*\s+([^\s\n]+)', content) if phone_match: properties['phone'] = phone_match.group(1) ``` ```python def write_ontology(self): """Write entities and relations to ontology file""" with open(self.graph_file, 'a') as f: # Write entities for entity in self.entities.values(): f.write(json.dumps({ 'op': 'upsert', 'entity': entity }) + '\n') # Write relations for relation in self.relations: f.write(json.dumps({ 'op': 'relate', **relation }) + '\n') print(f"📝 Wrote to {self.graph_file}") ``` ### Technical Analysis The extraction process copies email addresses and telephone numbers from Obsidian notes into entity properties. `write_ontology()` then serializes those properties directly into the append-only `graph.jsonl` file as plaintext JSON. The implementation creates the ontology directory with `Path.mkdir()` and opens the graph with the standard `open(..., 'a')` call, but it does not establish restrictive permissions such as `0700` for the directory and `0600` for the file. Consequently, access permissions are determined by the process umask, existing filesystem permissions, and any permissions already applied to an existing target. This also consolidates personal information from multiple notes into one predictable file. Such consolidation can increase the effect of unintended local disclosure. No network exfiltration or credential collection ...[truncated 1532 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create the ontology directory with owner-only permissions and verify existing directory permissions: ```python self.ontology_path.mkdir(parents=True, exist_ok=True, mode=0o700) os.chmod(self.ontology_path, 0o700) ``` 2. Create and append to the graph using an explicitly restricted descriptor: ```python fd = os.open( self.graph_file, os.O_WRONLY | os.O_CREAT | os.O_APPEND | os.O_NOFOLLOW, 0o600, ) with os.fdopen(fd, 'a', encoding='utf-8') as f: ... ``` 3. Check that the graph path is a regular file owned by the expected user before writing. Reject symbolic links and unexpected file types to prevent writes through attacker-controlled filesystem objects. 4. Add configuration controls allowing users to exclude sensitive properties such as email addresses and telephone numbers from the generated ontology. 5. Where the threat model includes other privileged services, backups, or shared storage, encrypt the ontology at rest and keep encryption keys outside the ontology directory. 6. Document clearly that extraction duplicates personal data into `graph.jsonl`, including the resulting retention and access-control implications. 7. Add automated tests that verify the generated directory is `0700`, the graph file is `0600`, and writes fail safely when the target is a symbolic link. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (10)

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The README encourages automated periodic processing of personal knowledge base notes, extraction of sensitive properties like email and phone, and storage of derived graph data without any visible privacy, consent, retention, or access-control warning. In this context, the omission is security-relevant because users may schedule unattended sync over highly sensitive personal/work notes and generate secondary data stores that broaden exposure and are easier to query or exfiltrate.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill clearly describes reading from the Obsidian vault and writing ontology, feedback, logs, and potentially modifying source notes, yet it does not declare any explicit tool scope or permissions. This creates an authorization and transparency gap: operators cannot easily constrain or review what filesystem access the skill expects, increasing the risk of overbroad file access or unintended writes.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill is designed to extract sensitive personal and team-management data such as emails, phones, behavioral patterns, reporting lines, blockers, and project assignments into a queryable ontology, but it provides no privacy, retention, or access-control warning. Centralizing this information materially increases exposure, making misuse, overcollection, or unauthorized querying more damaging than leaving the data dispersed in notes.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The skill states that Obsidian is the primary source and the ontology is derived, which implies one-way flow and source integrity, but later introduces a mode that writes back into Obsidian notes. This inconsistency can mislead users about trust boundaries and data flow, causing them to enable automation without realizing machine-generated ontology inferences may alter their primary records.

Intent-Code Divergence

Medium
Confidence
84% confidence
Finding
The documentation promises append-only ontology writes during extraction, which suggests safer, auditable behavior, but elsewhere describes updating existing state and modifying source notes. Contradictory guarantees about mutability undermine operator expectations and may lead to unsafe deployment assumptions, especially for scheduled automation handling sensitive notes.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill instructs users to install cron jobs that repeatedly scan notes and generate outputs, but it does not clearly warn that this creates ongoing background collection and writing behavior. Continuous unattended processing increases the chance of privacy leakage, stale or incorrect inferences propagating, and unnoticed file modifications or reports accumulating sensitive summaries.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest promises bidirectional synchronization between Obsidian notes and the ontology, but this script only extracts data from markdown into an ontology file and never updates source notes from ontology state. The feedback feature writes separate suggestion files, which is not actual reverse synchronization.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script automatically extracts personal contact data such as email addresses and phone numbers from markdown notes and persists them into an ontology store without any consent prompt, minimization, retention control, or sensitivity warning. In this skill context, the vault appears to contain real PKM/contact information under /root/life/pkm, so centralizing PII into a machine-queryable graph increases exposure if the graph is read by other tools, backed up, or leaked.

Description-Behavior Mismatch

Low
Confidence
82% confidence
Finding
The description suggests a general markdown-to-ontology extractor, but the code only recognizes a small set of patterns such as '**Email:**', '**Phone:**', '**Company:**', wiki links, and a hard-coded allowlist of project names. This is a materially narrower behavior than the broad capability implied by the manifest.

Missing User Warnings

Low
Confidence
90% confidence
Finding
The feedback action creates directories and writes a dated feedback file into the vault, but the method provides no advance disclosure beyond printing after the write completes. For code files, file writes that affect user data should have some visible warning, confirmation, or documented notice before execution.

Static analysis

No suspicious patterns detected.