Back to skill

Security audit

Slack Channel Context

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly does what it says, but its filename handling can let channel metadata read Markdown files outside the intended Slack context folder.

Review before installing. Use this only in Slack channels where automatic context injection is desired, keep context files free of secrets and sensitive private data, and avoid exposing the tool to untrusted channel_id or channel_name values until the path traversal issue is fixed with strict identifier validation and resolved-path containment checks.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/skill.py:102
Finding

Path Traversal in the Primary Slack Context Loader

Content
View full analysis

Vulnerability Details

File Location: scripts/skill.py:102-118 (duplicated in the force-reload path at scripts/skill.py:269-278)
Vulnerability Type: Path traversal leading to unauthorized local file disclosure
Risk Level: Medium

Vulnerable Code

python
# Try channel ID first (in contexts folder)
if channel_id:
    context_file = self.contexts_dir / f"{channel_id}.md"
    if context_file.exists():
        content = self._read_file(context_file)
        self._cache(cache_key, content)
        return content

# Try channel name (in contexts folder)
if channel_name:
    # Normalize channel name (remove #, lowercase)
    normalized_name = channel_name.lstrip("#").lower()
    context_file = self.contexts_dir / f"{normalized_name}.md"
    if context_file.exists():
        content = self._read_file(context_file)
        self._cache(cache_key, content)
        return content

The resulting path is passed to the following file-reading sink at scripts/skill.py:126-133:

