Back to skill

Security audit

skill-h-meeting-sync

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated meeting-sync purpose, but it handles a powerful Gitea token and repository meeting data with insecure defaults and broad automated write/delete authority.

Review before installing. Use only an HTTPS Gitea endpoint, create a dedicated low-privilege bot token limited to the required repositories, avoid running setup against untrusted .env content, and consider replacing the installer with a pinned virtualenv-based setup. Operators should also understand that the cron workflow may automatically change meeting statuses, create pending records, append logs, and archive-delete old meeting files in Gitea.

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
env-example.txt:2
Finding
Gitea Access Token and Meeting Data Transmitted over Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `env-example.txt:2`; `scripts/gitea_utils.py:9-15`; `scripts/log_utils.py:14-24` **Vulnerability Type**: Cleartext transmission of credentials and sensitive data **Risk Level**: High ### Vulnerable Code ```text # env-example.txt:1-3 # Gitea GITEA_BASE_URL=http://43.156.243.152:3000 GITEA_TOKEN_BOT=your_aifusionbot_access_token_here ``` ```python # scripts/gitea_utils.py:9-17 def gitea_request(method, path, token, base_url, raise_on_error=True, **kwargs): url = f"{base_url.rstrip('/')}/api/v1{path}" headers = { "Authorization": f"token {token}", "Content-Type": "application/json", } resp = requests.request(method, url, headers=headers, timeout=15, **kwargs) if raise_on_error: resp.raise_for_status() return resp ``` ```python # scripts/log_utils.py:14-24 api_url = f"{base_url.rstrip('/')}/api/v1/repos/{owner}/{repo_name}/contents/{filepath}" headers = { "Authorization": f"token {token}", "Content-Type": "application/json", } existing_content = "" existing_sha = None resp = requests.get(api_url, headers=headers, timeout=10) ``` ### Technical Analysis The distributed example configures Gitea through a raw IP address using plain HTTP. The request helpers then place the bot's bearer token in the `Authorization` header and transmit it to that URL without enforcing TLS. The same connection carries meeting metadata, participant information, repository content, and repository modifications. Base64 encoding used by the Gitea contents API is only a transport representation and provides no confidentiality or integrity. An attacker capable of observing or modifying traffic between the Skill host and Gitea can capture the reusable access token. An active network attacker can also tamper with API responses, causing the Skill to process falsified repository state. ### Attack Path 1. An operator copies `env-example.txt` to the documented `.env` location without ...[truncated 1166 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the example URL with an HTTPS endpoint using a trusted DNS name. 2. Reject insecure URLs in code before making requests: ```python from urllib.parse import urlparse parsed = urlparse(base_url) if parsed.scheme != "https": raise ValueError("GITEA_BASE_URL must use HTTPS") ``` 3. Do not disable TLS certificate validation. Use a private certificate authority bundle if the Gitea service uses an internal CA. 4. Rotate any token that may already have been transmitted over HTTP. 5. Create a dedicated, narrowly scoped bot token limited to the repositories and content operations required by this Skill. 6. Where Gitea supports it, apply source-IP restrictions, expiration, and repository-specific permissions. 7. Avoid placing a production-looking public IP in the distributed configuration example. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
setup.sh:31
Finding
Arbitrary Shell Command Execution through Sourced Environment Configuration<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh:31` **Vulnerability Type**: Shell command injection through executable configuration **Risk Level**: Medium ### Vulnerable Code ```bash # setup.sh:31 set -a; source "$ENV_FILE"; set +a ``` The file being sourced is defined and created as follows: ```bash # setup.sh:5-6 CONFIG_DIR="$HOME/.config/skill-h-meeting-sync" ENV_FILE="$CONFIG_DIR/.env" ``` ```bash # setup.sh:16-18 if [ ! -f "$ENV_FILE" ]; then cp "$SKILL_DIR/env-example.txt" "$ENV_FILE" chmod 600 "$ENV_FILE" ``` ### Technical Analysis The script uses Bash `source` to load a file described as an environment configuration file. `source` does not parse the file as passive `KEY=VALUE` data; it executes the entire file as shell code in the current process. File mode `600` reduces access by other local users but does not make the file contents safe. Commands, command substitutions, function definitions, redirections, and arbitrary shell statements placed in `.env` are executed when setup is rerun. For example, a value such as the following is executable rather than passive configuration: ```bash GITEA_BASE_URL="$(attacker_controlled_command)" ``` This risk can be exploited if an attacker or compromised provisioning process can modify the `.env` file, or if a user pastes untrusted configuration content into it. ### Attack Path 1. An attacker, compromised installer, malicious support instruction, or unsafe configuration template places shell syntax in `~/.config/skill-h-meeting-sync/.env`. 2. The user reruns `bash setup.sh` to validate or update the installation. 3. Bash reaches `source "$ENV_FILE"`. 4. The malicious statements execute immediately in the setup process. 5. The injected code inherits the installing user's filesystem, network, and process privileges. ### Impact Assessment Successful exploitation provides arbitrary command execution as the account running `setup.sh`. This can permit: - Reading or changing files a ...[truncated 474 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not use `source`, `.`, or `eval` to load `.env` files. 2. Parse the file with a non-executing dotenv parser or a small validation utility. 3. Accept only an explicit allowlist: - `GITEA_BASE_URL` - `GITEA_TOKEN_BOT` - `AIFUSION_META_REPO` - `ADVISOR_GITEA_USERNAME` 4. Reject malformed lines, duplicate keys, shell metacharacters where inappropriate, and unknown variables. 5. Perform setup validation in Python using `python-dotenv`, which is already a declared dependency: ```python from dotenv import dotenv_values values = dotenv_values(env_path) required = { "GITEA_BASE_URL", "GITEA_TOKEN_BOT", "AIFUSION_META_REPO", "ADVISOR_GITEA_USERNAME", } missing = [key for key in required if not values.get(key)] ``` 6. Retain restrictive file permissions and verify that the config file is a regular file rather than a symbolic link before reading it. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding
Unpinned Dependencies Installed into the System Python Environment<![CDATA[ ## Vulnerability Details **File Location**: `setup.sh:13`; `requirements.txt:1-5` **Vulnerability Type**: Unsafe dependency installation and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```bash # setup.sh:12-14 echo "📦 安装 Python 依赖..." pip install -r "$SKILL_DIR/requirements.txt" --break-system-packages -q echo "✅ Python 依赖安装完成" ``` ```text # requirements.txt:1-5 requests>=2.28.0 python-dotenv>=1.0.0 PyYAML>=6.0 pytz>=2023.3 python-dateutil>=2.8.2 ``` ### Technical Analysis Every dependency is specified with an open-ended lower bound. Consequently, installation can select any future release satisfying the constraint, along with unpinned transitive dependencies. There is no lock file, hash verification, or reviewed dependency snapshot. The use of `--break-system-packages` explicitly bypasses protections intended to prevent `pip` from modifying an externally managed Python installation. This can overwrite or conflict with packages used by unrelated system applications. Although the listed package names are legitimate and no typosquatted package was identified, the installation method creates avoidable supply-chain and system-integrity risk. ### Attack Path 1. A dependency account, release pipeline, package index, or transitive dependency is compromised, or a future incompatible version is published. 2. A user runs `setup.sh`. 3. `pip` resolves the newest versions satisfying the broad `>=` constraints. 4. The selected package is installed into the system Python environment without hash verification. 5. Malicious installation hooks or imported package code execute, or incompatible files disrupt other Python applications. ### Impact Assessment The selected package code runs with the privileges of the account invoking setup. Potential effects include: - Theft of the Gitea token and other readable credentials. - Modification of Skill behavior. - Arbitrary network communication or local code execution. - Corruption of unrelated ...[truncated 337 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create and use a dedicated virtual environment instead of modifying system Python. 2. Remove `--break-system-packages`. 3. Pin exact, reviewed direct and transitive dependency versions. 4. Generate a hash-locked requirements file, for example with `pip-tools`. 5. Install with hash enforcement: ```bash python3 -m venv "$SKILL_DIR/.venv" "$SKILL_DIR/.venv/bin/pip" install --require-hashes -r requirements.lock ``` 6. Invoke scripts using the virtual environment's Python interpreter. 7. Add automated dependency vulnerability scanning and a controlled update process. 8. Review package provenance and release changes before updating the lock file. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/email_utils.py:38
Finding
Unescaped Meeting Data Allows HTML Injection in Notification Emails<![CDATA[ ## Vulnerability Details **File Location**: `scripts/email_utils.py:38-48`, `scripts/email_utils.py:59-79`, `scripts/email_utils.py:107-143`, `scripts/email_utils.py:168-198` **Vulnerability Type**: HTML and link-attribute injection **Risk Level**: Medium ### Vulnerable Code Cancellation reasons and meeting topics are inserted directly into markup: ```python # scripts/email_utils.py:38-48 def build_cancel_html(topic, scheduled_time, meeting_code, repo, organizer, reason=""): time_str = _format_time(scheduled_time) reason_row = ( f'<tr><td style="padding:10px 14px;background:#f8f9fa;font-weight:bold;' f'width:110px;border:1px solid #e0e0e0;">取消原因</td>' f'<td style="padding:10px 14px;border:1px solid #e0e0e0;">{reason}</td></tr>' ) if reason else "" return f"""<!DOCTYPE html> ``` ```html <!-- scripts/email_utils.py:59-79 --> <td style="padding:10px 14px;border:1px solid #e0e0e0;">{topic}</td> ... <td style="padding:10px 14px;border:1px solid #e0e0e0;font-family:monospace;font-size:15px;letter-spacing:2px;">{meeting_code}</td> ... <td style="padding:10px 14px;border:1px solid #e0e0e0;">{repo}</td> ... <td style="padding:10px 14px;border:1px solid #e0e0e0;">{organizer}</td> ``` Rescheduling URLs and metadata are also inserted without escaping or URL validation: ```html <!-- scripts/email_utils.py:107-143 --> <td style="padding:10px 14px;border:1px solid #e0e0e0;">{topic}</td> ... <a href="{new_join_url}" style="background:#1a73e8;color:white;padding:11px 22px; text-decoration:none;border-radius:5px;display:inline-block;font-size:14px;margin-right:10px;"> 🎥 加入新腾讯会议 </a> ``` Pending-meeting content has the same issue: ```html <!-- scripts/email_utils.py:168-198 --> <td style="padding:10px 14px;border:1px solid #e0e0e0;">{topic}</td> ... <td style="padding:10px 14px;border:1px solid #e0e0e0;font-family:monospace;">{meeting_id}</td> ... <a href="{join_url}" style="background:#7b1fa2;color:white;padding:11p ...[truncated 2368 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Escape every value placed into HTML text or attributes: ```python from html import escape safe_topic = escape(str(topic), quote=True) safe_reason = escape(str(reason), quote=True) safe_organizer = escape(str(organizer), quote=True) safe_meeting_code = escape(str(meeting_code), quote=True) ``` 2. Validate URLs before inserting them into email markup: - Require `https`. - Restrict meeting links to approved Tencent Meeting domains. - Restrict agenda links to the configured Gitea hostname. - Reject embedded credentials, control characters, and malformed hostnames. 3. Construct HTML using a template engine with automatic escaping enabled rather than f-string concatenation. 4. Treat repository metadata, CLI arguments, and upstream Skill output as untrusted input. 5. Consider generating a plain-text alternative for every email. 6. Add tests covering quotes, angle brackets, event-handler attributes, `javascript:` URLs, deceptive hostnames, and markup injected into topics or reasons. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (52)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
Writing logs and updating repository contents via authenticated API without declared permissions creates a transparency and least-privilege problem. If operators or the runtime treat the skill as lower risk than it is, the skill could be granted access that permits silent content modification or log poisoning in source-control-backed repositories.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The manifest limits this skill to synchronizing existing meeting status across Tencent Meeting and Gitea, explicitly stating it does not handle meeting creation. However, the documented and implemented `create-pending` command creates a new placeholder record in `aifusion-meta`, which is a meeting-creation-related capability outside the stated scope.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The manifest limits skill-h to synchronizing existing Tencent meeting status with Gitea repos and explicitly says it does not handle meeting creation. This script's documented purpose and implementation create a new placeholder record in the meta repository for previously unlinked meetings, which is a creation workflow rather than status sync, cancellation, reschedule, addition sync, or archival.

Description-Behavior Mismatch

High
Confidence
94% confidence
Finding
The code builds a fresh meta.yaml with meeting details and writes it to a new meetings directory in aifusion-meta. The manifest describes a background task for keeping existing meeting states consistent across Tencent Meeting and Gitea, plus archiving expired directories, but not creating new repository metadata entries for unknown meetings.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
CONFIG_DIR="$HOME/.config/skill-h-meeting-sync"
ENV_FILE="$CONFIG_DIR/.env"

echo "🚀 设置 Skill-H (meeting_sync)..."
echo ""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill declares shell, environment, and network-driven behavior but does not specify any explicit tool or permission boundaries in the manifest. In an agent platform, missing scope declarations can cause the runtime or operator to grant broader access than necessary, increasing the blast radius if the skill is misused or compromised.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The manifest description is written entirely in Chinese and presents the skill behavior as fixed, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking or region-specific context. Under the policy, forcing a specific language or locale without opt-in is a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The user-facing command descriptions and operational notes in the header comment are written entirely in Chinese, with no indication that other languages are supported. This is a natural-language policy concern because it imposes a specific language without documented user choice or justification.

Intent-Code Divergence

Medium
Confidence
82% confidence
Finding
The top-level comment describes OpenClaw performing scan, Tencent meeting fetch, comparison, and then invoking the corresponding commands for cancellation/reschedule/archive-style sync outcomes. Yet the module also documents and dispatches a `create-pending` command, which is not part of that described sync flow and contradicts the stated operational intent of the module documentation.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
This code includes natural-language instructions and user-facing messages entirely in Chinese, and later emits Chinese status/error strings, but provides no user opt-in or documented locale constraint. Under the policy, forcing a specific language without user choice is a natural-language policy violation unless clearly justified as region-specific.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
main.js:26