Back to skill

Security audit

Channel Activity

Security checks for vulnerabilities and agentic risk

Overview

This skill provides useful multi-channel memory, but it can share stored conversation summaries across channels and identities without adequate access controls or consent safeguards.

Review before installing, especially in multi-user or multi-channel deployments. Use only with trusted users unless family sharing, cross-channel recall, automatic hooks, and long-term memory access are explicitly consented to and scoped. Pin the installer version, remove hard-coded import paths, isolate cache files per user or tenant, restrict file permissions, and avoid automatic prompt injection of memory records.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (6)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
channel_activity.py:49
Finding
Unauthenticated Family-Group Membership Enables Cross-User Memory Disclosure<![CDATA[ ## Vulnerability Details **File Location**: `channel_activity.py:49-72`, `channel_activity.py:138-180` **Vulnerability Type**: Missing authorization and insecure default sharing **Risk Level**: High ### Evidence ```python def add_to_family(self, family_id: str, identity: str): if family_id not in self.data["family_groups"]: self.create_family_group(family_id) if identity not in self.data["family_groups"][family_id]["members"]: self.data["family_groups"][family_id]["members"].append(identity) self._save() print(f"[家庭组] 添加 {identity} 到 {family_id}") ``` ```python def get_context_summary(self, current_identity: str, current_channel: str = None, ai_decision: bool = True, max_chars: int = 1000): family_id = self.get_family_group(current_identity) all_entries = [] if ai_decision and family_id: family_members = self.data["family_groups"][family_id]["members"] for member_identity in family_members: if member_identity == current_identity: continue if member_identity in self.data["identities"]: identity_data = self.data["identities"][member_identity] for channel, entries in identity_data.items(): for entry in entries: if datetime.fromisoformat(entry["time"]) > datetime.now() - timedelta(minutes=30): all_entries.append({ "identity": member_identity, "channel": channel, "time": entry["time"], "summary": entry["summary"], "from_family": True }) ``` ### Technical Analysis Family-group membership is managed through caller-supplied string identifiers. The code does not authenticate the caller, verify group ownership, request consent from the ...[truncated 1556 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bind every operation to an authenticated, server-established caller identity. 2. Do not accept `current_identity` as proof of identity. 3. Restrict group creation and membership changes to authenticated group owners or administrators. 4. Require explicit, recorded consent from every member before sharing their memory. 5. Make cross-member sharing opt-in rather than enabled by default. 6. Add per-record authorization checks before including an entry in a context summary. 7. Isolate cache files by tenant and user instead of keeping all identities in one shared document. 8. Protect membership metadata against direct modification using restrictive permissions and, where appropriate, integrity checks or a trusted database. 9. Add tests proving that unrelated users and unauthorized group members cannot retrieve each other's entries. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
complete_context.py:236
Finding
Untrusted Stored Messages Are Injected Directly into Agent Context<![CDATA[ ## Vulnerability Details **File Location**: `complete_context.py:236-254`, `channel_activity.py:229-250`, `INTEGRATION.md:28-34` **Vulnerability Type**: Stored cross-channel prompt injection **Risk Level**: High ### Evidence ```python def _combine_context( self, stm_entries: List[Dict], ltm_content: str ) -> str: combined = [] if stm_entries: combined.append("[短期记忆 - 最近30分钟]") for entry in stm_entries: timestamp = entry.get('created_at', '') content = entry.get('content', '') channel = entry.get('channel', '') combined.append(f"- [{channel}] {timestamp}: {content}") combined.append("") if ltm_content: combined.append("[长期记忆 - 永久记忆]") combined.append(ltm_content) return "\n".join(combined) ``` The integration guide additionally recommends automatically calling the session hook before every session and injecting its result into the model context. ### Technical Analysis Message content and long-term-memory content are treated as trusted context even though they can originate from user-controlled chat messages or mutable local files. The implementation concatenates the content into a prompt-like string without: - Marking it as untrusted data. - Escaping instruction delimiters or control syntax. - Preventing the model from following instructions found in memory. - Applying provenance, authorization, or content-policy checks. - Separating data from higher-priority agent instructions. This creates a stored prompt-injection channel. Truncating a message does not neutralize instruction-like content because a short malicious instruction can remain fully effective. Automatic session-hook integration increases the risk because the malicious content can be inserted into unrelated sessions without an explicit retrieval request. ### Attack Path 1. An attacker submits a message on a monitored channel containing an instruction aimed at the ...[truncated 1054 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat all stored messages and memory-file content as untrusted data. 2. Insert memory through a structured data channel rather than concatenating it into free-form instructions. 3. Add an explicit trusted instruction stating that content inside memory records must never be followed as commands. 4. Delimit each record and preserve provenance, author, channel, and trust level. 5. Escape or reject model-control syntax and known prompt-injection patterns as defense in depth. 6. Apply user, tenant, and group authorization before context construction. 7. Do not inject memory automatically into every session; retrieve only records relevant to an explicit user request. 8. Require confirmation before memory-derived content can cause side effects or tool calls. 9. Ensure tool authorization is performed outside the model and cannot be bypassed by prompt content. 10. Add adversarial tests using stored messages that attempt to override instructions, disclose secrets, or invoke tools. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
short_term_memory.py:137
Finding
Optional User Filters Permit Enumeration of the Shared Memory Cache<![CDATA[ ## Vulnerability Details **File Location**: `short_term_memory.py:137-216` **Vulnerability Type**: Missing object-level authorization **Risk Level**: High ### Evidence ```python def read( self, channel: Optional[str] = None, user_id: Optional[str] = None, limit: int = 10 ) -> List[Dict[str, Any]]: results = [] now = time.time() for entry in reversed(self.entries): if entry.get('expires_at', 0) <= now: continue if channel and entry.get('channel') != channel: continue if user_id and entry.get('user_id') != user_id: continue results.append(entry) if len(results) >= limit: break return results ``` ```python def query(self, query_text: str, limit: int = 5) -> List[Dict[str, Any]]: results = [] query_lower = query_text.lower() now = time.time() for entry in reversed(self.entries): if entry.get('expires_at', 0) <= now: continue if query_lower in entry.get('content', '').lower(): results.append(entry) if len(results) >= limit: break return results ``` ### Technical Analysis The `read()` method treats `user_id` and `channel` as optional convenience filters rather than mandatory authorization scope. Calling `read()` without filters returns entries belonging to every user in the shared cache. The `query()` method is more permissive: it has no user or tenant scope at all and searches every unexpired entry. Returned records contain the complete stored content and associated metadata. A caller can also supply another user's identifier because the library does not authenticate or bind that identifier to the caller. Similar optional-filter behavior is present in `CompleteContext.get_complete_context()`. ### Attack Path 1. An attacker gains access to an application endpoint or plugin operation that exposes these methods. 2. The attacker calls `r ...[truncated 853 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require an authenticated caller context for every read, search, update, delete, and upgrade operation. 2. Make tenant and user scope mandatory and derive both from trusted authentication state. 3. Do not authorize access based solely on a caller-supplied `user_id`. 4. Remove unrestricted global query operations or reserve them for explicitly authorized administrators. 5. Store each tenant or user in a separate database partition or file with restrictive permissions. 6. Return only the minimum fields required by the caller. 7. Add pagination and abuse controls, but do not rely on result limits as an access-control mechanism. 8. Add negative authorization tests for omitted, forged, and cross-tenant identifiers. ]]>

T07 · Tool Hijacking and Spoofing

Warning
Location
session_hook.py:6
Finding
Hard-Coded Import Precedence Path Allows Local Module Spoofing<![CDATA[ ## Vulnerability Details **File Location**: `session_hook.py:6-9`, `session_hook_lite.py:6-9` **Vulnerability Type**: Python module search-path hijacking **Risk Level**: Medium ### Evidence ```python import sys sys.path.insert(0, '/Users/kunpeng.zhu/.openclaw/workspace/skills/short-term-memory') from channel_activity import ChannelActivity ``` The same pattern appears in both session-hook implementations. ### Technical Analysis The code inserts a hard-coded external directory at index zero of `sys.path`. This gives modules in that directory precedence over installed or package-relative modules. Python executes top-level code when importing a module. Therefore, if an attacker can create or replace `channel_activity.py` in the hard-coded directory, the attacker's code executes as soon as the session hook is loaded. The path also refers to one developer's workspace rather than the verified installed package, making it possible for the runtime to import a different file from the one reviewed in this audit. ### Attack Path 1. An attacker gains write access to the hard-coded workspace directory, its parent, or the target module. 2. The attacker creates or replaces `channel_activity.py` with a malicious module. 3. A session starts and loads `session_hook.py` or `session_hook_lite.py`. 4. The hook places the attacker-controlled directory first in `sys.path`. 5. Python imports and executes the spoofed module with the privileges of the Agent process. ### Impact Assessment Successful exploitation results in arbitrary Python code execution under the account running the Agent. This can expose all files, credentials, environment variables, memory content, and tools accessible to that process. Exploitation requires write access to the specified local path or an equivalent filesystem compromise. It does not independently provide remote access. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the `sys.path.insert()` statements. 2. Package the project as a proper Python module and use package-relative imports. 3. Resolve resources relative to the verified package location rather than a developer-specific workspace. 4. Install the package into a controlled virtual environment with pinned dependencies. 5. Ensure the package directory and its parent are not writable by untrusted users. 6. Verify ownership and permissions before loading optional plugins. 7. Avoid importing executable modules from mutable workspace or cache directories. 8. Add deployment tests that confirm the imported module path matches the expected installed artifact. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
channel_activity.py:33
Finding
Plaintext Memory Storage and Incomplete TTL Purging Retain Sensitive Data<![CDATA[ ## Vulnerability Details **File Location**: `channel_activity.py:33-37`, `channel_activity.py:110-131` **Vulnerability Type**: Insecure sensitive-data storage and incomplete retention enforcement **Risk Level**: Medium ### Evidence ```python def _save(self): Path(self.cache_path).parent.mkdir(parents=True, exist_ok=True) with open(self.cache_path, 'w', encoding='utf-8') as f: json.dump(self.data, f, indent=2, ensure_ascii=False) ``` ```python def record(self, identity: str, channel: str, message: str, user_id: str = None, max_length: int = 100): now = datetime.now() if len(message) > max_length: summary = message[:max_length] + "..." else: summary = message if identity not in self.data["identities"]: self.data["identities"][identity] = {} if channel not in self.data["identities"][identity]: self.data["identities"][identity][channel] = [] entry = { "time": now.isoformat(), "summary": summary, "user_id": user_id } self.data["identities"][identity][channel].append(entry) cutoff = now - timedelta(minutes=self.ttl_minutes) self.data["identities"][identity][channel] = [ e for e in self.data["identities"][identity][channel] if datetime.fromisoformat(e["time"]) > cutoff ] self._save() ``` ### Technical Analysis Message summaries and user identifiers are serialized to a plaintext JSON file. The write operation does not explicitly establish restrictive file permissions, encryption, or integrity protection. The advertised 30-minute TTL is not enforced as physical deletion across the entire cache. Cleanup in `record()` only processes the identity and channel currently receiving a new record. Inactive channels can retain expired entries on disk indefinitely. Retrieval methods filter expired records from output, but filtering does not erase the underlying plaintext data. Local users, backups, diagnostic tools, or compr ...[truncated 1070 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Purge expired records across every identity and channel during load, read, search, and write operations. 2. Add a reliable periodic cleanup mechanism where the deployment architecture supports it. 3. Perform an immediate full-cache cleanup before every save. 4. Create cache files with owner-only permissions, such as mode `0600`, and restrict the parent directory. 5. Use atomic writes through a protected temporary file followed by a rename. 6. Minimize stored content and avoid stable user identifiers unless strictly required. 7. Encrypt stored memory where the threat model includes other local users, shared storage, or backups. 8. Define and enforce deletion behavior for backups and replicas. 9. Document that filtering expired records is not equivalent to secure deletion. 10. Add tests verifying that expired entries are physically removed even when their original channel receives no new messages. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:14
Finding
Mutable Latest-Tag Installer Executes Unpinned Third-Party Code<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:14`, `README_CLAWHUB.md:34` **Vulnerability Type**: Unpinned executable installation dependency **Risk Level**: Medium ### Evidence ```bash npx clawhub@latest install channel-activity ``` ### Technical Analysis The installation command directs `npx` to obtain and execute the package currently referenced by the mutable `latest` tag. The effective installer code can therefore differ from the version reviewed during this audit. No exact package version, integrity hash, lockfile, or immutable artifact reference is specified. A compromised publisher account, registry compromise, or unexpected upstream release could alter the code executed by users following the documented installation procedure. This audit did not find evidence that the current package is malicious; the issue is the unsafe and mutable dependency-selection mechanism. ### Attack Path 1. The upstream `clawhub` package or its `latest` tag is changed or compromised. 2. A user follows the documented installation command. 3. `npx` downloads the package version currently associated with `latest`. 4. Package code executes locally as part of the installation command. 5. The compromised installer acts with the permissions of the invoking user. ### Impact Assessment A compromised installer could access or modify any files and configuration available to the invoking account. In a typical Agent workspace, this may include Skill code, memory files, API configuration, credentials, and runtime hooks. The vulnerability is supply-chain dependent and does not prove that the referenced upstream package is presently compromised. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the installer to an exact audited version instead of `latest`. 2. Verify the package with a registry integrity hash, signature, or trusted checksum. 3. Use a lockfile or immutable internal artifact repository. 4. Review installer lifecycle scripts before execution. 5. Prefer a preinstalled, centrally managed CLI in production environments. 6. Document the expected publisher, package digest, and verification procedure. 7. Re-audit the pinned package before upgrading. 8. Run installation with the minimum filesystem and operating-system privileges required. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (40)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documented purpose is short-term channel memory, but the finding indicates undeclared local persistence, retention behavior differences, and long-term memory upgrade capability not disclosed in the description. This mismatch is dangerous because users and agent frameworks may authorize a low-risk transient memory skill while it actually stores data longer or more broadly than expected, increasing privacy and data handling risk.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
get_context_summary intentionally includes recent message summaries from other identities in the same family group whenever ai_decision is enabled, with no demonstrated consent, authorization, or policy check. This creates a direct cross-identity information disclosure path where private conversation summaries from one user can be surfaced to another user or channel context.

Missing User Warnings

High
Confidence
98% confidence
Finding
The family-group sharing logic exposes summaries of other members' recent activity with only a comment claiming the AI can decide sharing, but no actual privacy safeguard or warning. In practice this means private content from one identity may be silently revealed in another identity's context, which is a serious confidentiality issue in a memory skill.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The recommended automatic hook injects session data into context before every conversation without any notice about collection, retention, or cross-channel reuse of user content. Automating this behavior increases the likelihood of silent privacy violations and unintended disclosure because the model receives data from other channels by default.

Ssd 3

Medium
Confidence
97% confidence
Finding
These instructions normalize carrying user content from one channel directly into another channel's prompt and response flow. Because the transfer is automatic and happens at the prompt layer, it creates a natural-language exfiltration channel that can leak private information across otherwise separate conversations, especially if channels have different audiences, devices, or trust levels.

Ssd 3

Medium
Confidence
98% confidence
Finding
The example workflow shows the assistant disclosing what the user said in Feishu when asked from QQ, effectively endorsing cross-channel recall as normal behavior. In practice, this can reveal sensitive notes, personal data, or confidential business information to a different client, session, or observer without verifying whether disclosure is appropriate in the current context.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation explicitly describes retrieving recent activity from other channels and surfacing it in the current conversation, but provides no user consent, access control, or privacy warning. This creates a cross-channel data disclosure path where content shared in Feishu can be revealed in QQ (and vice versa) merely based on channel context rather than explicit user authorization.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The README explicitly describes collecting and caching cross-channel user content together with persistent user IDs, and even promoting short-term entries into long-term memory, but provides no privacy notice, retention guidance, access-control expectations, or consent considerations. In a multi-channel memory skill, that omission is security-relevant because it can lead operators to deploy cross-context data aggregation and retention in ways that expose personal data, enable unintended profiling, or violate least-privilege and data-minimization principles.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill explicitly stores per-channel message summaries and `user_id` values, then enables retrieval across channels, but the README provides no consent, minimization, access-control, or privacy-boundary guidance. This creates a real risk of unintended disclosure of user activity and identifiers between contexts that users may reasonably expect to remain separate.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Ssd 3

Medium
Confidence
98% confidence
Finding
The examples instruct the assistant to restate content said in one channel inside another channel in plain language, which directly normalizes cross-context disclosure of potentially sensitive conversation data. In a multi-channel assistant, this is especially dangerous because channel separation often implies different audiences, devices, or trust levels, so a benign memory feature can become a privacy leak.

Lp3

Medium
Category
MCP Least Privilege
Confidence
80% confidence
Finding
The skill advertises installable code and its documented behavior implies stateful memory, but the manifest declares no explicit tool scope or permissions despite detected file read/write capability. This creates a transparency and least-privilege problem: an agent or operator may grant or run the skill without understanding that it can persist or access local data.

Rp1

Medium
Category
MCP Rug Pull
Confidence
93% confidence
Finding
Using `npx clawhub@latest install channel-activity` pulls the latest package version at install time, which is a supply-chain risk because future compromised or incompatible releases could be executed automatically. In a skill installation path, this is especially risky because users may treat the command as trusted setup guidance and run unreviewed code.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documentation explicitly describes recording what users say in one channel, retaining it for 30 minutes, and then promoting expired content into permanent memory without any consent, minimization, or disclosure controls. This creates a real privacy and data-governance risk because sensitive content shared in one context may be silently persisted and later exposed in another context.

Ssd 3

Medium
Confidence
97% confidence
Finding
These instructions describe retaining user messages across channels and sessions and automatically converting temporary memory into permanent memory. In the context of an AI assistant, that behavior is dangerous because it breaks contextual boundaries and can cause unauthorized long-term storage of sensitive information that users may have only intended for a single channel or short-lived interaction.

Ssd 3

Medium
Confidence
98% confidence
Finding
The example workflow shows the assistant recalling a statement from Feishu and surfacing it in QQ as conversation context. That is a concrete cross-channel data disclosure pattern: information provided in one platform can be revealed in another without verifying identity, consent, or whether the destination channel should receive the data.

Ssd 3

Medium
Confidence
96% confidence
Finding
The guidance instructs the AI to include long-term memory and channel activity summaries in every reply context. This broad default inclusion increases the chance of prompt-context overexposure, unnecessary retention, and accidental disclosure of unrelated or sensitive information to users, tools, or downstream model calls.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill writes conversation summaries to a persistent JSON file on disk without any notice, retention confirmation beyond code comments, or protection mechanism shown here. Persisting cross-channel activity data increases exposure to local compromise, accidental reuse, forensic recovery, or misuse by other components that can read the file.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The code introduces family-group membership and cross-identity grouping even though the skill is described as short-term channel activity memory. That hidden expansion of scope materially changes the trust boundary: data associated with one identity may later be linked to a broader sharing domain than a user would reasonably expect.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The manifest describes the skill as 'Multi-channel short-term memory for AI assistants', which implies transient recording and retrieval of recent context. Beyond that, the code adds explicit update, delete, search, and full clear capabilities over stored memories, expanding behavior from simple short-term memory into broader memory management.

Natural-Language Policy Violations

Medium
Confidence
87% confidence
Finding
This Python file contains user-facing natural-language documentation and runtime messages entirely in Chinese, including the module description and status output. Because the skill does not offer any language/locale opt-in or explain that it is intentionally region-specific, it creates a language-policy concern under the locale-choice rule.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The skill advertises multi-channel short-term memory but its main context API also loads and returns long-term memory from MEMORY.md. This creates a scope mismatch that can expose durable, potentially sensitive data to callers who expect only time-limited channel activity, increasing the chance of unintended data disclosure across sessions or users.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The query interface searches long-term memory in addition to short-term entries, despite the skill being presented as short-term channel activity memory. This broadens retrieval scope silently and may let a user discover sensitive persistent information through simple keyword searches that were expected to be limited to recent ephemeral context.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
This JSON file contains user-facing natural-language summaries such as "项目 A 需要处理", "下午 3 点开会", and "妈妈去买菜了" in Chinese only. Under the policy, forcing a specific language without user opt-in or a documented locale justification is a natural-language policy violation.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The cache stores a persistent user identifier together with task-specific message content, which constitutes sensitive conversational and identity-linked data retention. In a multi-channel memory component, this increases privacy risk because anyone with access to the cache can correlate a specific user to their requests, and the `upgrade_to_long_term` setting makes the context more dangerous by potentially extending retention beyond the short-term purpose.

Static analysis

No suspicious patterns detected.