python
def _read_file(self, filepath):
    """Read and return file contents."""
    try:
        with open(filepath, "r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        print(f"Error reading {filepath}: {e}")
        return None

Technical Analysis

The loader treats channel_id and channel_name as path components without validating that they conform to Slack identifier syntax. It does not reject path separators, .. components, or absolute paths. It also does not resolve the resulting path and verify that it remains under self.contexts_dir.

Consequently, a value such as ../../notes produces a path equivalent to:

text
~/.openclaw/workspace/slack-channel-contexts/../../notes.md

Path.exists() and open() follow this traversal and read the target if it exists and is accessible to the OpenClaw process. The automatically appended ...[truncated 1736 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate channel IDs with a strict allowlist matching expected Slack identifier syntax, such as uppercase alphanumeric identifiers of an appropriate length.
  2. Validate channel names with a conservative allowlist, such as lowercase letters, digits, hyphens, and underscores.
  3. Explicitly reject /, \, null bytes, absolute paths, . components, and .. components.
  4. Resolve the context directory and candidate file before opening it, then verify containment:
python
base = self.contexts_dir.expanduser().resolve()
candidate = (base / f"{validated_identifier}.md").resolve()

try:
    candidate.relative_to(base)
except ValueError:
    raise ValueError("Context path escapes the configured context directory")
  1. Require the resolved target to be a regular file. If symlinks are not needed, reject symbolic links to prevent link-based directory escape.
  2. Centralize path construction in one validated helper and use it in both normal and force-reload flows.
  3. Add regression tests for ../, absolute paths, nested separators, symlink escapes, empty identifiers, and valid Slack IDs and names.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/load_context.py:105
Finding

Path Traversal in the Legacy Slack Context Loader

Content
View full analysis

Vulnerability Details

File Location: scripts/load_context.py:105-121 (duplicated in the force-reload path at scripts/load_context.py:272-281)
Vulnerability Type: Path traversal leading to unauthorized local file disclosure
Risk Level: Medium

Vulnerable Code

python
# Try channel ID first (in contexts folder)
if channel_id:
    context_file = self.contexts_dir / f"{channel_id}.md"
    if context_file.exists():
        content = self._read_file(context_file)
        self._cache(cache_key, content)
        return content

# Try channel name (in contexts folder)
if channel_name:
    # Normalize channel name (remove #, lowercase)
    normalized_name = channel_name.lstrip("#").lower()
    context_file = self.contexts_dir / f"{normalized_name}.md"
    if context_file.exists():
        content = self._read_file(context_file)
        self._cache(cache_key, content)
        return content

The resulting path is read at scripts/load_context.py:129-136:

python
def _read_file(self, filepath):
    """Read and return file contents."""
    try:
        with open(filepath, "r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        print(f"Error reading {filepath}: {e}")
        return None

Technical Analysis

The legacy compatibility module duplicates the primary loader's unsafe path construction. Caller-controlled channel identifiers are interpolated into filenames and joined to the context directory without syntax validation or a resolved-path containment check.

Directory traversal components and absolute paths can therefore cause the loader to inspect and read files outside the declared slack-channel-contexts directory. Keeping this module for backward compatibility preserves the vulnerability for integrations that continue importing scripts/load_context.py, including the included example and reload utility.

Attac

...[truncated 1197 chars]

Remediation
View remediation

Remediation Suggestions

  1. Apply the same strict identifier validation and canonical-path containment checks used in the primary implementation.
  2. Avoid maintaining duplicated security-sensitive path logic. Import the corrected loader from one canonical module or move safe path resolution into a shared helper.
  3. Reject absolute paths, separators, traversal components, null bytes, and identifiers that do not match expected Slack formats.
  4. Resolve both the base directory and candidate path, then enforce that the candidate is a descendant of the base directory before checking or opening it.
  5. Reject symlink targets outside the context directory, or disallow symlinks entirely if they are unnecessary.
  6. Update scripts/example.py and scripts/reload_all_contexts.py to import the canonical corrected implementation.
  7. Add tests that exercise both the primary and backward-compatible entry points to prevent the implementations from diverging.
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
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The declared purpose is automatic loading of the current Slack channel context, but the documented implementation also includes manual bulk reload and cache-bypass utilities. This mismatch can mislead operators about what the skill is capable of, making it easier for broader file processing behavior to be approved or triggered without appropriate scrutiny.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · TROUBLESHOOTING.md (reported line 10)May include surrounding context.

Check 1: Is the skill enabled?

bash
# Check if the variable is set in .env
grep SLACK_CONTEXT_ENABLED ~/.openclaw/workspace/.env
# Should return: SLACK_CONTEXT_ENABLED=true

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · TROUBLESHOOTING.md (reported line 11)May include surrounding context.

Check 1: Is the skill enabled?

bash
# Check if the variable is set in .env
grep SLACK_CONTEXT_ENABLED ~/.openclaw/workspace/.env
# Should return: SLACK_CONTEXT_ENABLED=true

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README promotes automatic loading of Slack channel context into AI sessions without any warning that these files may contain sensitive internal information and will be injected into model context. In a Slack-integrated skill, this increases the chance of unintended disclosure, over-sharing across conversations, or inclusion of confidential project data in prompts sent to downstream systems.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 38)May include surrounding context.

Important: Only add the skill name ("slack-channel-context") - not the full configuration!

Step 2: Create Context Files

bash
# Create the directory if it doesn't exist

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · README.template.md (reported line 18)May include surrounding context.

md
**For AI assistants:** Context files are loaded automatically when you're in a Slack channel. No action needed!

**For humans:** To create context for a new channel:
1. Read the [skill documentation](../../skills/slack-channel-context/SKILL.md)
2. Follow the "Creating Channel Context Files" section
3. Save as `<CHANNEL_ID>.md` or `<CHANNEL_NAME>.md` in this directory

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill documentation describes file, environment, and write-capable behavior but does not declare any explicit tool scope or permissions boundaries. In an agent ecosystem, undeclared capabilities can cause the skill to be invoked with broader authority than users expect, increasing the risk of unauthorized file access, context poisoning, or modification of workspace data.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger language says to use the skill whenever you are in a Slack channel or thread and need context, which is broad enough to activate in many ordinary conversations. Overbroad activation increases the chance of unnecessary loading of local files into session context, exposing unrelated sensitive information or allowing maliciously crafted context files to influence agent behavior.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documented automatic detection of Slack channels and threads lacks clear trust and scope constraints for when context should be injected. In practice, this can create prompt-injection and data-minimization issues because any detected channel/thread state may cause unreviewed local content to be imported into the model context.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description states that the skill 'automatically loads' Slack channel context for channels and threads, but it does not define narrow activation conditions or trust boundaries for when that loading should occur. In a Slack-integrated agent, broad auto-activation can cause untrusted or irrelevant channel files to be injected into the model context, increasing prompt-injection exposure and unintended data disclosure across conversations.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

Automatic filesystem scaffolding is not necessary for the core function of loading context and creates side effects beyond the advertised behavior of the skill. In this skill context, the danger is limited because it only writes a fixed README file, but it still creates an opportunity for unintended file creation when environment-controlled paths point outside the expected workspace.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The loader performs an unexpected filesystem write as part of reading channel context by auto-creating README.md on first use. Even though the written content comes from a bundled template rather than attacker input, this violates least surprise, can modify user workspaces without consent, and may be unsafe if the contexts directory is redirected via environment variables to a sensitive location.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

initialize_readme() creates directories and writes README.md with no interactive disclosure, and it can be triggered indirectly during message-context loading. While the content source is a local template rather than untrusted input, the undisclosed write behavior is still a genuine safety issue because it expands the skill from passive reading to mutation of the workspace.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill is described as a context loader, but it performs an undisclosed write by auto-creating README.md during normal context loading. Even though the write is limited to a documentation file, hidden side effects violate least surprise and can be unsafe in environments where skills are expected to be read-only unless explicitly invoked.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill performs automatic file creation as a side effect of loading context, without user-facing warning or confirmation. In agent/tooling environments, silent writes can undermine trust, create unexpected artifacts, and violate assumptions that a read helper is non-mutating.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The code writes README.md without any user-facing warning or confirmation when loading context, which is an unsafe surprise in a function expected to read files only. This is especially relevant for agent skills, where users may not realize a passive context-loading action can mutate the filesystem.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The manifest and module documentation describe a Slack channel/thread context loader. But get_context_for_slack_message also reads generic or non-Slack-looking fields such as chat_id and group_subject, indicating support for additional message-source schemas not justified by the stated Slack-specific purpose.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.