Back to skill

Security audit

review-sendmsg

Security checks for vulnerabilities and agentic risk

Overview

This skill is a code-review helper, but it under-discloses that it sends repository diffs and review logs to external services and it does not actually review Python files despite advertising Python review.

Review carefully before installing. Only use this in repositories where sending source diffs to the configured LLM provider and sending review metadata or logs to Telegram is acceptable, and do not rely on it for Python review unless the target-file filtering is fixed.

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
scripts/review.py:125
Finding

Undisclosed transmission of repository source-code diffs to a configurable external endpoint

Content
View full analysis
Dict[str, Any]: api_key = os.getenv("LLM_API_KEY") api_url = os.getenv("LLM_API_URL", "https://api.deepseek.com/v1/chat/completions") model = os.getenv("LLM_MODEL", "deepseek-chat") if not api_key: return {"error": "LLM_API_KEY not set"} ``` ```python payload = { "model": model, "temperature": 0, "messages": [{"role": "user", "content": prompt}], } data = post_with_retry( api_url, headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}, payload=payload, timeout=180, ) ``` The prompt contains the reviewed Git diff, truncated to 120,000 characters: ```python Diff: {diff_text[:120000]} ``` The request helper sends that payload to the supplied URL: ```python r = requests.post(url, headers=headers, json=payload, timeout=timeout) ``` ### Technical Analysis The review operation reads changed source code from a Git repository and embeds it in an LLM prompt. The resulting payload is transmitted to `LLM_API_URL`, which is entirely controlled through an environment variable and is not restricted to an approved host or HTTPS scheme. External LLM processing may be necessary for the optional LLM review feature. However, the implementation exceeds a safe least-disclosure model because: - External transmission is enabled by the normal review workflow rather than by explicit per-run consent. - The active `SKILL.md` does not disclose that repository contents leave the local environment. - No secret scanning or redaction is applied before transmission. - No destination allowlist or certificate-policy hardening is im ...[truncated 1668 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/review_runner.py:48
Finding

Detailed review logs and repository metadata are uploaded to Telegram

Content
View full analysis
Remediation
View remediation

other

Warning
Location
scripts/review.py:12
Finding

The advertised Python review skill silently excludes Python files

Content
View full analysis
{to[:7]}\nno target files") return ``` The multi-project runner does the same: ```python files = get_changed_files(repo, last, new) if not files: state_file.write_text(new) return {**meta, "status": "skip", "reason": "no target files", "last": last, "new": new} ``` ### Technical Analysis Changed-file discovery is restricted to PHP, JavaScript, TypeScript, SQL, and shell files. Python files are never passed to local checks, hard rules, or the LLM. This directly contradicts the primary declared purpose of the Skill. The mismatch creates a security-control failure rather than merely a cosmetic naming problem. Users can reasonably believe that Python changes have undergone structured correctness and security review when the implementation has silently filtered them out. The multi-project runner also advances its state marker after a Python-only change is skipped. Consequently, the skipped commit will not be reconsidere ...[truncated 1062 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding

Third-party dependencies are installed from open-ended version ranges

