Back to skill

Security audit

Sentiment Compass

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly consistent with social-media monitoring, but it needs Review because it stores and exposes credentials in plain text and has under-scoped external data flows.

Install only if you are comfortable with monitored social-media content and alert details being sent to configured third-party services. Use limited-scope API keys, avoid storing high-value SMTP credentials, restrict the config file permissions yourself, verify webhook URLs carefully, and pin dependencies before production use.

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:230
Finding

Plaintext Secret Storage, Retrieval, and Process-Argument Exposure

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 GLM API key is also included directly in a subprocess 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 permits unrestricted retrieval and output of configured values: ```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": key = sys.argv[2] if len(sys.argv) > 2 else "" value = sys.argv[3] if len(sys.argv) > 3 else "" try: value = json.loads(value) except Exception: pass set_config(key, value) print(json.dumps({"ok": True, "key": key, "value": value}, ensure_ascii=False)) ``` Equivalent `curl` argument exposure also occurs in the batch-analysis and report-summary request paths at lines 885-890 and 1291-1296. ### Technical Analysis The configuration file can contain a GLM API key, a Feishu webhook URL containing a secret token, and SMTP credentials. These values are serialized directly to `~/.sentiment-compass/config.json`. The code does not ex ...[truncated 2124 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sentiment.py:238
Finding

External Transmission of a Full Subscription Bearer Token Without Clear Disclosure

Content
View full analysis
dict: if not api_key: return {"valid": False, "tier": "FREE", "error": "No API key provided"} 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")) ``` ### Technical Analysis When a token with a recognized prefix is supplied to `SentimentCompass`, the complete token is sent as an HTTP bearer credential to `geo-api.yk-global.com`. This is a direct external disclosure of a sensitive authentication value. The declared Skill documentation mentions subscription-token prefixes and links to the vendor website, but the reviewed documentation does not clearly identify the validation host, explain that the full token is transmitted, define retention or logging behavior, or request informed consent. The claim in `SELF_REVIEW.md` that sensitive data remains local is inconsistent with this implementation. Remote verification may be legitimate for enforcing subscription tiers, but it is not r ...[truncated 1516 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/sentiment.py:1383
Finding

Unrestricted Configurable Webhook Enables Arbitrary Outbound Requests

Content
View full analysis
2 else "" value = sys.argv[3] if len(sys.argv) > 3 else "" try: value = json.loads(value) except Exception: pass set_config(key, value) ``` ### Technical Analysis The method is described as a Feishu alert sender, but it accepts any configured URL. It does not enforce HTTPS, verify that the hostname belongs to Feishu, reject embedded credentials, resolve and block private addresses, or constrain redirects. Consequently, any actor able to influence the Skill configuration or induce an agent to run the documented configuration command can turn the host into an outbound HTTP POST client. The request includes alert information such as monitored keywords, negative-post metadata, authors, timestamps, counts, and sentiment reasons. Using a subprocess argument list avoids shell metacharacter injection because `shell=True` is not used. The vulnerability is therefore not command injection; it is unvalidated destination control and excessive ...[truncated 1493 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
requirements.txt:2
Finding

Unpinned Third-Party Dependencies Permit Unreviewed Future Releases

Content
View full analysis
=1.40.0 beautifulsoup4>=4.12.0 jieba>=0.42.1 requests>=2.31.0 ``` ### Technical Analysis Every dependency uses only a lower version bound. A future installation may therefore resolve to any later release available from the configured package index. The project provides no lockfile, exact version constraints, package hashes, or documented review process for dependency updates. The listed package names are established packages and there is no evidence of typosquatting or an intentionally malicious dependency in the reviewed artifact. The security weakness is that future builds are not reproducible and may automatically consume compromised, vulnerable, or incompatible releases without review. Playwright also requires a separately downloaded browser binary. That component should be version-controlled and integrity-verified as part of the same supply-chain policy. ### Attack Path 1. A user installs the project using `pip install -r requirements.txt`. 2. The package resolver selects the newest release satisfying each lower bound. 3. A future release, compromised package-index account, compromised distribution artifact, or vulnerable transitive dependency is selected. 4. Package installation hooks or imported runtime code execute under the installing user's privileges. 5. The compromised component can access files, environment variables, network connectivity, and credentials available to that user. ### Impact Assessment A compromised dependency executes with the same operating-system privileges as the user installing or running the Skill. It may potentially: - Read the plaintext Skill configuration and service credentials. - Modify local files and the SQLite database. - Send network requests from the host. - Alter crawling, analysis ...[truncated 210 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (25)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The README explicitly promotes social media monitoring, AI analysis, and Feishu/email alerting, and later documents configuration of webhooks, SMTP, and an external AI API without warning users that content and credentials may be sent to third-party services. In a monitoring tool, this omission increases the risk of unintentional collection, transfer, and disclosure of personal or sensitive data, especially when users may assume analysis is local or low-risk.

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 依赖 |

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The self-review claims data is stored only locally, but the same document describes sending content to external GLM-4, Feishu, and email services. This is a real security/privacy documentation issue because operators may enable the skill under a false assumption that monitored content never leaves the host, leading to unintended third-party disclosure of collected social-media data or reports.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The deployment instructions tell users to configure a Feishu webhook without warning that alerts may send monitored keywords, excerpts, summaries, or negative-sentiment results to an external messaging service. In a sentiment-monitoring skill, that increases the chance of unintentional disclosure of potentially sensitive monitoring results to third parties or misconfigured chat groups.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill advertises and demonstrates capabilities that imply network access, local file storage, and code/script execution behaviors, but it declares no explicit tool scope or permission boundaries. In practice this can let an agent invoke broader tools than a user would reasonably expect, especially because the skill performs web scraping, writes SQLite/JSON data locally, and sends outbound alerts/webhook traffic.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill states that scraped post/comment content is sent to the GLM-4 API for sentiment analysis and may also be forwarded to Feishu webhooks or SMTP, but it does not prominently warn users about this external data transmission. This creates privacy and compliance risk because third-party content, potentially including personal data, is exported off-platform without clear consent or minimization guidance.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The file specifies '基于 GLM-4 API 的中文语义情感分析' and all examples and classifications are framed as Chinese-only behavior, but it does not indicate that users can choose another language or that the skill is intentionally limited to a Chinese-language region/use case. This can violate language/locale policy when a skill imposes a language constraint without opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The file description states the engine is for Chinese platforms, and multiple execution paths force zh-CN locale or Chinese-only prompts, such as Playwright browser contexts and GLM prompt text. The policy allows locale constraints only when clearly documented and justified or when users can opt in; this code enforces the locale in implementation without any user-selectable language option.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill performs license/token verification against an unrelated external service and sends bearer credentials there, despite that not being necessary for sentiment monitoring functionality. This creates an unjustified data egress path for secrets, increases supply-chain trust on a third party, and could leak or misuse user-provided keys if the service is compromised or malicious.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest promises social-media monitoring, which does justify network fetching, but this implementation additionally launches external Node.js code through subprocesses to perform browser automation and anti-detection behaviors. Executing an external runtime is a materially broader capability than simple monitoring logic and is not explicitly disclosed in the skill's stated purpose.

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",

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Collected post text and alert content are transmitted to external AI and notification services without an explicit user-facing warning or per-action consent at the point of use. Because social-media monitoring may include personal data, complaints, or business-sensitive content, silent egress to third parties creates privacy, confidentiality, and compliance risk.

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
82% confidence
Finding

