Back to skill

Security audit

Sentiment Analysis Compass

Security checks for vulnerabilities and agentic risk

Overview

The skill largely matches its stated monitoring purpose, but it needs Review because it stores credentials insecurely and can send monitored content, alerts, and subscription tokens to external services with weak disclosure and controls.

Review this skill before installing. Use it only in an isolated environment, avoid putting real API keys or SMTP passwords on command lines, restrict and protect ~/.sentiment-compass, configure only trusted alert endpoints, and assume monitored posts, keywords, summaries, and credentials may be sent to external providers when GLM-4, Feishu, email, or subscription verification are enabled.

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/sentiment.py:1694
Finding

Credentials are exposed through command-line arguments, plaintext configuration, process arguments, and command output

Content
View full analysis
dict: if CONFIG_PATH.exists(): try: return json.loads(CONFIG_PATH.read_text(encoding="utf-8")) except Exception: pass return {"tier": "FREE", "glm_api_key": "", "feishu_webhook": "", "smtp_config": {}} def save_config(cfg: dict): CONFIG_PATH.write_text( json.dumps(cfg, ensure_ascii=False, indent=2), encoding="utf-8", ) ``` The API key is also passed to an external process as a command-line argument: ```python result = subprocess.run( ["curl", "-s", "-X", "POST", GLM_API_URL, "-H", f"Authorization: Bearer {api_key}", "-H", "Content-Type: application/json", "-d", json.dumps(payload, ensure_ascii=False)], capture_output=True, text=True, timeout=30 ) ``` The CLI exposes arbitrary configuration values, including secrets: ```python elif cmd == "config-get": key = sys.argv[2] if len(sys.argv) > 2 else "" val = get_config(key) print(json.dumps({"ok": True, "key": key, "value": val}, ensure_ascii=False)) elif cmd == "config-set": # python3 sentiment.py config-set key = sys.argv[2] if len(sys.argv) > 2 else "" value = sys.argv[3] if len(sys.argv) > 3 else "" # Try to parse JSON try: value = json.loads(value) except Exception: pass set_config(key, value) print(json.dumps({"ok": True, "key": key, "value": value}, ensure_ascii=False)) ``` The documented setup also places secrets directly in shell command arguments: ```bash python3 scripts/sentiment.py config-set glm_api_key "your_key" python3 scripts/sentiment.py config-set feishu_webhook "https://open.feishu.cn/..." python3 scripts/sentiment.py config-se ...[truncated 2112 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sentiment.py:297
Finding

Paid-tier verification transmits the complete subscription token without adequate privacy disclosure

Content
View full analysis
dict: """ Verify API key via 91Skillhub API. Returns dict with keys: valid (bool), tier (str), error (str, if failed). On network error, degrades to FREE tier gracefully. """ if not api_key: return {"valid": False, "tier": "FREE", "error": "No API key provided"} # 快速判断:不在已知前缀列表 = 外部 key,跳过验证 prefix = api_key.split("-")[0].upper() if "-" in api_key else api_key[:4].upper() if prefix not in VALID_PREFIXES: return {"valid": False, "tier": "FREE", "error": "Not a 91Skillhub key"} cached = _get_cached(api_key) if cached: return cached try: req = urllib.request.Request( VERIFY_URL, method="POST", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", }, data=b"{}", ) with urllib.request.urlopen(req, timeout=10) as resp: data = json.loads(resp.read().decode("utf-8")) ``` Verification is automatically performed when a token is supplied to the constructor: ```python class SentimentCompass: def __init__(self, tier: str = "FREE", api_key: str = ""): # Verify token if api_key provided; degrade to FREE on failure if api_key: result = verify_token(api_key) if result["valid"]: self.tier = result["tier"] else: self.tier = "FREE" ``` The self-review makes a conflicting locality claim: ```text | Sensitive data does not leak | All data is stored locally in `~/.sentiment-compass/` ...[truncated 1873 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sentiment.py:1383
Finding

Unrestricted Feishu webhook URL permits monitoring-data exfiltration and server-side requests to unintended destinations

Content
View full analysis
50 else post[0] body["card"]["elements"].append({ "tag": "div", "text": {"tag": "lark_md", "content": f"• [{platform_emoji.get(post[1], '📌')}] {title}\n — {post[2]} | 👍{post[4]} | {post[5]}"} }) ``` The configured URL is then used directly: ```python try: result = subprocess.run( ["curl", "-s", "-X", "POST", webhook, "-H", "Content-Type: application/json", "-d", json.dumps(body, ensure_ascii=False)], capture_output=True, text=True, timeout=10 ) resp = json.loads(result.stdout) if resp.get("code") == 0 or resp.get("StatusCode") == 0: # Mark as sent self.conn.execute( "UPDATE alerts SET notification_sent=1 WHERE keyword=? AND triggered_at=?", (alert["keyword"], alert["triggered_at"]) ) ``` ### Technical Analysis The webhook configuration is not validated as a genuine Feishu endpoint. The code does not enforce: - An HTTPS scheme. - An allowlisted Feishu hostname. - A permitted port. - Rejection of loopback, link-local, private, or reserved IP addresses. - DNS resolution checks. - Redirect restrictions. Consequently, anyone who can modify `config.json` or invoke `config-set feishu_webhook` can cause the Skill to issue a POST request to an arbitrary URL. The POST body c ...[truncated 1839 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Open-ended dependency versions make installation non-reproducible and increase supply-chain exposure