Content
View full analysis
=2.31.0 python-dotenv>=1.0.1 ``` ### Technical Analysis The dependency declarations specify only minimum versions. Every future version satisfying those constraints can be selected during installation, including releases that were not present during this audit. No malicious, typosquatted, or untrusted package was identified in the current declarations. The risk arises from non-reproducible resolution: separate installations can execute different dependency code, and a future compromised or defective release could be installed automatically. Because these packages process environment configuration, HTTP requests, API credentials, source-code payloads, and Telegram uploads, compromise of either dependency could affect confidential repository data and network credentials. ### Attack Path 1. The Skill is installed without a lock file or constraints file. 2. The package resolver selects the newest versions satisfying the `>=` constraints. 3. A future dependency release is compromised, malicious, or contains a relevant vulnerability. 4. A later installation automatically retrieves that release. 5. The dependency executes in the review process and can access environment variables, source-code diffs, network payloads, and local files available to the process. This is a prospective supply-chain path; the audit found no evidence that the currently named packages are malicious. ### Impact Assessment The possible scope is limited by the privileges of the review process but may include: - Access to `LLM_API_KEY`, `TG_BOT_TOKEN`, and other environment variables. - Access to repository diffs and locally cloned repositories. - Modification or interception of outbound HTTP traffic. - Access to generated review logs and state directories. - Arbitra ...[truncated 229 chars]
Remediation
View remediation
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (42)

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · scripts/review.py (reported line 70)May include surrounding context.

python
"file": f, "message": p.stderr.strip()})
        elif ext == ".sql":
            if not Path(fp).exists() or Path(fp).stat().st_size == 0:
                issues.append({"tool": "sql-empty-check", "file": f, "message": "empty sql file"})
    return issues


def post_with_retry(url: str, headers: Dict[str, str], payload: Dict[str, Any], timeout: int = 180) -> Dict[str, Any]:
    max_retries = int(os.getenv("LLM_MAX_RETRIES", "3"))
    backoff = float(os.getenv("LLM_BACKOFF_SECONDS", "1.5"))

    last_err = None
    for i in range(max_retries + 1):
        try:
            r = requests.post(url, headers=headers, json=payload, timeout=timeout)
            # 重试条件:429/5xx
            if r.status_code in (429, 500, 502, 503, 504):
                last_err = f"http_{r.status_code}: {r.text[:500]}"
                if i < max_retries:
                    time.sleep(backoff * (2 ** i))
                    continue
            r.raise_for_status()
            return r.json()
        ex

Tainted flow: 'payload' from os.getenv (line 142, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/review.py (reported line 76)May include surrounding context.

python
last_err = None
    for i in range(max_retries + 1):
        try:
            r = requests.post(url, headers=headers, json=payload, timeout=timeout)
            # 重试条件:429/5xx
            if r.status_code in (429, 500, 502, 503, 504):
                last_err = f"http_{r.status_code}: {r.text[:500]}"

Tainted flow: 'token' from os.getenv (line 200, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/review.py (reported line 206)May include surrounding context.

python
return

    try:
        requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": chat_id, "text": message[:3900]},
            timeout=15,

YARA rule 'agent_skill_credential_exfiltration_webhook': AI agent skill credential harvesting followed by webhook or external exfiltration [agent_skills]

Critical
Category
YARA Match
Confidence
96% confidence
Finding

The combination of bulk environment-variable loading, external HTTP requests, Telegram messaging, and LLM diff upload strongly matches a credential-harvesting/exfiltration pattern. Even if framed as automation, this skill has the technical capability to access secrets and transmit sensitive repository data off-host, which is especially dangerous in an agent skill context.

Content

Scanner excerpt · scripts/review_runner.py (reported line 22)May include surrounding context.

python
ml
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Any

import requests
from dotenv import load_dotenv

# 自动加载项目根目录 .env(无需每次手动 source)
load_dotenv(Path(__file__).resolve().parents[1] / ".env")

TARGET_EXT = {".php", ".js", ".ts", ".sql", ".sh"}
EXCLUDE_PREFIX = ("vendor/", "node_modules/", "dist/", "build/")

BASE_DIR = Path(os.getenv("REVIEW_BASE_DIR", "/home/skill/py-review/.state"))
STATE_DIR = BASE_DIR / "state"
WORK_DIR = BASE_DIR / "repos"
LOCK_DIR = BASE_DIR / "lock"

LLM_API_KEY = os.getenv("LLM_API_KEY", "")
LLM_API_URL = os.getenv("LLM_API_URL", "https://api.deepseek.com/v1/chat/completions")
LLM_MODEL = os.getenv("LLM_MODEL", "deepseek-chat")
BATCH_SIZE = int(os.getenv("DIFF_BATCH_SIZE", "8"))
MAX_DIFF_CHARS = int(os.getenv("MAX_DIFF_CHARS", "120000"))
REVIEW_MODE = os.getenv("REVIEW_MODE", "full").strip().lower()  # full|local|llm

TG_BOT_TOKEN = os.getenv("TG_BOT_TOKEN", "")
TG_CHAT_ID = os.getenv("TG

Tainted flow: 'TG_BOT_TOKEN' from os.getenv (line 34, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

This path uploads a log file to Telegram, and the log contains project name, branch, author, commit subject, and full JSON review results. That creates a clear exfiltration channel for potentially sensitive repository metadata and security review details to an external messaging platform.

Content

Scanner excerpt · scripts/review_runner.py (reported line 58)May include surrounding context.

python
# 单条消息发送:有日志文件时,走 sendDocument + caption;否则 sendMessage
        if log_file and Path(log_file).exists():
            with open(log_file, "rb") as f:
                r = requests.post(
                    f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendDocument",
                    data={
                        "chat_id": TG_CHAT_ID,

Tainted flow: 'TG_BOT_TOKEN' from os.getenv (line 34, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The fallback sendMessage call still transmits repository review information to Telegram when document upload fails. This preserves the external exfiltration behavior even during error handling, making accidental or unauthorized disclosure more likely.

Content

Scanner excerpt · scripts/review_runner.py (reported line 70)May include surrounding context.

python
)
            if r.status_code != 200:
                # 降级:至少发一条纯文本,避免“无通知”
                requests.post(
                    f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage",
                    json={"chat_id": TG_CHAT_ID, "text": msg[:3900], "disable_web_page_preview": True},
                    timeout=15,

Tainted flow: 'TG_BOT_TOKEN' from os.getenv (line 34, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
97% confidence
Finding

The code transmits review results and repository metadata to Telegram using credentials loaded from environment variables. Even though the token itself is not sent as message content, this is still external data exfiltration because commit author, subject, status, and possibly detailed findings are sent to a third-party service outside the reviewed repositories' trust boundary.

Content

Scanner excerpt · scripts/review_runner.py (reported line 76)May include surrounding context.

python
timeout=15,
                )
        else:
            requests.post(
                f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage",
                json={
                    "chat_id": TG_CHAT_ID,

Tainted flow: 'TG_BOT_TOKEN' from os.getenv (line 34, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
95% confidence
Finding

The final exception fallback silently sends plaintext status data to Telegram, again exporting potentially sensitive information outside the environment. Silent error-handling paths are especially risky because operators may not realize data is still leaving the system under failure conditions.

Content

Scanner excerpt · scripts/review_runner.py (reported line 89)May include surrounding context.

python
except Exception:
        # 最后兜底(纯文本)
        try:
            requests.post(
                f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage",
                json={"chat_id": TG_CHAT_ID, "text": msg[:3900], "disable_web_page_preview": True},
                timeout=15,

Tainted flow: 'LLM_API_URL' from os.getenv (line 28, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
99% confidence
Finding

The script sends repository diffs to an externally configured LLM API, which can expose proprietary source code, secrets embedded in diffs, and security findings to a third party. Because the endpoint is configurable via environment variable, a malicious or misconfigured deployment could redirect full code diffs and the bearer token to an attacker-controlled service.

Content

Scanner excerpt · scripts/review_runner.py (reported line 290)May include surrounding context.

python
retries = int(os.getenv("LLM_MAX_RETRIES", "3"))
    for i in range(retries + 1):
        try:
            r = requests.post(
                LLM_API_URL,
                headers={"Authorization": f"Bearer {LLM_API_KEY}", "Content-Type": "application/json"},
                json=payload,

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

Automatically loading a project-level .env gives this skill access to secrets that may belong to the surrounding project rather than the review tool itself. In combination with later outbound network requests, this broad secret access meaningfully increases the chance of credential misuse or unintended disclosure.

Content

Scanner excerpt · scripts/review_runner.py (reported line 17)May include surrounding context.

python
from dotenv import load_dotenv

# 自动加载项目根目录 .env(无需每次手动 source)
load_dotenv(Path(__file__).resolve().parents[1] / ".env")

TARGET_EXT = {".php", ".js", ".ts", ".sql", ".sh"}
EXCLUDE_PREFIX = ("vendor/", "node_modules/", "dist/", "build/")

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The notification subsystem sends logs and status messages to Telegram, including repository metadata and detailed review outputs. This creates an external dissemination path for sensitive operational and code-review information without strong justification or visible safeguards.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The review function packages raw git diff content into a prompt and sends it to an external LLM service. In this context, that can leak source code, credentials present in code changes, and internal development details, making it significantly more dangerous than a generic network call.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · .env (reported line 2)May include surrounding context.

text
LLM_API_KEY=your_key_here
LLM_API_URL=https://api.deepseek.com/v1/chat/completions
LLM_MODEL=deepseek-chat

DIFF_BATCH_SIZE=8

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/review.py (reported line 16)May include surrounding context.

python
def run(cmd: List[str], cwd: str = None) -> subprocess.CompletedProcess:
    return subprocess.run(cmd, cwd=cwd, text=True, capture_output=True)


def changed_files(repo: str, frm: str, to: str) -> List[str]:

External Transmission

Medium
Category
Data Exfiltration
Confidence
96% confidence
Finding

This request sends code-review payloads, including diff content, to an external endpoint controlled by configuration. Because the endpoint is environment-configurable and the prompt includes up to 120000 characters of diff data, the skill can disclose sensitive source changes to third parties or to a maliciously substituted API URL.

Content

Scanner excerpt · scripts/review.py (reported line 76)May include surrounding context.

python
last_err = None
    for i in range(max_retries + 1):
        try:
            r = requests.post(url, headers=headers, json=payload, timeout=timeout)
            # 重试条件:429/5xx
            if r.status_code in (429, 500, 502, 503, 504):
                last_err = f"http_{r.status_code}: {r.text[:500]}"

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The embedded prompt instructs the model in Chinese and constrains output fields such as risk levels to Chinese values only, imposing a specific language/locale. There is no opt-in, configuration, or documented reason showing that this locale restriction is intentional and acceptable.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code transmits git diff content to an external LLM API without any consent, warning, or filtering. Diffs can contain secrets, proprietary source code, credentials, or security-sensitive changes, so sending them off-host materially increases confidentiality and supply-chain risk.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The skill sends review outcomes to Telegram, an external third-party service unrelated to core local diff analysis. Even though only summary text is sent here, this creates an undisclosed outbound channel that can leak repository activity, commit identifiers, and review decisions to external infrastructure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script posts review results to Telegram without any user-facing disclosure. Even abbreviated notifications reveal commit references, file-change activity, and pass/fail status to an external service, which may be sensitive in private development environments.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This is an outbound network transmission to Telegram carrying repository review metadata. While not as severe as sending full diffs, it still leaks internal development activity to an external service and creates an additional covert communications channel in the skill.

Content

Scanner excerpt · scripts/review.py (reported line 206)May include surrounding context.

python
return

    try:
        requests.post(
            f"https://api.telegram.org/bot{token}/sendMessage",
            json={"chat_id": chat_id, "text": message[:3900]},
            timeout=15,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script automatically loads a project-level .env and then uses resulting secrets for external services, including an LLM API and Telegram. In an agent-skill context, auto-harvesting secrets from nearby project files materially increases the risk that credentials are consumed and used without clear user awareness or scope limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The file contains hardcoded Chinese-language comments, prompts, and notification text, including the LLM review prompt and all user-visible status messages. This enforces a specific locale without offering the user a language choice or documenting a justified region-specific constraint.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · references/SKILL.original.md (reported line 19)May include surrounding context.

md
LOCK_DIR = BASE_DIR / "lock"

LLM_API_KEY = os.getenv("LLM_API_KEY", "")
LLM_API_URL = os.getenv("LLM_API_URL", "https://api.deepseek.com/v1/chat/completions")
LLM_MODEL = os.getenv("LLM_MODEL", "deepseek-chat")
BATCH_SIZE = int(os.getenv("DIFF_BATCH_SIZE", "8"))
MAX_DIFF_CHARS = int(os.getenv("MAX_DIFF_CHARS", "120000"))

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/review.py (reported line 124)May include surrounding context.

python
LOCK_DIR = BASE_DIR / "lock"

LLM_API_KEY = os.getenv("LLM_API_KEY", "")
LLM_API_URL = os.getenv("LLM_API_URL", "https://api.deepseek.com/v1/chat/completions")
LLM_MODEL = os.getenv("LLM_MODEL", "deepseek-chat")
BATCH_SIZE = int(os.getenv("DIFF_BATCH_SIZE", "8"))
MAX_DIFF_CHARS = int(os.getenv("MAX_DIFF_CHARS", "120000"))

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/review_runner.py (reported line 28)May include surrounding context.

python
LOCK_DIR = BASE_DIR / "lock"

LLM_API_KEY = os.getenv("LLM_API_KEY", "")
LLM_API_URL = os.getenv("LLM_API_URL", "https://api.deepseek.com/v1/chat/completions")
LLM_MODEL = os.getenv("LLM_MODEL", "deepseek-chat")
BATCH_SIZE = int(os.getenv("DIFF_BATCH_SIZE", "8"))
MAX_DIFF_CHARS = int(os.getenv("MAX_DIFF_CHARS", "120000"))

Static analysis

No suspicious patterns detected.