Back to skill

Security audit

Obsidian Librarian

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for saving and querying Obsidian notes, but it gives itself broad vault indexing and external AI-processing authority with a few under-scoped network and privacy behaviors users should review first.

Review this before installing if your Obsidian vault contains private, regulated, client, or proprietary material. Use a dedicated vault or carefully scoped OBSIDIAN_VAULT_PATH, avoid saving sensitive conversations with broad "save this" prompts, and do not enable Supabase unless you are comfortable storing searchable note chunks there. Be cautious ingesting shortened URLs because the skill may resolve them from the local runtime before using Apify.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (11)

Tainted flow: 'request' from os.environ.get (line 350, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
for _ in range(max_hops):
        try:
            request = urllib.request.Request(current, method="HEAD", headers={"User-Agent": "Mozilla/5.0"})
            with urllib.request.urlopen(request, timeout=timeout) as response:
                final = response.geturl()
        except Exception:
            try:
Confidence
89% confidence
Finding
The redirect resolver issues HEAD/GET requests to arbitrary shortener URLs and follows them to a final destination without any allowlist or private-address filtering. In a skill that ingests user-provided URLs, this creates an SSRF-style primitive that can be used to make the host contact internal services or attacker-chosen endpoints.

Tainted flow: 'request' from os.environ.get (line 355, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
except Exception:
            try:
                request = urllib.request.Request(current, headers={"User-Agent": "Mozilla/5.0"})
                with urllib.request.urlopen(request, timeout=timeout) as response:
                    final = response.geturl()
            except Exception:
                return current
Confidence
89% confidence
Finding
This fallback GET request has the same core issue as the HEAD request above: it will fetch attacker-controlled redirect targets with no network egress restrictions. Because this skill explicitly captures arbitrary URLs and X links, the reachable attack surface is broader and makes SSRF more realistic.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
Falling back to curl when Python reports CERTIFICATE_VERIFY_FAILED weakens the trust boundary around TLS errors and changes transport behavior in a way that may mask certificate validation problems. In practice this can enable insecure request handling or inconsistent verification semantics against attacker-controlled endpoints.

Vague Triggers

Medium
Confidence
84% confidence
Finding
The trigger set includes broad natural phrases such as 'save this' and 'save it', which are common conversational language and can cause unintended activation. In a skill that writes user content to persistent storage and may fetch remote URLs, accidental triggering can lead to unwanted data retention, network access, or processing of sensitive content.

Vague Triggers

Medium
Confidence
89% confidence
Finding
The instruction to prefer saving to the Obsidian vault when intent is ambiguous creates an unsafe default for a state-changing action. In context, this skill persists content into a knowledge base and may process prior message content, so ambiguity can cause private or unintended text to be stored without clear user consent.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code sends `content.markdown_body` plus up to 500 vault concepts and category data to an external Gemini API, which can expose sensitive knowledge-base contents and internal metadata to a third party. In the context of an Obsidian second-brain skill, users may store personal, confidential, or proprietary notes, so undisclosed transmission materially increases privacy and data leakage risk.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The function sends arbitrary text content to Google's Gemini embedding API over the network, which can expose sensitive vault contents, notes, URLs, or user-captured research to a third party if users are not clearly informed and have not consented. In this skill's context, the data being embedded may come from a personal knowledge base or RAG corpus, so undisclosed external transmission meaningfully increases privacy and compliance risk.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The function sends the user's question plus retrieved Obsidian vault content to `gemini_generate_text`, which transmits potentially sensitive personal notes to an external LLM provider. In a second-brain / personal knowledge-base skill, vault data is especially likely to contain private information, so lack of an explicit user-facing warning or consent gate creates a real privacy and data-exposure risk.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
This code sends the user's raw query to an external embedding service via `embed_single(...)` using a Gemini API key, which can expose sensitive vault-search terms or private note content implied by the query to a third party. In a knowledge-base/second-brain skill, users are likely to search highly personal or confidential material, so undisclosed network transmission increases privacy and data-handling risk.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code sends `raw.raw_content` directly to an external Gemini API as part of the prompt, which can expose sensitive user-captured material to a third-party service without any visible consent, redaction, or policy enforcement in this component. In this skill's context, users may save arbitrary URLs, posts, articles, and notes into a 'second brain,' making accidental transmission of private or confidential content more likely.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
This code sends raw vault chunk content to an external embedding service via `embed_texts(...)`, which can expose sensitive notes, credentials, personal data, or proprietary information to a third party. In the context of an Obsidian knowledge-base skill, users may reasonably store highly sensitive material in their vault, so exporting contents without clear consent flow, scoping, or filtering is a real privacy and data-governance risk even if it is part of intended functionality.

Static analysis

No suspicious patterns detected.