Back to skill

Security audit

starmemo

Security checks for vulnerabilities and agentic risk

Overview

This is a functional memory assistant, but it needs Review because it can automatically retain conversations and send prompts or memories to external services with incomplete disclosure and unsafe setup patterns.

Install only if you are comfortable with a memory skill that may save ordinary conversation text locally and, after LLM configuration, send current prompts or recalled memories to configured AI providers. Avoid entering secrets, use an isolated environment, leave AI/web/key persistence disabled unless needed, and rotate any API key that may have been passed via command-line history.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
starmemo.py:319
Finding
Automatic Collection and External Transmission of Conversation Data<![CDATA[ ## Vulnerability Details **File Location**: `starmemo.py:14-24`, `starmemo.py:145-210`, `starmemo.py:319-325`, `starmemo.py:426-429`; `v2/core.py:87-109`; `v2/ai_processor.py:69-89` **Vulnerability Type**: Excessive collection and disclosure of potentially sensitive conversation data **Risk Level**: High ### Vulnerable Code ```python def on_user_input(ctx, user_input): config = ctx.get("config", {}) if config.get("save", True): save_to_memory(ctx, user_input) return process_query(ctx, user_input) ``` ```python if msg and not msg.startswith("记忆配置") and allow_save: core = self.llm.optimize(msg) self.storage.save(msg, core) ``` ```python def _call_llm(self, prompt: str, max_tokens: int = 500) -> str: if not self.enable_ai: return "" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}" } data = { "model": self.model, "messages": [{"role": "user", "content": prompt}], "temperature": self.temperature, "max_tokens": max_tokens } try: res = requests.post( self.api_endpoint, headers=headers, json=data, timeout=15 ) res.raise_for_status() return res.json()["choices"][0]["message"]["content"].strip() except Exception as e: print(f"⚠️ LLM call failed: {e}") return "" ``` ```python structured = self.ai.extract_structured(text) self.storage.save_daily( cause=structured.get("cause", text[:100]), change=structured.get("change", text[:200]), todo=structured.get("todo", ""), topic=structured.get("topic", "") ) knowledge_list = self.ai.extract_knowledge(text) ``` ### Technical Analysis The legacy input hook defaults to saving every user input when the `save` configuration field is absent. In the legacy message handler, almost every non-configuration message is passed to `LLMClient.optimize()` before be ...[truncated 2551 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic capture and AI processing by default. 2. Require explicit user opt-in before enabling external LLM processing. 3. Save messages only following an explicit memory request or a narrowly defined, documented trigger. 4. Add per-message controls such as “do not save” and “process locally only.” 5. Detect and redact credentials, private keys, authentication headers, financial data, and common personal identifiers before storage or transmission. 6. Clearly disclose the destination provider and the categories of data sent before AI processing is enabled. 7. Separate local memory functionality from remote AI functionality so local saving does not implicitly trigger a network request. 8. Ensure disabling network access blocks both search and LLM API calls. 9. Add retention limits, memory deletion commands, and secure export controls. 10. Update `_meta.json`, `README.md`, and both skill manifests to declare network access and accurately describe the privacy model. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
starmemo.py:89
Finding
Configurable Endpoint Can Receive API Credentials and Private Memory Data<![CDATA[ ## Vulnerability Details **File Location**: `starmemo.py:89-92`, `starmemo.py:145-164`; `v2/ai_processor.py:267-270`, `v2/ai_processor.py:69-87` **Vulnerability Type**: Unvalidated outbound endpoint with bearer-credential disclosure **Risk Level**: High ### Vulnerable Code ```python with open(self.config_path, "r", encoding="utf-8") as f: data = json.load(f) self.api_key = data.get("api_key", "") self.base_url = data.get("base_url", self.base_url) self.model_name = data.get("model_name", self.model_name) ``` ```python class LLMClient: def __init__(self, config): self.config = config self.api = f"{config.base_url.rstrip('/')}/chat/completions" def optimize(self, text): if not self.config.enable_ai or not self.config.api_key: return text[:self.config.max_len] text = text[:300] headers = { "Content-Type": "application/json", "Authorization": f"Bearer {self.config.api_key}" } data = { "model": self.config.model_name, "messages": [{"role": "user", "content": f"Summarize concisely: {text}"}], "temperature": self.config.optimize_temperature, "max_tokens": self.config.optimize_tokens } try: res = requests.post( self.api, headers=headers, json=data, timeout=10 ) ``` ```python self.api_key = data.get("api_key", "") self.base_url = data.get("base_url", "") self.model = data.get("model_name", "") ``` ### Technical Analysis The application reads `base_url` directly from `.skill_config` and constructs the LLM endpoint by appending `/chat/completions`. It then sends both the configured API key in a bearer authorization header and conversation-derived content in the request body. There is no validation that: - The URL uses HTTPS. - The host belongs to a documented LLM provider. - The credential was issued fo ...[truncated 1712 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate outbound endpoints against an explicit allowlist of documented HTTPS provider hosts. 2. Reject plaintext HTTP URLs and URLs containing user-info components, unexpected ports, fragments, or ambiguous host encodings. 3. Require a separate, explicit security confirmation before allowing a custom endpoint. 4. Clear the current API key whenever the provider or endpoint changes. 5. Bind each stored credential to a specific provider identifier and host. 6. Display the normalized destination host before saving or using a credential. 7. Protect configuration integrity and refuse configurations with unsafe ownership or permissions. 8. Consider removing arbitrary `base_url` loading from the standard configuration path. 9. Add tests covering redirects, malformed URLs, non-HTTPS schemes, lookalike domains, and endpoint changes. 10. Disable automatic redirects for authenticated requests or validate every redirect destination before forwarding authorization headers. ]]>

T08 · Insecure Dependencies

Warning
Location
starmemo.py:40
Finding
Import-Time Installation of an Unpinned Dependency<![CDATA[ ## Vulnerability Details **File Location**: `starmemo.py:40-47`; `v2/ai_processor.py:12-21` **Vulnerability Type**: Unsafe runtime dependency installation **Risk Level**: Medium ### Vulnerable Code ```python def auto_install(): try: import requests except ImportError: import subprocess subprocess.check_call( [sys.executable, "-m", "pip", "install", "-q", "requests"] ) auto_install() import requests ``` ### Technical Analysis Importing either affected module can invoke pip if `requests` is unavailable. The installation does not specify an exact version or integrity hash and relies on the Python environment's configured package index, proxy, certificates, and dependency resolver. This creates an import-time side effect with substantially greater privileges than ordinary module loading. The package installation can modify the active Python environment and execute package build or installation logic. The declared requirement uses a minimum version constraint, but the runtime command installs an unrestricted latest compatible release. The code does not establish that the retrieved package is malicious, and no dependency-confusion package name was identified. The vulnerability is the unsafe installation mechanism and lack of reproducibility. ### Attack Path 1. The skill runs in an environment where `requests` is not already installed. 2. An attacker controls or influences pip configuration, a package-index mirror, DNS, a trusted proxy, or the package supply chain. 3. Importing `starmemo` or `v2.ai_processor` automatically invokes pip. 4. Pip downloads the package and transitive dependencies from the configured source. 5. Malicious build or installation logic executes with the privileges of the skill process. 6. The installed package can modify the environment, access the user's files, or execute further payloads. A less severe path occurs when an untested future dependency release is installed and ...[truncated 673 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all import-time and runtime calls to pip. 2. Declare dependencies through a standard package manifest or locked requirements file. 3. Pin exact reviewed versions of direct and transitive dependencies. 4. Use integrity hashes, such as pip's `--require-hashes` workflow. 5. Install dependencies before running the skill in an isolated virtual environment. 6. Fail safely with a clear installation message if a dependency is missing. 7. Use an approved package index and validate repository configuration in deployment. 8. Add automated dependency vulnerability scanning and a controlled update process. 9. Avoid installing packages into a global or shared interpreter environment. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
cli.py:62
Finding
API Key Exposure Through Command-Line Arguments and Configuration Output<![CDATA[ ## Vulnerability Details **File Location**: `cli.py:62-68`, `cli.py:149`; `v2/cli.py:129`, `v2/cli.py:235`; `README.md:57-62`, `README.md:191-196`; `v2/SKILL.md:91-97` **Vulnerability Type**: Insecure credential input and partial credential disclosure **Risk Level**: Medium ### Vulnerable Code ```python print(f"API Key: {config.api_key[:15]}..." if config.api_key else "Not set") ``` ```python config_parser.add_argument("--key", help="Set API Key") ``` ```python config_p.add_argument("--key", help="Set API Key") ``` The documented usage pattern is equivalent to: ```bash python3 v2/cli.py config --llm huoshan --key YOUR_API_KEY ``` ### Technical Analysis The documented and implemented configuration flow accepts API keys directly as command-line arguments. Command-line secrets may be visible through: - Shell history. - Process listings and process-inspection interfaces. - Terminal recording or command auditing. - Wrapper scripts and automation logs. - Error reports that record the complete command. The legacy `config --show` path also prints the first 15 characters of the configured API key. This is excessive disclosure and may reveal most or all meaningful material for short credentials or recognizable provider prefixes. Restricting `.skill_config` to mode `0600` does not mitigate exposure through process metadata, shell history, or terminal output. ### Attack Path 1. The user follows the documented configuration command and supplies a real API key with `--key`. 2. The shell stores the complete command in history, or another local process observes the argument list while the command is running. 3. Alternatively, the user runs the legacy configuration display command. 4. The command reveals the first 15 characters of the persisted key in terminal output. 5. A local attacker, log collector, terminal recorder, support recipient, or backup reader obtains the exposed credential material. 6. If the complete key is recovered, it can be used against ...[truncated 573 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `--key` command-line option from normal credential enrollment. 2. Read credentials using a non-echoing protected prompt, such as `getpass.getpass()`. 3. Alternatively, accept credentials through a dedicated file descriptor, protected environment variable, or operating-system credential store. 4. Never print any part of an API key in configuration output. 5. Display only whether a key is configured and, if necessary, a non-secret provider identifier. 6. Warn users not to place credentials in shell commands, scripts, issue reports, or chat messages. 7. Update all documentation and examples to use the protected enrollment mechanism. 8. Support credential rotation and provide instructions for revoking keys that may already have entered shell history. 9. Prefer provider keys with the minimum available permissions, quota, and expiration period. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (48)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared purpose presents the skill as a memory system, but the detected behavior includes broad automatic data capture, third-party LLM transmission, web fetching, persistent config/API key storage, and package installation. This mismatch is highly dangerous because users and reviewers may consent to a simple memory feature while the skill actually exfiltrates data, expands its runtime surface, and stores sensitive material.

Missing User Warnings

High
Confidence
99% confidence
Finding
All user input is automatically persisted by default without a user-facing warning or consent flow. In a memory skill, this is especially dangerous because users may disclose secrets, credentials, personal data, or regulated information that will then be stored locally across sessions.

Ssd 3

High
Confidence
99% confidence
Finding
The code explicitly states and implements global capture of all user inputs across platforms, with saving enabled by default and no scenario-based exceptions. In context, that makes the skill more dangerous because it is integrated into chat/agent workflows where sensitive data is commonly entered unexpectedly.

Intent-Code Divergence

High
Confidence
93% confidence
Finding
The comments claim the original retrieval/response flow remains unchanged, but the referenced helper name does not exist for query processing and instead collides with a save function name elsewhere. In security-sensitive review, misleading comments plus incompatible control flow are dangerous because they can hide unintended behavior, break expected safeguards, or cause operators to misunderstand what data is stored or processed.

Ssd 3

High
Confidence
97% confidence
Finding
The reusable save function persists arbitrary provided content to disk without contextual checks, policy enforcement, or sensitivity filtering. Because it is presented as cross-platform and unrestricted, other components can call it to store sensitive material broadly and silently.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
Automatic dependency installation is not necessary for the core stated purpose and gives the skill the ability to modify the host environment. In a plugin setting, that is dangerous because loading the skill can trigger network access and package execution without a review gate.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill sends user input and memory context to third-party LLM APIs without an in-band warning at the time of use. Because recalled memory can contain prior sensitive conversations, this creates a meaningful data exfiltration risk beyond the current prompt alone.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README advertises web-enabled learning and external LLM integration via API keys, but does not clearly disclose that user memories, prompts, or knowledge-base content may be transmitted to third-party services. In a memory skill, that omission is especially risky because the stored data is likely to contain sensitive personal or organizational information, creating privacy, compliance, and unintended data-sharing exposure.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill advertises capabilities that imply file access, persistence, shell execution, and network use, but it does not declare any explicit tool scope or permissions boundary. In a memory-oriented skill, this is dangerous because it obscures the real attack surface and can enable over-privileged operation, especially when combined with persistence and external calls.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill explicitly enables online learning and persistence but does not warn users that their data may be stored long-term or transmitted to external services. In this context, the omission is dangerous because a memory system naturally handles user-provided content that may include sensitive personal or business information.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The save triggers are broad enough to capture ordinary conversation, task details, and newly learned information without a narrowly defined consent boundary. In a persistent memory skill, that creates a substantial risk of storing sensitive personal, enterprise, or cross-context data that the user did not intend to retain.

Vague Triggers

Medium
Confidence
97% confidence
Finding
Using common conversational words like '之前', '上次', or '那个' as recall triggers is too vague and can cause memory retrieval in contexts where the user is not actually asking for persisted data. This increases the chance of unintended disclosure of previously stored sensitive information into the current conversation.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The skill registers the broad on_user_input hook, meaning it can activate on every user message without any declared trigger constraints or exclusions. For a skill with read_file and write_file permissions and a memory-oriented purpose, this increases the attack surface for unintended data collection, silent persistence of sensitive content, and unexpected file modifications.

Missing User Warnings

Medium
Confidence
81% confidence
Finding
The save command reads arbitrary content, including from stdin, and writes it to storage via skill.storage.save. While it prints a success message afterward, there is no prior warning in the command help, docstring, or inline user disclosure that provided content will be persisted as memory, which may surprise users handling sensitive text.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
Displaying part of a stored API key without warning increases the chance of accidental credential exposure through screenshots, shell history capture, terminal logging, or shared sessions. In a CLI context, users often assume 'show config' is safe to run, so exposing secret material is riskier than necessary.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
Automatic package installation occurs without user/admin warning, which means simply importing the skill may trigger environment changes and outbound network activity. This violates least surprise and can undermine controlled deployment practices.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
import requests
    except ImportError:
        import subprocess
        subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "requests"])
auto_install()
import requests
Confidence
96% confidence
Finding
The skill automatically invokes pip at import time to install a dependency, which executes a package-management side effect without user approval. In an agent/plugin context this expands the trusted computing base, can alter the runtime environment, and may introduce supply-chain risk if package sources or mirrors are compromised.

External Transmission

Medium
Category
Data Exfiltration
Content
"max_tokens": self.config.optimize_tokens
        }
        try:
            res = requests.post(self.api, headers=headers, json=data, timeout=10)
            res.raise_for_status()
            return res.json()["choices"][0]["message"]["content"].strip()[:self.config.max_len]
        except:
Confidence
97% confidence
Finding
This request transmits user-provided text to an external LLM provider for optimization, potentially including sensitive information from raw inputs. Because it is tied to memory processing, the function may exfiltrate data users believed would remain local.

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
This memory skill performs broader network-backed chat and optional retrieval functions rather than staying limited to local memory management. That capability expansion increases the attack surface and privacy risk because user inputs and recalled memory may be transmitted externally in ways users do not expect from a 'memory' component.

External Transmission

Medium
Category
Data Exfiltration
Content
"max_tokens": self.config.chat_tokens
        }
        try:
            res = requests.post(self.api, headers=headers, json=data, timeout=10)
            res.raise_for_status()
            return res.json()["choices"][0]["message"]["content"].strip()
        except:
Confidence
98% confidence
Finding
This call sends current user input and memory context to an external LLM chat endpoint. The combination of live prompt data plus stored memory materially raises confidentiality risk if the memory contains prior sensitive content.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
Fallback and system prompt strings in clarify are hard-coded in Chinese, and the file branding/instructions are also Chinese-centric. This can violate language/locale policy because users are not offered a language choice or an opt-in to Chinese-only responses.

External Transmission

Medium
Category
Data Exfiltration
Content
]
        data = {"model": self.config.model_name, "messages": messages, "temperature": self.config.chat_temperature, "max_tokens": self.config.clarify_tokens}
        try:
            res = requests.post(self.api, headers=headers, json=data, timeout=10)
            res.raise_for_status()
            return res.json()["choices"][0]["message"]["content"].strip()
        except:
Confidence
96% confidence
Finding
This clarify flow also sends user input and memory context to an external endpoint, even though the task could be handled locally or with a minimal template. It creates unnecessary external exposure for a non-essential feature.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Optional web fetching is outside the minimum capability needed for structured memory and causes user-derived queries to be sent to external services. Even if gated by config, it broadens the skill from storage into retrieval/augmentation and increases privacy and exfiltration risk.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
When enabled, the skill sends search queries derived from user messages to external web services without a user-facing warning at request time. Queries may contain names, internal project details, or other sensitive content that users did not intend to disclose externally.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill explicitly advertises persistent memory storage and web-connected learning, and later shows both features enabled, but provides no explicit consent flow, retention notice, or boundaries on what data may be transmitted externally. In a memory-oriented skill, this materially increases the chance that user-provided sensitive information is stored long-term and potentially sent to third-party LLM or web services without clear user awareness.

Static analysis

No suspicious patterns detected.