Back to skill

Security audit

memory-pro

Security checks for vulnerabilities and agentic risk

Overview

This local memory-search skill needs Review because it can index more workspace Markdown than documented and can send private memory snippets to external reranking endpoints when that option is enabled.

Install only if you are comfortable with this skill indexing private memory plus additional workspace Markdown directories, or first set MEMORY_PRO_EXTRA_MD_DIRS to an empty value. Keep MEMORY_PRO_ENABLE_RERANK disabled unless you explicitly consent to sending search queries and retrieved memory snippets to the configured provider, and avoid arbitrary rerank endpoints. Treat BM25 pickle artifacts and /tmp benchmark outputs as sensitive local files.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

other

Error
Location
v2/rerank.py:54
Finding
External Disclosure of Private Memory During Reranking<![CDATA[ ## Vulnerability Details **File Location**: `v2/rerank.py:54-68`, `v2/rerank.py:76-92`, and `v2/retrieval_hybrid.py:316-323` **Vulnerability Type**: Sensitive data disclosure to an external service **Risk Level**: High ### Complete Code Snippet ```python if provider == "jina": endpoint = os.getenv("MEMORY_PRO_RERANK_ENDPOINT", "https://api.jina.ai/v1/rerank") api_key = os.getenv("MEMORY_PRO_RERANK_API_KEY", "") model = os.getenv("MEMORY_PRO_RERANK_MODEL", "jina-reranker-v2-base-multilingual") headers = {"Content-Type": "application/json"} if api_key: headers["Authorization"] = f"Bearer {api_key}" payload = { "model": model, "query": query, "documents": [c.get("sentence", "") for c in work], "top_n": topn, } r = requests.post(endpoint, json=payload, headers=headers, timeout=timeout_ms / 1000) r.raise_for_status() data = r.json() elif provider == "openai_compatible": endpoint = os.getenv("MEMORY_PRO_RERANK_ENDPOINT", "") api_key = os.getenv("MEMORY_PRO_RERANK_API_KEY", "") model = os.getenv("MEMORY_PRO_RERANK_MODEL", "") if not endpoint or not model: raise RuntimeError("openai_compatible rerank requires ENDPOINT and MODEL") headers = {"Content-Type": "application/json"} if api_key: headers["Authorization"] = f"Bearer {api_key}" payload = { "model": model, "query": query, "documents": [c.get("sentence", "") for c in work], "top_n": topn, } r = requests.post(endpoint, json=payload, headers=headers, timeout=timeout_ms / 1000) ``` The external call is reached through hybrid retrieval: ```python # Optional rerank (Phase 3): timeout-safe + fallback rerank_meta = {"applied": False} try: from rerank import should_rerank, rerank_candidates if should_rerank(query): fused, rerank_meta = rerank_candidates(query, fused) except Exception: # fail-open: keep original fused ranking ...[truncated 2672 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Keep all reranking local by default and prefer an on-device reranking model. 2. Present an explicit warning and require informed user consent before enabling external reranking. 3. Document exactly which fields and how many candidate documents are transmitted. 4. Restrict endpoints to an administrator-controlled HTTPS allowlist. 5. Reject plain HTTP endpoints and URLs containing embedded credentials. 6. Reduce outbound candidates to the final requested `top_k`. 7. Add configurable source exclusions so core files and sensitive scopes cannot be transmitted. 8. Apply secret and personal-data redaction before constructing the request. 9. Consider sending minimized excerpts rather than complete sentences. 10. Log the destination and number of transmitted records without logging their contents. 11. Provide a strict local-only mode that prevents all outbound requests regardless of environment configuration. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
v2/preprocess.py:142
Finding
Default Corpus Collection Exceeds the Documented Search Scope<![CDATA[ ## Vulnerability Details **File Location**: `v2/preprocess.py:142-170`; inconsistent declaration at `SKILL.md:223-226` **Vulnerability Type**: Overbroad access to workspace files **Risk Level**: Medium ### Complete Code Snippet ```python def preprocess_entries(): """ Return entries with metadata for build_index / hybrid retrieval. """ base_path = os.path.dirname(os.path.abspath(__file__)) data_dir = os.getenv("MEMORY_PRO_DATA_DIR", "${OPENCLAW_WORKSPACE}/memory/") full_dir_path = _resolve_path(base_path, data_dir) if not os.path.exists(full_dir_path): raise FileNotFoundError(f"Directory not found: {full_dir_path}") entries = [] # Primary source: daily memory _ingest_markdown_dir(entries, full_dir_path, source_type="daily", scope="global") # Additional sources: self-improvement learnings / docs extra_md_dirs_raw = os.getenv( "MEMORY_PRO_EXTRA_MD_DIRS", "${OPENCLAW_WORKSPACE}/.learnings,${OPENCLAW_WORKSPACE}/skills/self-improving-agent/.learnings,${OPENCLAW_WORKSPACE}/docs" ) extra_md_dirs = [p.strip() for p in extra_md_dirs_raw.split(',') if p.strip()] for extra_dir in extra_md_dirs: _ingest_markdown_dir(entries, _resolve_path(base_path, extra_dir), source_type="extra", scope="global") workspace_root = _resolve_path(base_path, os.getenv("OPENCLAW_WORKSPACE", "../../../../workspace/")) core_files = os.getenv("MEMORY_PRO_CORE_FILES", "MEMORY.md,SOUL.md,STATUS.md,AGENTS.md,USER.md").split(',') for filename in core_files: filepath = os.path.join(workspace_root, filename) entries.extend(_collect_from_file(filepath, source_type="core", scope="global")) ``` The declared architecture only lists the following sources: ```markdown - **Data Source**: - Daily logs: `${OPENCLAW_WORKSPACE}/memory/*.md` - Core files: `MEMORY.md`, `SOUL.md`, `STATUS.md`, `AGENTS.md`, `USER.md` (from workspace root). ``` ### Technical Analysis The decla ...[truncated 1888 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Change the default value of `MEMORY_PRO_EXTRA_MD_DIRS` to an empty string. 2. Require users to opt in to each extra directory explicitly. 3. Update `SKILL.md` to disclose every default and optional corpus source. 4. Display the resolved source paths before indexing and require confirmation during interactive setup. 5. Implement a canonical-path allowlist rooted under approved directories. 6. Reject paths that resolve outside configured roots. 7. Add source-level controls preventing sensitive files from being externally reranked. 8. Provide exclusion patterns for confidential documents. 9. Record source provenance in audit logs without logging document content. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
v2/retrieval_hybrid.py:212
Finding
Unsafe Deserialization of a Configurable Pickle File<![CDATA[ ## Vulnerability Details **File Location**: `v2/retrieval_hybrid.py:212-219` **Vulnerability Type**: Arbitrary code execution through unsafe deserialization **Risk Level**: Medium ### Complete Code Snippet ```python # load bm25 payload (optional) bm25_path = os.getenv("MEMORY_PRO_BM25_PATH", "bm25_corpus.pkl") bm25_raw = {} if os.path.exists(bm25_path): try: with open(bm25_path, "rb") as f: bm25_payload = pickle.load(f) bm25_raw = _bm25_search(query, bm25_payload, top_k=candidate_pool) except Exception: bm25_raw = {} ``` ### Technical Analysis Python pickle is an executable serialization format. Loading an untrusted pickle can invoke attacker-selected callables through object reduction methods, resulting in arbitrary Python or operating-system command execution. The file path is controlled through `MEMORY_PRO_BM25_PATH`. The code does not verify: - File ownership - File permissions - Canonical path - Symlink status - File integrity or signature - Expected serialization format Catching exceptions does not mitigate this issue because malicious code executes during `pickle.load()` before control returns to the exception handler. The project normally creates the pickle itself in `build_index.py`, but the configurable path and lack of integrity checks mean the retrieval process assumes that the file remains trusted. ### Attack Path 1. An attacker gains the ability to replace the BM25 artifact or influence `MEMORY_PRO_BM25_PATH`. 2. The attacker creates a malicious pickle containing a reduction routine that executes a command. 3. The path is made to reference the malicious file. 4. A user submits a request in hybrid mode. 5. `hybrid_search()` opens the file and calls `pickle.load()`. 6. The embedded routine executes with the permissions and environment of the Memory Pro service account. ### Impact Assessment Successful exploitation permits arbitrary code execution as the user running the service. The at ...[truncated 388 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace pickle with a non-executable format such as JSON, MessagePack with strict schemas, or SQLite. 2. Validate the loaded structure and enforce exact types, field names, and size limits. 3. Store generated artifacts in a private directory owned by the service user with mode `0700`. 4. Create corpus files with mode `0600`. 5. Resolve the configured path canonically and require it to remain under an approved data directory. 6. Reject symbolic links and files not owned by the expected user. 7. If legacy pickle support is temporarily required, verify a cryptographic signature or trusted hash before loading. 8. Regenerate the BM25 artifact from trusted source documents rather than accepting externally supplied serialized objects. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
v2/benchmark.py:39
Finding
Private Search Results Written to Predictable Shared Temporary Files<![CDATA[ ## Vulnerability Details **File Location**: `v2/benchmark.py:39-45`, `v2/benchmark.py:65-85`, and `v2/validate_phase1.sh:19-20,61-62` **Vulnerability Type**: Insecure temporary-file handling and plaintext sensitive-data storage **Risk Level**: Medium ### Complete Code Snippet ```python def main(): ap = argparse.ArgumentParser(description="Memory Pro Phase-2 benchmark (vector vs hybrid)") ap.add_argument("--api", default="http://127.0.0.1:8001/search") ap.add_argument("--queries", default=os.path.join(os.path.dirname(os.path.abspath(__file__)), "eval_queries.json")) ap.add_argument("--top-k", type=int, default=5) ap.add_argument("--out", default="/tmp/memory_pro_benchmark.json") args = ap.parse_args() # ... details.append({ "query": q, "vector_latency_ms": round(v_ms, 2), "hybrid_latency_ms": round(h_ms, 2), "vector_top1": (v_res[0]["sentence"][:140] if v_res else ""), "hybrid_top1": (h_res[0]["sentence"][:140] if h_res else ""), "overlap_at_k": round(overlap[-1], 3), }) # ... out = {"summary": summary, "details": details} with open(args.out, "w", encoding="utf-8") as f: json.dump(out, f, ensure_ascii=False, indent=2) ``` Validation also creates predictable files containing logs and complete search responses: ```bash python3 build_index.py >/tmp/memory_pro_build.log 2>&1 || { tail -n 60 /tmp/memory_pro_build.log || true fail "build_index.py failed" } python3 "$CLIENT" "handover load" --url "$API_URL/search" --mode vector --json >/tmp/memory_pro_vector.json || fail "Vector query failed" python3 "$CLIENT" "handover load" --url "$API_URL/search" --mode hybrid --json >/tmp/memory_pro_hybrid.json || fail "Hybrid query failed" ``` ### Technical Analysis The benchmark stores retrieved memory excerpts in `/tmp/memory_pro_benchmark.json`. The validation script stores complete vector and hybrid search responses in predictable `/tmp` paths. These ...[truncated 1678 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use Python's `tempfile.NamedTemporaryFile` or `TemporaryDirectory`. 2. In shell scripts, create a private directory with `mktemp -d` and set `umask 077`. 3. Create temporary files with mode `0600`. 4. Avoid fixed filenames in shared directories. 5. Use exclusive creation and reject symbolic links. 6. Remove temporary outputs automatically with a shell `trap` or Python cleanup handler. 7. Avoid writing raw search responses unless explicitly requested. 8. Redact or omit memory sentence content from benchmark details. 9. Store persistent benchmark output in a user-owned application data directory rather than `/tmp`. ]]>

T08 · Insecure Dependencies

Note
Location
v2/main.py:54
Finding
Sentence-Transformer Model Loaded Without a Pinned Revision<![CDATA[ ## Vulnerability Details **File Location**: `v2/main.py:54-56` and `v2/build_index.py:58` **Vulnerability Type**: Unpinned remote model dependency **Risk Level**: Low ### Complete Code Snippet Service startup: ```python # Load model logger.info("Loading SentenceTransformer model...") model = SentenceTransformer("all-MiniLM-L6-v2") ``` Index construction: ```python print("Starting index construction...") model = SentenceTransformer('all-MiniLM-L6-v2') entries = preprocess_entries() ``` ### Technical Analysis The model is identified only by the mutable name `all-MiniLM-L6-v2`. No repository revision, commit identifier, artifact hash, or verified local path is provided. When the model is not already cached, Sentence Transformers may obtain its files from a remote model repository. The exact artifact loaded by a new installation can therefore vary over time. This weakens reproducibility and increases supply-chain exposure. The reviewed code does not explicitly download and execute a remote script, and there is no evidence that the referenced model is malicious. The finding concerns missing integrity pinning rather than a confirmed malicious dependency. ### Attack Path 1. The service starts on a host where the model is not cached. 2. `SentenceTransformer("all-MiniLM-L6-v2")` resolves the model by name through the configured model repository. 3. The host retrieves the currently published artifact associated with that identifier. 4. If the upstream artifact, account, repository, or transport configuration has been compromised, the host loads altered model content. 5. The altered artifact may affect availability, retrieval behavior, or confidentiality depending on the formats and library behavior involved. ### Impact Assessment The primary impact is loss of build reproducibility and exposure to upstream supply-chain changes. A modified model could produce manipulated embeddings, degrade or bias search results, or cause denial of service. The rev ...[truncated 205 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the model repository to a reviewed immutable revision. 2. Verify downloaded artifact hashes before loading. 3. Pre-download the verified model into a controlled local directory. 4. Configure production deployments for offline loading from that trusted directory. 5. Record the model revision and hashes in deployment documentation. 6. Restrict model cache-directory permissions. 7. Add dependency lock files for Python packages involved in model retrieval and deserialization. 8. Monitor upstream security advisories for Sentence Transformers, Transformers, model-storage libraries, and the selected model repository. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (54)

Tainted flow: 'url' from os.getenv (line 27, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
for attempt in range(MAX_RETRIES):
        try:
            # Send POST request
            response = requests.post(url, json=payload, headers=headers, timeout=TIMEOUT)
            response.raise_for_status()
            return response.json()
Confidence
97% confidence
Finding
The request target is controllable via an environment variable and a command-line override, and the script sends the user’s semantic-search query to that endpoint over the network. That creates an exfiltration/SSRF-style risk because sensitive memory queries can be transmitted to an unintended or attacker-controlled service, especially since the skill is described as local memory search.

Tainted flow: 'endpoint' from os.getenv (line 54, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
"documents": [c.get("sentence", "") for c in work],
            "top_n": topn,
        }
        r = requests.post(endpoint, json=payload, headers=headers, timeout=timeout_ms / 1000)
        r.raise_for_status()
        data = r.json()
        # jina 常見格式: {results:[{index,relevance_score},...]}
Confidence
98% confidence
Finding
The code sends the user's query and memory-derived candidate sentences to a network endpoint taken from an environment variable, with no allowlist or validation of the destination. This creates a real exfiltration path for sensitive local memory contents and also allows SSRF-style abuse if an attacker can influence environment configuration.

Tainted flow: 'endpoint' from os.getenv (line 76, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
"documents": [c.get("sentence", "") for c in work],
            "top_n": topn,
        }
        r = requests.post(endpoint, json=payload, headers=headers, timeout=timeout_ms / 1000)
        r.raise_for_status()
        data = r.json()
        rows = data.get("results", data.get("data", []))
Confidence
98% confidence
Finding
The openai-compatible path posts sensitive query text and candidate memory sentences to an externally configured endpoint from environment variables without destination validation. That is a direct data exfiltration channel and may also permit SSRF or internal network access if the endpoint is attacker-controlled.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documentation and environment variables indicate optional third-party reranking, which can transmit user queries and candidate memory snippets to external providers. For a memory-search skill handling potentially private notes, this is a significant confidentiality risk, especially because the top-level description emphasizes a local vector database and may lead users to expect no external data sharing.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documentation and environment variables indicate optional third-party reranking, which can transmit user queries and candidate memory snippets to external providers. For a memory-search skill handling potentially private notes, this is a significant confidentiality risk, especially because the top-level description emphasizes a local vector database and may lead users to expect no external data sharing.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documentation and environment variables indicate optional third-party reranking, which can transmit user queries and candidate memory snippets to external providers. For a memory-search skill handling potentially private notes, this is a significant confidentiality risk, especially because the top-level description emphasizes a local vector database and may lead users to expect no external data sharing.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The documentation and environment variables indicate optional third-party reranking, which can transmit user queries and candidate memory snippets to external providers. For a memory-search skill handling potentially private notes, this is a significant confidentiality risk, especially because the top-level description emphasizes a local vector database and may lead users to expect no external data sharing.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documentation and environment variables indicate optional third-party reranking, which can transmit user queries and candidate memory snippets to external providers. For a memory-search skill handling potentially private notes, this is a significant confidentiality risk, especially because the top-level description emphasizes a local vector database and may lead users to expect no external data sharing.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documentation and environment variables indicate optional third-party reranking, which can transmit user queries and candidate memory snippets to external providers. For a memory-search skill handling potentially private notes, this is a significant confidentiality risk, especially because the top-level description emphasizes a local vector database and may lead users to expect no external data sharing.

Credential Access

High
Category
Privilege Escalation
Content
- "OPENCLAW_NETWORK_DRIVE"
        - "OPENCLAW_WORKSPACE"
      config:
        - ".env"
        - "/skills/memory-pro/data/INDEX.json"
        - "/skills/memory-pro/data/state.json"
        - "/skills/memory-pro/v2/eval_queries.json"
Confidence
90% confidence
Finding
Declaring `.env` as a configuration file for a skill that also uses numerous environment variables and may perform network operations creates a meaningful credential-exposure risk. In this context, `.env` may contain API keys, local service endpoints, or workspace secrets that could be read, copied, or inadvertently indexed or transmitted if handling is not tightly constrained.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The skill metadata promises local semantic search, but this code transmits both user queries and memory content to third-party reranking services. That mismatch is security-relevant because users may reasonably trust that private memory data never leaves the device when in fact it can be exported remotely.

Missing User Warnings

High
Confidence
99% confidence
Finding
This is a stronger variant of the same issue: the deserialization sink is not only unsafe, but the file path is environment-controlled and lacks validation or trust boundaries. In an agent skill context, environment variables are often deployment-configurable, so this expands the attack surface from local artifact tampering to configuration injection leading to arbitrary code execution.

Lp3

Medium
Category
MCP Least Privilege
Confidence
86% confidence
Finding
The skill declares broad capabilities through required environment variables, local file access, index rewriting, and optional remote API configuration, but does not declare an explicit tool scope or permission boundary. That makes the effective privileges opaque to users and reviewers, increasing the chance that sensitive memory content or credentials are accessed in ways the user did not anticipate.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill instructs users to restart the service without prominently warning that this rebuilds and rewrites the local memory index from workspace content. In a memory-focused skill, rewriting derived artifacts can unexpectedly ingest new sensitive files, overwrite prior state, or create a false expectation that restart is a harmless read-only troubleshooting step.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### "Index size mismatch"
- This means `memory.index` and `sentences.txt` are out of sync.
- **Fix**: Restart the service. The startup script `start.sh` automatically runs `build_index.py` to fix this consistency issue before starting the API.

### "Address already in use"
- Port 8001 is taken by a zombie process.
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The troubleshooting advice recommends killing whatever process holds port 8001, but does not warn that the process may not belong to this skill. This can terminate unrelated local services and, if copied blindly, encourages unsafe operator behavior that may cause denial of service or data loss.

Tainted flow: 'STATE_FILE' from os.getenv (line 24, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
def save_state(state):
    """Save processing state"""
    STATE_FILE.parent.mkdir(parents=True, exist_ok=True)
    with open(STATE_FILE, 'w', encoding='utf-8') as f:
        json.dump(state, f, ensure_ascii=False, indent=2)

def load_index():
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.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest describes the skill as providing semantic search over memory files using a local vector database. In this file, the index is loaded from and saved to a JSON file, and the rest of the logic extracts regex-based keywords and contexts rather than embeddings or vector-based retrieval, which is a materially different implementation and behavior.

Tainted flow: 'INDEX_FILE' from os.getenv (line 20, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
def save_index(index):
    """Save index to file"""
    INDEX_FILE.parent.mkdir(parents=True, exist_ok=True)
    with open(INDEX_FILE, 'w', encoding='utf-8') as f:
        json.dump(index, f, ensure_ascii=False, indent=2)

def process_file(filepath, incremental=False, state=None):
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.

Tainted flow: 'INDEX_FILE' from os.getenv (line 17, credential/environment) → open (file write)

Medium
Category
Data Flow
Content
def save_index(index):
    INDEX_FILE.parent.mkdir(parents=True, exist_ok=True)
    with open(INDEX_FILE, 'w', encoding='utf-8') as f:
        json.dump(index, f, ensure_ascii=False, indent=2)

def search(query):
Confidence
92% confidence
Finding
The script derives INDEX_FILE from an environment variable and then writes to that path without validation. An attacker who can influence the environment could redirect writes to an unintended file location, causing arbitrary file overwrite within the privileges of the running process and potentially corrupting other workspace data.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest describes a semantic-search skill backed by a local vector database, which implies embedding/vector similarity behavior. In this file, the search implementation lowercases the query and checks for substring matches against JSON keys loaded from INDEX.json, with no vector database or semantic retrieval logic present.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The implementation does not directly search local memory files as the manifest suggests; instead it depends on an HTTP service. This mismatch is dangerous because users may trust the skill as purely local while their queries are actually sent to another process or service, weakening transparency and informed consent.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Allowing the API endpoint to be overridden through both environment variables and CLI arguments means any caller or surrounding environment can redirect search traffic to an arbitrary host. In the context of memory search, that can expose highly sensitive queries to external systems unrelated to the stated local-search purpose.

External Transmission

Medium
Category
Data Exfiltration
Content
for attempt in range(MAX_RETRIES):
        try:
            # Send POST request
            response = requests.post(url, json=payload, headers=headers, timeout=TIMEOUT)
            response.raise_for_status()
            return response.json()
Confidence
81% confidence
Finding
This is a genuine external transmission sink: the script sends query data in a POST request to another service. External transmission is not automatically malicious, but in this context it is security-relevant because the skill handles memory-search inputs that may be sensitive and the manifest does not make this behavior obvious.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The script has direct network transmission capability via HTTP POST, which expands the trust boundary beyond a local file-search utility. In this skill context, that is more dangerous because users would reasonably expect local processing of memory contents and queries, not outbound requests.

Static analysis

No suspicious patterns detected.