Back to skill

Security audit

Chat Logger

Security checks for vulnerabilities and agentic risk

Overview

This chat-logging skill has a coherent purpose, but it stores private messages and can expose all users' logs without clear authorization controls.

Review this skill carefully before installing. It may be acceptable only in a controlled workspace where all users know their direct messages are being logged, global summaries are restricted to authorized admins, and the path handling is fixed to prevent writes outside the intended log directory.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (5)

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:33
Finding

Main Agent Control-Flow Hijacking Through Mandatory Skill Instructions

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:33-57
Vulnerability Type: Mandatory instructions that override the host Agent's routing and processing behavior
Risk Level: Critical

Vulnerable Code

python
from skills.chat_logger.skill import handle_chat_query, record_message

# Step 1: Check whether this is a Chat Logger query command
if message.strip() in ["chatlog summary", "daily briefing", "my records"]:
    # The original instructions require exclusive Chat Logger execution
    result = handle_chat_query(message, user_name, channel)
    if result:
        print(result)
        return  # Immediately stop all subsequent processing

The surrounding Skill instructions explicitly require that the main Agent must not process matching messages, must return the Skill result without modification, and must immediately terminate subsequent processing.

Technical Analysis

The Skill does not merely document its callable API. It directs the host Agent to surrender control over message routing and response handling. For selected trigger messages, the Agent is instructed to:

  1. Execute only this Skill.
  2. Avoid its normal processing logic.
  3. Return the Skill-generated content without modification.
  4. Terminate processing immediately.

These requirements can bypass competing handlers, policy checks, output validation, and other security controls that would ordinarily run after Skill execution. This behavior matches instruction hijacking because the Skill text attempts to alter the active Agent's goals and control flow when loaded.

Attack Path

  1. The Chat Logger Skill is loaded, including the mandatory routing instructions in SKILL.md.
  2. A user sends one of the designated query commands.
  3. The main Agent follows the Skill's instruction to execute only handle_chat_query().
  4. The Skill generates a response containing stored log information.
  5. The main Agent returns that resp ...[truncated 640 chars]
Remediation
View remediation

Remediation Suggestions

  • Remove all instructions stating that the main Agent is forbidden from processing a message.
  • Remove requirements to return Skill output unchanged or terminate processing immediately.
  • Describe handle_chat_query() as an optional API rather than an exclusive routing mechanism.
  • Leave authorization, routing, policy enforcement, and output validation under the host Agent's control.
  • Require all Skill responses to pass through the host's standard safety and disclosure checks.
  • Document supported commands without imposing higher-priority behavioral instructions on the Agent.

T09 · Insecure Skill Coding Practices

Error
Location
skill.py:25
Finding

Arbitrary Filesystem Path Traversal Through Unvalidated Channel Names

Content
View full analysis

Vulnerability Details

File Location: skill.py:25-71
Vulnerability Type: Path traversal and write outside the intended log directory
Risk Level: High

Vulnerable Code

python
def _safe_name(self, name: str) -> str:
    """Sanitize a name by replacing selected characters."""
    return re.sub(r'[\\/:*?"<>|]', '_', name)

def _get_channel_dir(self, channel: str) -> Path:
    """Obtain the channel directory."""
    channel_map = {
        'feishu': 'feishu',
        'dingtalk': 'dingtalk',
        '飞书': 'feishu',
        '钉钉': 'dingtalk'
    }
    channel_en = channel_map.get(channel, channel)
    return self.base_dir / channel_en

def write_message(self, channel: str, user_name: str, user_content: str) -> bool:
    try:
        date = datetime.now().strftime('%Y-%m-%d')
        time_str = datetime.now().strftime('%H:%M')

        channel_dir = self._get_channel_dir(channel)
        user_dir = channel_dir / self._safe_name(user_name)
        user_dir.mkdir(parents=True, exist_ok=True)

        file_path = user_dir / f"{date}.md"

        if not file_path.exists():
            header = f"# {date} record - {user_name} ({channel})\n\n"
            file_path.write_text(header, encoding='utf-8')

        entry = f"\n### {time_str}\n**User**: {user_content}\n"

        with open(file_path, 'a', encoding='utf-8') as f:
            f.write(entry)

