Back to skill

Security audit

优惠券查询助手

Security checks for vulnerabilities and agentic risk

Overview

This coupon skill performs coupon lookup, but it also can run a local updater and includes shared service credentials and unsafe cache handling, so it should be reviewed before installation.

Install only if you trust the publisher and accept that it contacts a third-party coupon service and displays externally supplied coupon links. Avoid using the chat-triggered upgrade path; prefer a version that removes runtime self-updates, stores cache data in a protected per-user location, validates returned links, and does not ship shared API credentials in the skill package.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/get_coupon.py:21
Finding
Obfuscated Hardcoded API Credential Transmitted to a Third-Party Service<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get_coupon.py`, lines 21–47 and 95–114 **Vulnerability Type**: Hardcoded credential, concealed network destination, and sensitive credential transmission **Risk Level**: High ### Vulnerable Code ```python def _get_api_config(self): url_part1 = "aHR0cHM6Ly9vcGVuLmRhdGFkZXguY29tLmNuL2RleHNlcnZlci9kZXgtYXBpL3Yx" url_part2 = "L2dldGNvdXBvbg==" a1_part1 = "QVBQLVZFTm1FdjAtOTM4MTAy" a1_part2 = "MjQ5MTI5OTE0NDMzLTEx" a2_part1 = "S0VZMDM1VkVObkhzeA==" a2_part2 = "MkIzOTQ5SWdNRWZuYVI0QldZR3Q5M3BlZE1rd3BRMHYxMg==" api_base = base64.b64decode(url_part1).decode() + base64.b64decode(url_part2).decode() a1 = base64.b64decode(a1_part1).decode() + base64.b64decode(a1_part2).decode() a2 = base64.b64decode(a2_part1).decode() + base64.b64decode(a2_part2).decode() ts = str(int(time.time())) token = hashlib.md5(f"api_{ts}".encode()).hexdigest()[:8] return { 'url': api_base, 'a1': a1, 'a2': a2, 't1': ts, 'token': token } ``` ```python config = self._get_api_config() api_url = config['url'] payload = { 'a1': config['a1'], 'a2': config['a2'], 't1': config['t1'] } req = urllib.request.Request( api_url, data=json.dumps(payload).encode('utf-8'), headers={ 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': 'application/json', 'X-Token': config['token'] }, method='POST' ) resp = urllib.request.urlopen(req, timeout=10) ``` ### Technical Analysis The program embeds a reusable application identifier and API key directly in distributed client code. The endpoint and credentials are split into fragments and Base64-decoded at runtime. Base64 is reversible encoding rather than encryption and offers no confidentiality. Anyone who can access the Skill package can reconstruct the endpoint and credentia ...[truncated 2008 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the application ID and API key from the distributed Skill source, including encoded fragments and plaintext comments. 2. Do not treat Base64 or string splitting as secret protection. 3. Keep reusable provider credentials on a controlled backend and expose only a narrowly scoped coupon-query interface to clients. 4. If users must authenticate directly, load credentials from a protected secret manager or environment-based secret injection mechanism rather than source control. 5. Prefer short-lived, audience-restricted, least-privilege tokens over a shared permanent key. 6. Rotate and revoke the exposed credential because it must be considered compromised once distributed. 7. Document the third-party endpoint and the exact request fields sent over the network. 8. Replace the predictable truncated MD5 token scheme with a provider-supported authentication mechanism, such as a server-issued short-lived token or an HMAC using a secret that is not shipped to clients. 9. Apply provider-side rate limiting, usage monitoring, credential scoping, and anomaly alerts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/get_coupon.py:17
Finding
Predictable Shared Temporary Cache Permits Local Cache Poisoning and Unsafe File Redirection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get_coupon.py`, lines 17 and 57–72 **Vulnerability Type**: Unsafe temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```python def __init__(self, query=""): self.query = query self.cache_file = "/tmp/coupon_data_cache" self.cache_ttl = 900 ``` ```python def get_cache(self): try: if os.path.exists(self.cache_file): mtime = os.path.getmtime(self.cache_file) if time.time() - mtime < self.cache_ttl: with open(self.cache_file, 'r') as f: return json.load(f) except: pass return None def set_cache(self, data): try: with open(self.cache_file, 'w') as f: json.dump(data, f) except: pass ``` ### Technical Analysis The cache uses a fixed path in the globally writable `/tmp` directory. The program neither creates the file securely nor verifies its type, ownership, permissions, or canonical destination before reading or writing it. The check with `os.path.exists()` followed by a separate `open()` operation also creates a time-of-check/time-of-use window. Another local process may replace the path between those operations. The write operation follows symbolic links and truncates the resolved destination if the running user has permission to write it. Cache contents are accepted as JSON without validating their expected structure, field types, URL schemes, or destination domains. The cached coupon data is later used to generate displayed links and instructions. A local attacker able to manipulate `/tmp/coupon_data_cache` can therefore inject deceptive coupon content. The feasibility of redirecting writes to protected files depends on the host's operating-system hardening, filesystem protections, and the permissions of the account running the Skill. The repository does not demonstrate privilege escalation to files the account cannot already write. ### Attack ...[truncated 1377 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store cached data in a per-user cache directory, such as a platform-appropriate directory obtained through `platformdirs`, rather than directly under `/tmp`. 2. Create the containing directory with permissions limited to the current user, preferably mode `0700` on POSIX systems. 3. Create cache files with exclusive and restrictive permissions, preferably mode `0600`. 4. Reject symbolic links and non-regular files. On supported systems, use `os.open()` with flags such as `O_NOFOLLOW`, `O_CREAT`, and appropriate exclusive-creation behavior. 5. Verify file ownership and permissions before accepting existing cache data. 6. Write to a securely created temporary file in the same protected directory, flush and synchronize it as appropriate, and atomically replace the cache using `os.replace()`. 7. Validate cached JSON against a strict schema before use, including expected object types and field lengths. 8. Allow only expected HTTPS destinations or approved platform domains before displaying remotely supplied links. 9. Avoid broad exception suppression so security-relevant cache failures can be logged and diagnosed safely. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/get_coupon.py:198
Finding
Unverified Package Update Can Replace the Audited Skill with Remote Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/get_coupon.py`, lines 198–224 and 243–245 **Vulnerability Type**: Unverified dependency and update channel **Risk Level**: Medium ### Vulnerable Code ```python def check_update(): print(f"Checking the latest version of {SKILL_NAME}...\n") try: result = subprocess.run( ["clawhub", "update", SKILL_NAME], capture_output=True, text=True, timeout=60 ) if result.returncode == 0: print("Update completed successfully.\n") print("Please retry the coupon query.\n") return True else: print(f"Update failed: {result.stderr or result.stdout}") return False except FileNotFoundError: print("The clawhub command was not found.") print("Install the clawhub CLI first: npm i -g clawhub\n") return False except subprocess.TimeoutExpired: print("The update timed out. Please retry later.\n") return False except Exception as e: print(f"Update error: {str(e)}\n") return False ``` ```python if "--check-update" in args or "--upgrade" in args or "upgrade" in "".join(args): check_update() return ``` The displayed snippet translates user-facing source strings into English while preserving the executable update logic under review. ### Technical Analysis The Skill invokes `clawhub update getcoupon`, allowing an external package source and local CLI to replace the installed Skill. The code does not pin an approved version, verify a cryptographic digest, validate a package signature, or confirm the expected publisher identity. The command is passed as an argument array with a constant package name, so the reviewed code does not expose shell-command injection through the user's query. The risk instead lies in granting the update channel authority to replace code after the current package has been audited. ...[truncated 1755 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove update execution from the coupon-query runtime and place updates in a separate administrative workflow. 2. Require explicit, informed confirmation before replacing installed code. 3. Pin updates to an approved immutable version rather than accepting an unspecified latest version. 4. Verify the package publisher identity and require cryptographically signed release metadata or package signatures. 5. Verify a trusted SHA-256 or stronger digest before installation. 6. Use a trusted absolute path for the update CLI or otherwise validate the resolved executable. 7. Display the target version, publisher, source, and requested permission changes before installation. 8. Perform updates under the least-privileged account possible and prevent the updater from modifying unrelated agent or system components. 9. Retain the previous verified version and support rollback if integrity checks or post-update validation fail. 10. Do not recommend global CLI installation from an unpinned package name as part of normal Skill output. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The declared purpose is a coupon query assistant, but the behavior includes local subprocess execution for skill upgrades and remote API access that are not disclosed. Hidden upgrade logic is especially dangerous because it can change code after review, and shell execution greatly expands the blast radius from simple data retrieval to arbitrary local actions.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
A coupon-query skill should not perform self-update operations that can modify installed software. This creates a privilege and supply-chain risk: a simple user query such as asking to upgrade can cause external code retrieval/execution, which is dangerous if the update source, CLI, or local PATH is compromised.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill metadata declares no tool scope or permissions, yet the analyzed behavior indicates access to file operations, network, and shell execution. This creates a transparency and containment failure: reviewers and runtime policy may treat the skill as low-risk while it can perform far more powerful actions, including command execution and external communication.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger language is broad enough to match common shopping conversation, which can cause the skill to activate unexpectedly. In a skill with external network access and possible upgrade behavior, accidental invocation increases exposure by sending user queries to third-party services or invoking risky code paths without clear user intent.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The example invocations are vague and insufficiently constrained, making it likely the skill will trigger on ordinary conversation such as asking about deals in general. Because the skill relies on third-party coupon aggregation and potentially risky implementation behavior, this ambiguity raises the chance of unintended data sharing and unauthorized execution paths.

Vague Triggers

Medium
Confidence
91% confidence
Finding
Single-word triggers like platform names or generic terms such as '优惠券' and '折扣' are highly collision-prone in everyday dialogue. In this context, broad triggers are more dangerous because the skill is not a purely static responder; it may reach third-party services and, per analysis, includes undisclosed powerful capabilities.

Ae4

Medium
Category
analysis-evasion
Confidence
95% confidence
Finding
The file contains mixed-script and obfuscated-looking coupon text, including unusual Unicode characters in fallback content. Such text can hide deceptive links, make phishing or social-engineering payloads harder to inspect, and can mislead users into copying attacker-controlled content into another app.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The skill's user-facing strings are entirely in Chinese and the suggested invocations are also Chinese-only, with no option to select another language or locale. This creates a language/locale policy issue because the behavior is enforced by the skill rather than chosen by the user.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"🔍 正在检测 {SKILL_NAME} 最新版本...\n")
    
    try:
        result = subprocess.run(
            ["clawhub", "update", SKILL_NAME],
            capture_output=True,
            text=True,
Confidence
98% confidence
Finding
The skill invokes an external CLI via subprocess, which introduces code execution behavior unrelated to coupon lookup. Even though arguments are passed as a list, this still allows the skill to trigger installation/update side effects and execution of whatever 'clawhub' binary is resolved in the environment, expanding the attack surface significantly.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The main command path explicitly interprets user input as an upgrade trigger, causing behavior beyond the declared coupon-query scope. This increases risk because ordinary interaction text can invoke state-changing maintenance actions, violating least privilege and making social-engineering abuse easier.

Static analysis

No suspicious patterns detected.