Content
View full analysis
=1.40.0 beautifulsoup4>=4.12.0 jieba>=0.42.1 requests>=2.31.0 ``` The README directs users to install whatever versions currently satisfy those ranges: ```bash pip install -r requirements.txt playwright install chromium ``` ### Technical Analysis Each Python dependency specifies only a minimum version and has no upper bound, exact pin, lock file, or package hash. As a result, two installations performed at different times may obtain different code even though the audited project is unchanged. The separate `playwright install chromium` operation also downloads a browser artifact selected by the resolved Playwright version. Without a locked Playwright version and artifact-integrity policy, the effective installed component set is not reproducible from the audited repository alone. No dependency name in the file is an obvious typo or dependency-confusion target, and the audit found no evidence that the currently named packages are malicious. The issue is the absence of controls against future compromised, unexpectedly incompatible, or malicious releases. ### Attack Path 1. A user follows the README and runs `pip install -r requirements.txt`. 2. The package resolver selects the newest available versions satisfying the `>=` constraints. 3. A future release or compromised package version contains malicious installation or runtime behavior. 4. Package code executes during installation, import, browser setup, or normal Skill operation. 5. The malicious dependency inherits the filesystem, environment, network, and process privileges of the user running the installation or Skill. ### Impact Assessment A compromised dependency could act with the pri ...[truncated 585 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • 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 (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill description claims extensive scraping, sentiment analysis, reporting, and alerting capabilities, but the provided artifact appears to be documentation and placeholders rather than a verifiable implementation. This mismatch is dangerous because reviewers and users may approve or trust a skill based on declared behavior while hidden or later-supplied code could perform materially different actions, including data collection or exfiltration outside the stated purpose.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 174)May include surrounding context.

md
See `scripts/sentiment.py` for full implementation:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The markdown advertises Feishu/email push alerts and later shows configuration of webhook and SMTP credentials, but it does not warn users that monitored content and report data may be transmitted to third-party services. For markdown files, missing warnings about behaviors affecting privacy or system/data handling should be flagged when the description omits them.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README instructs users to set API keys, webhooks, and SMTP credentials directly via command examples without any warning about secure storage, shell history exposure, config file protection, or least-privilege handling. In a tool that monitors social media and sends outbound alerts, exposed secrets could let an attacker abuse email infrastructure, bot webhooks, or external AI APIs, and may also enable unauthorized data transmission.

Content

No source excerpt is available for this finding.

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 · SELF_REVIEW.md (reported line 7)May include surrounding context.

md
| 文件 | 说明 |
|------|------|
| `skills/sentiment-compass/SKILL.md` | Skill 定义文档 |
| `skills/sentiment-compass/scripts/sentiment.py` | 核心引擎(约 720 行) |
| `skills/sentiment-compass/scripts/tests/test_sentiment.py` | 测试套件(34 个测试用例) |
| `skills/sentiment-compass/requirements.txt` | Python 依赖 |

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The self-review claims sensitive data does not leave the local machine because all data is stored locally, but the same document also describes sending alerts to Feishu/email and using external GLM-4 APIs. This mismatch can cause operators to underestimate data egress risk, leading to accidental transmission of monitored content, keywords, or sentiment results to third-party services without proper disclosure or controls.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
82% confidence
Finding

The skill advertises behaviors that require network access, local storage, scheduling, and likely shell/file operations, yet it declares no explicit tool scope or permissions. This creates an authorization ambiguity where a host may grant broader capabilities than users expect, increasing the chance of over-privileged execution and unintended data access or outbound activity.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest description lists generic triggers such as "sentiment" and "sentiment analysis," which are broad natural-language phrases that could match ordinary conversation outside the intended skill context. The file does not provide narrowing constraints or exclusion examples to clarify when the skill should or should not activate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill states that scraped post bodies and comments are sent to the GLM-4 API for sentiment analysis, but it does not clearly warn users that third-party content will be transmitted to an external AI provider. This creates a data handling and privacy risk, especially when monitored content may include personal data, sensitive business mentions, or regulated information.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
80% confidence
Finding

The skill describes creating persistent monitoring tasks and future cron-triggered crawls from a single user request, indicating actions continue beyond the immediate session. Persistent background execution can surprise users, repeatedly collect data, and continue using stored credentials, webhooks, or configuration without clear confirmation, review, or revocation controls.

Content

Scanner excerpt · SKILL.md (reported line 152)May include surrounding context.

User: Monitor "coffee brand" on Xiaohongshu and Douyin, crawl every day at 9am

text

→ Create task → Return confirmation → Next Cron trigger executes first crawl

### Example 2: Competitor Negative Alert

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

Natural-language strings and runtime behavior force Chinese operation, including zh-CN browser locale headers and prompts instructing the model to respond only in Chinese. This is a language/locale constraint applied by default without presenting the user a choice or clearly documenting an opt-in mechanism.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest describes a social media monitoring and sentiment analysis tool, where network access and local storage are expected. However, importing and later using subprocess to invoke external programs like Node.js/Playwright and curl introduces a general process-spawning capability that is not justified by the stated product purpose itself.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script persistently stores scraped posts, analyses, alerts, logs, and configuration under the user's home directory, including potentially sensitive monitored content and service credentials. Without clear warning, retention controls, or credential protection, this can expose private data locally to other processes, backups, or compromised accounts.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

The hard-coded external verification endpoint sends bearer tokens off-host to a third-party service, creating a clear external transmission path for credentials. If users do not expect this or if the endpoint is compromised, API keys and associated metadata could be exposed or abused.

Content

Scanner excerpt · scripts/sentiment.py (reported line 238)May include surrounding context.

python
# ─── 91Skillhub Token Verification ───────────────────────────────────────────
VERIFY_URL = "https://api.yk-global.com/v1/verify"  # Fixed

VALID_PREFIXES = {
    "GEO", "PROFIT", "INV", "DATA", "MON",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code sends API keys and potentially user-provided texts or scraped post content to third-party services (api.yk-global.com and GLM) without any evident consent, warning, minimization, or policy gate in the implementation. For a sentiment-monitoring tool handling social content, this creates a real privacy and data-governance risk, especially if monitored keywords or content are sensitive.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest says the skill monitors specified Chinese social media platforms for mentions and analyzes sentiment, but this implementation adds a browser automation layer that spawns an external runtime and simulates anti-detection behavior. That capability is materially different from straightforward monitoring and is not explicitly justified in the declared scope.

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

python
"""

    try:
        result = subprocess.run(
            ["node", "-e", script],
            capture_output=True, text=True, timeout=45
        )

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

python
"temperature": 0.3,
            "max_tokens": 256,
        }
        result = subprocess.run(
            ["curl", "-s", "-X", "POST", GLM_API_URL,
             "-H", f"Authorization: Bearer {api_key}",
             "-H", "Content-Type: application/json",

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

python
"temperature": 0.3,
            "max_tokens": 256,
        }
        result = subprocess.run(
            ["curl", "-s", "-X", "POST", GLM_API_URL,
             "-H", f"Authorization: Bearer {api_key}",
             "-H", "Content-Type: application/json",

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Calling GLM-4 and Feishu are aligned with the manifested features, but invoking curl via subprocess adds a broader execution primitive unrelated to the user-facing purpose of sentiment monitoring. This increases capability beyond what the manifest implies because the same functionality could be performed with ordinary Python HTTP requests.

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

python
"temperature": 0.5,
                "max_tokens": 200,
            }
            result = subprocess.run(
                ["curl", "-s", "-X", "POST", GLM_API_URL,
                 "-H", f"Authorization: Bearer {api_key}",
                 "-H", "Content-Type: application/json",

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
86% confidence
Finding

The code posts alert data to a user-configurable feishu_webhook using curl, enabling arbitrary outbound HTTP requests to attacker-chosen destinations if configuration is influenced by an untrusted party. While not shell injection, this creates an SSRF-style/exfiltration primitive because alert contents and metadata can be transmitted to any URL.

Content

Scanner excerpt · scripts/sentiment.py (reported line 1445)May include surrounding context.

python
})

        try:
            result = subprocess.run(
                ["curl", "-s", "-X", "POST", webhook,
                 "-H", "Content-Type: application/json",
                 "-d", json.dumps(body, ensure_ascii=False)],

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The manifest describes monitoring named social platforms, which implies platform-specific monitoring capability. This self-review clarifies at L109 that the skill relies on generic Playwright scraping of public content with no official API support, which may not actually provide dependable or equivalent monitoring for all claimed platforms, especially WeChat Official Accounts.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency is specified with a lower bound only, which allows future installs to resolve to different versions over time. This weakens reproducibility and can unintentionally introduce vulnerable or breaking releases into the skill's runtime environment.

Content

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

text
# Sentiment Compass dependencies
playwright>=1.40.0
beautifulsoup4>=4.12.0
jieba>=0.42.1
requests>=2.31.0

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

Using an unpinned version for beautifulsoup4 means the environment may pull different releases on different installs. That creates supply-chain and stability risk because a newly published vulnerable or incompatible version could be consumed automatically.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
# Sentiment Compass dependencies
playwright>=1.40.0
beautifulsoup4>=4.12.0
jieba>=0.42.1
requests>=2.31.0

Static analysis

No suspicious patterns detected.