Technical Analysis

_get_channel_dir() maps recognized values but accepts every unrecognized channel value unchanged. The value is then joined directly to base_dir. A channel containing ../ components can therefore resolve outside the intended memory/chat-logs directory. An absolute channel path can also cause pathlib to discard the preceding base path.

The username sanitizer only replaces a limited set of characters. It does not reject . or .., and the code does not resolve and validate the final path befor ...[truncated 1469 chars]

Remediation
View remediation

Remediation Suggestions

  • Reject every channel not present in an explicit allowlist such as {"feishu", "dingtalk"}.
  • Do not use the original channel value as a fallback path component.
  • Reject empty names, ., .., absolute paths, and names containing path separators.
  • Resolve the final destination with Path.resolve() before any directory creation or file write.
  • Verify that the resolved path is a descendant of the resolved base_dir, for example with relative_to().
  • Use stable internal user and channel identifiers instead of display names for filesystem paths.
  • Apply restrictive directory and file permissions.
  • Add tests covering ../, absolute paths, repeated traversal components, Unicode path separators, and symlink-based escapes.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
skill.py:289
Finding

Cross-User Conversation Disclosure Through Unscoped Record Queries

Content
View full analysis

Vulnerability Details

File Location: skill.py:289-310
Vulnerability Type: Missing object-level authorization and user scoping
Risk Level: High

Vulnerable Code

python
def handle_chat_query(message: str, user_name: str,
                      channel: str = None) -> Optional[str]:
    message = message.strip()

    if channel:
        record_message(channel, user_name, message)

    if "今日简报" in message or "今天简报" in message:
        return get_daily_summary()

    if "我的记录" in message or "我的简报" in message:
        return get_daily_summary()

    if "chatlog汇总" in message.lower() or "chatlog" in message.lower():
        return get_chatlog_summary()

    return None

The called daily-summary implementation traverses every channel and every user directory:

python
for channel_dir in sorted(base_dir.iterdir()):
    if not channel_dir.is_dir():
        continue

    for user_dir in sorted(channel_dir.iterdir()):
        if not user_dir.is_dir():
            continue

        file_path = user_dir / f"{date}.md"
        if file_path.exists():
            content = file_path.read_text(encoding='utf-8')

Technical Analysis

handle_chat_query() receives user_name, but does not use it to scope access. The command corresponding to “my records” calls the same global get_daily_summary() used for the system-wide daily report. That function iterates through all channel and user directories and reveals user identifiers and message counts.

The broader chatlog query calls get_chatlog_summary(), which also traverses all users and returns message excerpts. No authentication, role verification, access-control check, ownership validation, or channel isolation is performed before the records are returned.

Attack Path

  1. Multiple users have conversation records stored under the shared Chat Logger base directory.
  2. A non-administrative user invokes the person ...[truncated 854 chars]
Remediation
View remediation

Remediation Suggestions

  • Bind the caller to an authenticated, immutable user identifier supplied by the trusted host rather than a user-controlled display name.
  • Implement a user-scoped summary function and pass the authenticated identity to it for personal queries.
  • Resolve only the authenticated user's canonical storage directory instead of traversing the complete base directory.
  • Restrict global daily and complete summaries to explicitly authorized administrator roles.
  • Enforce channel or tenant isolation where records from different workspaces are stored together.
  • Avoid exposing raw message excerpts unless the caller has explicit permission to view message content.
  • Add authorization tests proving that one user cannot enumerate or read another user's records.

T01 · Skill Instruction Hijacking

Warning
Location
skill.py:303
Finding

Overbroad Substring Triggers Bypass Documented Exact-Match Routing

Content
View full analysis

