other
- Location
v2/rerank.py:54- Finding
External Disclosure of Private Memory During Reranking
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
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.
v2/rerank.py:54External Disclosure of Private Memory During Reranking
v2/preprocess.py:142Default Corpus Collection Exceeds the Documented Search Scope
v2/retrieval_hybrid.py:212Unsafe Deserialization of a Configurable Pickle File
v2/benchmark.py:39Private Search Results Written to Predictable Shared Temporary Files
v2/main.py:54Sentence-Transformer Model Loaded Without a Pinned Revision
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.
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()
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.
"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},...]}
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.
"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", []))
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.
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.
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.
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.
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.
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.
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.
- "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"
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.
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.
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.
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.
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.
### "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.
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.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
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():
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.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
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):
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.
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):
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.
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.
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.
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.
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()
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.
No suspicious patterns detected.