Back to skill

Security audit

Enhanced Memory

Security checks for vulnerabilities and agentic risk

Overview

This memory-search skill is mostly purpose-aligned, but it can copy sensitive memory/workspace notes into an index and send source text or queries to an embedding endpoint that is not constrained to local Ollama.

Install only if you are comfortable with this skill reading memory files and selected workspace-level notes. Keep OLLAMA_URL pointed at a trusted local Ollama instance, treat memory/vectors.json as sensitive because it contains copied plaintext chunks, and avoid running it in shared environments without tightening file permissions and endpoint controls.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/embed_memories.py:16
Finding

Environment-controlled embedding endpoint can receive sensitive agent memory

Content
View full analysis
1 else MEMORY_DIR memory_dir = os.path.abspath(memory_dir) workspace_root = os.path.abspath(os.path.join(memory_dir, '..')) files = get_md_files(memory_dir) all_chunks = [] for f in files: a ...[truncated 4635 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
scripts/embed_memories.py:100
Finding

Indexed memory content is duplicated in a plaintext file without enforced restrictive permissions

Content
View full analysis
20: chunks.append({ 'file': os.path.relpath(filepath, workspace_root), 'header': header, 'line': start, 'text': text, }) header = line.lstrip('#').strip() lines = [line] start = i else: lines.append(line) if lines: text = '\n'.join(lines).strip() if text and len(text) > 20: chunks.append({ 'file': os.path.relpath(filepath, workspace_root), 'header': header, 'line': start, 'text': text, }) return chunks ``` ```python for i in range(0, len(all_chunks), 20): batch = all_chunks[i:i + 20] texts = [c['text'][:2000] for c in batch] vectors = embed_batch(texts) for chunk, vec in zip(batch, vectors): chunk['embedding'] = vec) done = min(i + 20, len(all_chunks)) print(f' {done}/{len(all_chunks)} chunks embedded') vectors_path = os.path.join(memory_dir, 'vectors.json') with open(vectors_path, 'w') as f: json.dump(all_chunks, f, indent=None) print(f'Saved {len(all_chunks)} vectors to {vectors_path}') ``` ### ...[truncated 2332 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (13)

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

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The script sends chunked contents of local markdown files to a network endpoint taken directly from the OLLAMA_URL environment variable, with no validation that it is local or trusted. Because the indexed content includes memory files and selected workspace files, a user or wrapper can redirect embeddings to an arbitrary remote server and exfiltrate potentially sensitive project data.

Content

Scanner excerpt · scripts/embed_memories.py (reported line 86)May include surrounding context.

python
"""Get embeddings for a batch of texts from Ollama."""
    data = json.dumps({'model': MODEL, 'input': texts}).encode()
    req = urllib.request.Request(OLLAMA_URL, data=data, headers={'Content-Type': 'application/json'})
    with urllib.request.urlopen(req, timeout=60) as resp:
        return json.loads(resp.read())['embeddings']

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

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The request target is derived from the OLLAMA_URL environment variable and user query text is sent to that endpoint without validation or restriction. This enables SSRF-style behavior or silent exfiltration of sensitive prompts/queries if an attacker can influence the environment, and the risk is amplified because this skill processes memory-search content that may contain sensitive internal data.

Content

Scanner excerpt · scripts/search_memory.py (reported line 135)May include surrounding context.

python
"""Get embedding vector from Ollama."""
    data = json.dumps({'model': MODEL, 'input': [text]}).encode()
    req = urllib.request.Request(OLLAMA_URL, data=data, headers={'Content-Type': 'application/json'})
    with urllib.request.urlopen(req, timeout=30) as resp:
        return json.loads(resp.read())['embeddings'][0]

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description describes a broad, enhanced memory retrieval/search subsystem with multiple scoring signals and search-time behaviors. The supplied code chunk is much narrower: it builds semantic cross-references using existing embeddings and cosine similarity, plus simple reporting commands. The only notable overlap is the 'knowledge graph cross-references' aspect and the declared use case of building cross-references. However, the primary declared purpose—an advanced 4-signal memory search replacement—is not represented in this code. Therefore the description materially overstates and mischaracterizes what this specific code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a full 4-signal memory search/retrieval and cross-reference system. The supplied code chunk only performs offline embedding/index construction: collecting markdown files, chunking by headers, calling Ollama's embed API, and saving vectors. While indexing memory files is one small part of the declaration, the primary claimed behavior is a sophisticated search/scoring system that is absent here. Additionally, the script indexes not only the memory directory but also workspace-level files such as MEMORY.md, AGENTS.md, USER.md, SOUL.md, and research.md, which is broader than a plain memory-file embedding description. Therefore the description materially overstates and misrepresents what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description presents a broad enhanced memory search/indexing system with multiple advanced retrieval features and an Ollama embedding dependency. The supplied code chunk only scores memory item salience based on file metadata, modification age, access frequency, and simple query-word overlap from logs, then generates reminder prompts. While 'salience scoring' is mentioned in the description, the code does not implement the stated primary search/retrieval capabilities, indexing pipeline, or knowledge graph behavior. This is a material description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code substantially matches the core search-related portion of the description: it performs 4-signal fusion retrieval (vector, keyword, header, filepath), temporal routing via date extraction and file-path date boosts, adaptive weighting, and pseudo-relevance feedback, and it uses Ollama with the nomic-embed-text model by default. However, the declared purpose materially overstates the implemented scope by claiming use for indexing memory files, building cross-references, and scoring memory salience. This code only searches an existing vectors.json index and does not create/update indexes, compute salience, or build/use a knowledge graph. Because those are presented as core capabilities/use cases rather than minor extras, this is a description-behavior mismatch.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/memory_salience.py (reported line 136)May include surrounding context.

python
prompts.append(f"📝 Daily notes from {item['name']} haven't been reviewed for MEMORY.md.")
        elif item['type'] == 'core' and item['age_days'] > 2:
            prompts.append(f"🧠 MEMORY.md last updated {item['age_days']} days ago.")
    return prompts


def main():

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises and instructs use of scripts that read and write workspace files and make local network requests to Ollama, but the manifest declares no explicit tool scope or permissions. Missing scope boundaries can cause an agent platform to over-grant capabilities or leave reviewers unable to assess whether file and network access are intended, increasing the chance of unintended data access or exfiltration through the referenced scripts.

Content

No source excerpt is available for this finding.

Tainted flow: 'CROSSREF_FILE' from os.environ.get (line 22, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/crossref_memories.py (reported line 98)May include surrounding context.

python
'file_graph': file_graph,
    }

    with open(CROSSREF_FILE, 'w') as f:
        json.dump(result, f, indent=2)

    print(f'\nCross-reference index built:')

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The environment-configurable OLLAMA_URL allows all indexed content to be sent to any HTTP endpoint, not just a local Ollama instance. Combined with the skill's purpose of sweeping memory and selected workspace files, this creates a straightforward exfiltration channel for sensitive local data under the guise of embedding generation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script does not limit indexing to the memory directory; it also pulls in workspace-level files like MEMORY.md, AGENTS.md, USER.md, SOUL.md, and research.md. In this skill context, those files may contain broader instructions, personal notes, or operational data that users would not expect to be ingested and embedded when running a memory indexing tool.

Content

No source excerpt is available for this finding.

Tainted flow: 'vectors_path' from os.environ.get (line 115, credential/environment) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/embed_memories.py (reported line 116)May include surrounding context.

python
print(f'  {done}/{len(all_chunks)} chunks embedded')

    vectors_path = os.path.join(memory_dir, 'vectors.json')
    with open(vectors_path, 'w') as f:
        json.dump(all_chunks, f, indent=None)

    print(f'Saved {len(all_chunks)} vectors to {vectors_path}')

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The code transmits the user's search query to an embedding service over HTTP without any explicit notice, consent flow, or local-only enforcement in this file. In a memory-search skill, queries often include sensitive personal, organizational, or secret-bearing context, so silent transmission creates a meaningful privacy and data-handling risk even if the service is intended to be local.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.