Vulnerability Details

File Location: skill.py:303-310
Vulnerability Type: Overbroad Skill activation and unexpected control-flow interception
Risk Level: Medium

Vulnerable Code

python
if "今日简报" in message or "今天简报" in message:
    return get_daily_summary()

if "我的记录" in message or "我的简报" in message:
    return get_daily_summary()

if "chatlog汇总" in message.lower() or "chatlog" in message.lower():
    return get_chatlog_summary()

Technical Analysis

The Skill documentation claims strict, exact matching for a limited set of commands. The implementation instead performs substring checks and supports additional undocumented aliases. In particular, any message containing the case-insensitive string chatlog is interpreted as a request for the complete global summary.

This discrepancy significantly expands the activation surface. A normal sentence discussing the logger, quoted text, or attacker-supplied content containing the trigger can activate a sensitive query. When combined with the documented requirement that the main Agent immediately return the Skill output and stop processing, the substring match can unexpectedly intercept normal requests and bypass subsequent Agent handling.

Attack Path

  1. A user sends an otherwise unrelated message that contains the word chatlog.
  2. The host invokes handle_chat_query() as directed by the Skill integration.
  3. The final condition evaluates as true even though the complete message is not an authorized command.
  4. get_chatlog_summary() generates a global report containing stored message excerpts.
  5. Under the documented host flow, the main Agent returns the report and terminates normal processing.

Impact Assessment

This flaw enables unintended activation of a sensitive global-data operation. It can cause accidental cross-user disclosure, denial of expected Agent processing, and unauthorized command execution in contexts where ...[truncated 138 chars]

Remediation
View remediation

Remediation Suggestions

  • Normalize the complete input once and compare it against an explicit command allowlist using equality.
  • Do not use substring matching for privileged or data-disclosing commands.
  • Keep documented and implemented trigger sets identical.
  • Require separate authorization before executing global-summary commands.
  • Ensure the host Agent retains the ability to validate the command and resulting output.
  • Add negative tests for sentences, quotations, prefixes, suffixes, and mixed-content messages containing trigger terms.

T09 · Insecure Skill Coding Practices

Warning
Location
skill.py:317
Finding

Broken Incoming-Message Hook Causes Silent Audit Logging Failure

Content
View full analysis

Vulnerability Details

File Location: skill.py:317-336
Vulnerability Type: Invalid method invocation and inconsistent logging API contract
Risk Level: Medium

Vulnerable Code

python
def on_incoming_message_hook(channel: str, sender_id: str,
                             sender_name: str, content: str,
                             **kwargs) -> dict:
    try:
        chat_type = kwargs.get('chat_type', 'direct')

        if chat_type != 'direct':
            return {'success': True, 'skipped': 'group_chat'}

        success = _chat_logger.record_message(
            channel, sender_name, content, chat_type
        )

        return {'success': success, 'recorded': success}
    except Exception as e:
        return {'success': False, 'error': str(e)}

The ChatLoggerSkill class defines write_message() rather than record_message(). Separately, the module-level record_message() function accepts only three arguments:

python
def record_message(channel: str, user_name: str,
                   user_content: str) -> bool:
    return _chat_logger.write_message(channel, user_name, user_content)

Technical Analysis

The incoming-message Hook invokes _chat_logger.record_message(), but no such instance method exists. Every direct-message Hook invocation therefore raises AttributeError. The broad exception handler converts this into a failure dictionary, which can be ignored by integrations expecting automatic logging.

The documentation also presents a four-argument record_message() contract including chat_type, while the implemented module-level function accepts only three arguments. Integrations following the documented contract will raise TypeError.

Because the Skill describes the Hook and explicit call as a redundant logging mechanism, these inconsistencies create false assurance that messages are being recorded reliably.

Attack Path

  1. A direc ...[truncated 950 chars]
Remediation
View remediation

