Back to skill

Security audit

Slack Thread Export

Security checks for vulnerabilities and agentic risk

Overview

This skill is built for Slack exports, but it needs review because it bulk-accesses a logged-in Slack session and contains unsafe JavaScript construction in that authenticated context.

Install only if you are authorized to export the relevant Slack workspace data, keep channel/date/user scope narrow, and treat all CSV/JSONL outputs as sensitive. The publisher should fix the browser JavaScript interpolation and CSV formula handling before this is used on untrusted channel lists or shared exports.

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

Error
Location
scripts/export_slack_threads.py:14
Finding

JavaScript Injection in Authenticated Slack Browser Context

Content
View full analysis
{ const channel = '__CHANNEL__'; const page = __PAGE__; const teamId = '__TEAM_ID__'; const userId = '__USER_ID__'; const after = '__AFTER__'; const before = '__BEFORE__'; ``` ```python def run_eval(target_id: str, channel: str, page: int, user_id: str, team_id: str, after: str | None, before: str | None) -> dict: fn = (JS_TEMPLATE .replace('__CHANNEL__', channel) .replace('__PAGE__', str(page)) .replace('__TEAM_ID__', team_id) .replace('__USER_ID__', user_id) .replace('__AFTER__', after or '') .replace('__BEFORE__', before or '')) cmd = [ 'openclaw', 'browser', '--browser-profile', 'chrome', '--timeout', '120000', 'evaluate', '--target-id', target_id, '--fn', fn, '--json' ] ``` ### Technical Analysis The channel name, Slack team ID, Slack user ID, and date arguments are inserted directly into JavaScript source code using string replacement. These values are placed inside single-quoted JavaScript literals without escaping quotes, backslashes, line terminators, or other JavaScript syntax. An input containing a single quote followed by JavaScript statements can terminate the intended literal and alter the function evaluated by Browser Relay. This is not shell injection—the subprocess command is correctly passed as an argument array—but it is code injection into the JavaScript evaluation layer. The injection is especially sensitive because the generated function executes inside an authenticated Slack browser tab. The page context can read Slack-origin local storage, including the `localConfig_v2` data used by the exporter, and can make requests using the active browser session. The retry workflow does not r ...[truncated 1880 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/export_slack_threads.py:43
Finding

CSV Formula Injection Through Exported Slack Content

Content
View full analysis
{ try { return new URL(permalink).searchParams.get('thread_ts') || ''; } catch(e) { return ''; } })(), username: item.username || '', text: text || '[non-text/attachment-only]', permalink, source_query_channel: channel, query, }); ``` ```python def write_csv(path: Path, rows: list[dict]) -> None: path.parent.mkdir(parents=True, exist_ok=True) with path.open('w', encoding='utf-8', newline='') as f: w = csv.DictWriter(f, fieldnames=FIELDS) w.writeheader() for row in sorted(rows, key=lambda x: (x.get('datetime_utc',''), x.get('channel_name',''), x.get('thread_ts',''))): w.writerow({k: row.get(k, '') for k in FIELDS}) ``` ### Technical Analysis Data obtained from Slack is written directly to CSV fields without neutralizing spreadsheet formulas. The Python CSV module correctly quotes and delimits CSV data, but CSV quoting does not prevent spreadsheet applications from interpreting a cell as a formula. Slack message text is controlled by workspace participants. Other exported fields, including usernames, channel names, permalinks, source channel names, and generated query values, may also contain or incorporate externally influenced content. A value beginning with a formula marker such as `=`, `+`, `-`, or `@` can be interpreted as a formula when the CSV is opened in compatible spreadsheet software. The vulnerability is triggered outside the Python process when an operator opens the generated file. Its behavior ther ...[truncated 1849 chars]
Remediation
View remediation
object: if not isinstance(value, str): return value candidate = value.lstrip(' \t\r\n') if candidate.startswith(FORMULA_PREFIXES): return "'" + value return value ``` Then apply it to all CSV fields: ```python w.writerow({ key: spreadsheet_safe(row.get(key, '')) for key in FIELDS }) ``` 4. Clearly document that the CSV is a presentation-oriented, formula-neutralized export. Preserve the JSONL file as the lossless raw representation. 5. If exact CSV text preservation is required, provide an explicit unsafe/raw CSV option with a prominent warning rather than making it the default. 6. Add tests covering all formula prefixes, leading whitespace, tabs, multiline values, usernames, channel names, query fields, and message text. 7. Advise users to import untrusted CSV files with formula execution disabled and to keep exported Slack archives in access-controlled locations. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill describes capabilities that can read browser session data, invoke network requests against Slack, write exported files, and run local scripts, but it declares no explicit tool scope or permissions boundary. That creates unnecessary ambient authority: an agent may execute broader file, shell, or network actions than the user expects, increasing the chance of over-collection or misuse of sensitive Slack session data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill is explicitly designed to export Slack conversations and save raw JSONL audit/debug files, yet the user-facing description and workflow do not prominently require a privacy warning or consent check before collecting potentially sensitive workplace communications. In context, this is more dangerous because the workflow reuses a live logged-in browser session and accesses internal Slack search data, which can include confidential employee or business information at scale.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The notes describe operational guidance for exporting Slack thread data at scale, including retry and resume patterns, but do not include an explicit privacy, authorization, or data-minimization warning near the collection workflow. In the context of a skill specifically designed to extract conversations from a logged-in Slack session, this omission increases the risk of over-collection or unauthorized export of sensitive employee communications.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script reads the Slack auth token from browser localStorage and uses it to issue authenticated requests against Slack's internal search API from a logged-in browser context. This enables bulk extraction of private workspace data using the user's session, expanding access and automation in a way that can bypass normal user awareness, consent, and administrative controls.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/export_slack_threads.py (reported line 99)May include surrounding context.

python
'openclaw', 'browser', '--browser-profile', 'chrome', '--timeout', '120000',
        'evaluate', '--target-id', target_id, '--fn', fn, '--json'
    ]
    r = subprocess.run(cmd, capture_output=True, text=True)
    if r.returncode != 0:
        raise RuntimeError(r.stderr.strip() or r.stdout.strip())
    outer = json.loads(r.stdout)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script performs bulk export of Slack thread content and writes it to local files without any built-in privacy warning, sensitivity check, or confirmation gate. In this skill's context, the data source is a logged-in Slack session, so silent collection and storage materially increase the chance of exporting confidential workplace communications without informed user consent.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill writes every matched row to JSONL before applying the heuristic work-like filter used for CSV output, so sensitive non-work or over-collected content is still retained on disk. Users may believe filtering limits collection, but the raw export preserves the full dataset and increases exposure if files are shared, reused, or compromised.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/retry_failed_channels.py (reported line 73)May include surrounding context.

python
return 0

    print(rendered)
    raise SystemExit(subprocess.run(cmd).returncode)


if __name__ == '__main__':

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The default keyword list includes Korean terms alongside English ones, which bakes a specific language/locale assumption into the skill's filtering behavior. The file does not explain this locale constraint or provide an explicit opt-in mechanism for Korean-language defaults.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.