The code posts alert data to a configurable webhook URL without validating destination host, scheme, or trust boundary. If an attacker can modify configuration, this becomes an SSRF-style outbound request primitive that can exfiltrate alert contents to arbitrary endpoints or probe internal services reachable from the host.

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)],

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
85% confidence
Finding

Natural-language policy violations include forcing a specific language without user opt-in. This README presents all operational guidance in Chinese and does not indicate that the skill supports other languages, offers a choice, or is intentionally limited to a Chinese-only audience for a documented reason.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

L109 says the skill has 'no official API dependency' and relies on pure Playwright scraping, but the same file documents GLM-4 API-based sentiment analysis as an implemented feature and shows configuration of a glm_api_key in L160-L162. That is not merely incomplete wording: it actively overstates the absence of API dependency despite code functionality depending on an external API for one of the core advertised capabilities.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The self-review states that all data is stored locally in ~/.sentiment-compass/, which affects user data handling and retention, but there is no user warning about persistent storage, sensitivity of collected content, or cleanup expectations. For markdown files, SQP-2 covers missing warnings about behaviors that could affect user data or privacy.

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 supply-chain reproducibility and can unintentionally introduce vulnerable or incompatible releases, though it is not by itself evidence of compromise.

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 range for beautifulsoup4 makes builds non-reproducible and exposes deployments to future upstream changes without review. In a monitoring/scraping skill that depends on HTML parsing, silent upgrades can also break parsing behavior and increase operational risk.

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

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The jieba package is not pinned to a specific release, so installations may vary across environments and time. This creates avoidable supply-chain and reproducibility risk, even if no specific exploited issue is demonstrated here.

Content

Scanner excerpt · requirements.txt (reported line 4)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
98% confidence
Finding

Requests is declared with only a minimum version, so dependency resolution may select any later release, including versions with known advisories or behavior changes. Because this skill likely performs external HTTP requests to social-media-related services, an unsafe or inconsistent requests version increases network-facing attack surface and can expose data or transport-security issues.

Content

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

text
playwright>=1.40.0
beautifulsoup4>=4.12.0
jieba>=0.42.1
requests>=2.31.0

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

The manifest includes requests without an exact version, and requests has multiple historical advisories; therefore it is impossible to verify from this file whether deployment will use a fixed or affected release. In a skill that likely makes outbound HTTP requests for monitoring and alerting, this uncertainty is more dangerous because vulnerable client behavior can directly affect credential handling, TLS verification, redirects, or request routing.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

This Python test file contains extensive hard-coded Chinese-language inputs, expected outputs, and platform assumptions throughout the test suite. Because the file gives no indication that the skill is intentionally region- or locale-specific, it appears to enforce one language/locale by default rather than offering an opt-in or documenting the constraint.

Content

No source excerpt is available for this finding.