Remediation Suggestions

  • Replace the invalid call with _chat_logger.write_message(channel, sender_name, content).
  • Alternatively, implement a correctly typed instance method and use it consistently.
  • Define one canonical record_message() signature and align the class, module function, Hook, and documentation.
  • Handle chat_type consistently at a single API boundary.
  • Avoid silently swallowing logging failures; emit structured host-visible telemetry and metrics.
  • Add unit and integration tests for direct messages, group messages, Hook failures, and documented API examples.
  • Configure the host to detect and alert on unsuccessful audit-log writes.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (14)

Ssd 3

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The documented command 'chatlog汇总' is described as allowing 'all users' complete summaries', which implies cross-user access to stored conversations. That is a direct data disclosure vulnerability: any user who can invoke the command may obtain other users' private chat history or summaries without a demonstrated authorization boundary.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documentation claims strict, exact-match trigger handling and emphasizes that the main agent must not handle certain messages, yet the skill also describes hook-based automatic recording and dual execution paths. This mismatch is dangerous because integrators may rely on the documented safety model while the actual behavior records or processes messages more broadly than expected, defeating user consent and policy assumptions.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill is explicitly designed to collect every direct-message user input into persistent logs and expose retrieval/summarization commands over that stored data. This creates a substantial privacy risk because sensitive content may be retained and later surfaced without adequate minimization, consent, or authorization controls.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill is designed to automatically persist user chat content to local files, yet there is no visible consent, disclosure, or opt-in mechanism. Silent logging of user messages can capture sensitive personal or business information and violate privacy expectations or compliance requirements.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill persistently stores user chat content in per-user files and later aggregates it, creating a durable repository of potentially sensitive communications. Because the design also supports cross-user summarization, compromise or misuse of this feature can expose private content beyond the original conversation context.

Content

No source excerpt is available for this finding.

Ssd 3

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

A plain-language request containing 'chatlog' can return a full all-user summary with message excerpts, without any authentication or authorization checks in the handler. This creates a direct cross-user data disclosure path: any caller able to invoke the skill may obtain metadata and content snippets from other users' conversations.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest describes strict exact-match triggers, but the implementation accepts broad substring matches such as any message containing 'chatlog' or variants of summary phrases. This weakens routing guarantees and can invoke sensitive reporting behavior unexpectedly, increasing the chance that ordinary conversation text triggers disclosure of stored logs.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The hook is intended to auto-record incoming direct messages without any user-facing warning, which makes collection invisible and continuous. Even though the current implementation appears broken, the intended design is still privacy-invasive and dangerous if corrected or deployed in a compatible environment.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill documents persistent file read/write behavior but does not declare any tool scope or permission boundary. In practice this weakens governance and reviewability: an agent integrating the skill may grant broader filesystem access than users or operators expect, increasing the chance of unintended data exposure or tampering.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill automatically persists incoming direct messages to chat logs but does not present a clear user-facing warning or consent mechanism in the primary description. Silent collection of conversation content creates privacy and compliance risk, especially when users may reasonably assume ephemeral chat rather than durable storage.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language instructions define activation exclusively through Chinese phrases such as chatlog汇总, 今日简报, and 我的记录, and the document presents the skill entirely in Chinese without any opt-in or alternative locale. SQP-3 applies to all file types when a skill forces a specific language or locale without user choice or documented justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The natural-language description and interaction strings are entirely Chinese and present the skill as operating in that locale without any opt-in or alternative language option. Under the policy, language constraints should not be forced unless the skill clearly offers choice or documents a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The module docstring states "主动调用模式,不依赖 Hook" (active invocation mode, not dependent on Hook). Later code explicitly defines hook entry points and documents a "Hook + 显式调用双保险" design for automatic recording, which directly contradicts the stated intent.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The hook docstring says this is an automatic-recording hook that calls the core logging function. However, the implementation invokes _chat_logger.record_message(...), while the class only defines write_message(...), so the documented behavior does not match the actual code path and the hook cannot perform as described.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.