Back to skill

Security audit

公众号素材库 & 预设包

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent asset-import purpose, but its preset importer can modify and expose credential-like values in ways users should review carefully before installing.

Review this skill before installing in repositories that contain real API keys, WeChat credentials, or confidential business material. Prefer dry runs, inspect .aws bundles before import, avoid --allow-any-host, and do not run the importer where stdout logs may capture secrets unless the config-diff behavior is fixed or redacted.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/import_presets_aws.py:227
Finding

Sensitive configuration values are exposed through stdout diff output

Content
View full analysis
list[dict[str, Any]]: """Compare each key present in package config against the matching local path.""" out: list[dict[str, Any]] = [] for k, nv in new.items(): path = f"{prefix}.{k}" if prefix else k if k not in old: continue ov = old[k] if isinstance(nv, dict) and isinstance(ov, dict): out.extend(_config_diff(ov, nv, path)) elif nv != ov: out.append({"key": path, "old": ov, "new": nv}) return out def _print_config_diff_json(diffs: list[dict[str, Any]]) -> None: print(json.dumps(diffs, ensure_ascii=False, indent=2)) ``` The vulnerable functions are invoked without excluding secret fields: ```python else: old_map = _load_yaml_mapping(config_dest, "Local config.yaml") diffs = _config_diff(old_map, new_map) _print_config_diff_json(diffs) _info( f"config differences: {len(diffs)} entries were written to stdout" ) _write_aws_env_incremental(repo, new_map, args.dry_run) ``` ### Technical Analysis The imported `config.yaml` is explicitly permitted to contain sensitive values, including: - `wechat_appsecret` - `writing_model.api_key` - `image_model.api_key` - `wechat_appid` When a local configuration already exists, `_config_diff` recursively compares the local and package configurations. For every changed leaf, it places both the original value and the package-supplied value into a JSON object. `_print_config_diff_json` then prints the complete object to stdout without redaction. Consequently, differences involving credentials expose both the existing local secret and the newly imported secret. Although the separate `aws.env` update path intentionall ...[truncated 1489 chars]
Remediation
View remediation
Any: if path in SENSITIVE_CONFIG_PATHS: return "[REDACTED]" return value # When recording a difference: out.append({ "key": path, "old": _redacted_diff_value(path, ov), "new": _redacted_diff_value(path, nv), }) ``` A safer design is to omit `old` and `new` entirely for sensitive paths: ```python if path in SENSITIVE_CONFIG_PATHS: out.append({"key": path, "changed": True, "sensitive": True}) else: out.append({"key": path, "old": ov, "new": nv}) ``` ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/import_presets_aws.py:80
Finding

Download host allowlist is not reapplied after HTTP redirects

Content
View full analysis
None: p = urlparse(url) if p.scheme != "https": _err(f"Only https:// preset downloads are allowed; received: {p.scheme}://") host = (p.hostname or "").lower() if not allow_any_host: if host != ALLOWED_HOST_EXACT and not host.endswith(ALLOWED_HOST_SUFFIX): _err(f"Host is outside the allowlist: {host}") if not Path(p.path).name.endswith(".aws"): _err("URL path must end in .aws") def _download_bundle(url: str, repo: Path) -> Path: downloads = repo / ".aws-article" / "downloads" downloads.mkdir(parents=True, exist_ok=True) fname = Path(urlparse(url).path).name or "bundle.aws" local = downloads / fname tmp_out = local.with_suffix(local.suffix + ".part") req = urllib.request.Request(url, headers={"User-Agent": "aws-wechat-article-assets/1.0"}) _info(f"Downloading: {url}") try: with urllib.request.urlopen(req, timeout=DOWNLOAD_TIMEOUT_SEC) as resp, open(tmp_out, "wb") as out: shutil.copyfileobj(resp, out) except urllib.error.HTTPError as e: _err(f"HTTP {e.code} download failed: {url}") except urllib.error.URLError as e: _err(f"Network error: {e.reason}") ``` Only the original argument is validated: ```python raw = args.bundle if _is_url(raw): _validate_url(raw, args.allow_any_host) bundle = _download_bundle(raw, repo) else: bundle = Path(raw).resolve() ``` ### Technical Analysis The importer claims to restrict downloads to HTTPS URLs hosted by `aiworkskills.cn` or its subdomains. `_validate_url` correctly checks the initially supplied URL, but `urllib.request.urlopen` follows redirects automatically. The code neither installs a redirect handler that ...[truncated 1772 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/import_presets_aws.py:93
Finding

Unbounded archive download and extraction permit disk-exhaustion denial of service

Content
View full analysis
Path: downloads = repo / ".aws-article" / "downloads" downloads.mkdir(parents=True, exist_ok=True) fname = Path(urlparse(url).path).name or "bundle.aws" local = downloads / fname tmp_out = local.with_suffix(local.suffix + ".part") req = urllib.request.Request(url, headers={"User-Agent": "aws-wechat-article-assets/1.0"}) _info(f"Downloading: {url}") try: with urllib.request.urlopen(req, timeout=DOWNLOAD_TIMEOUT_SEC) as resp, open(tmp_out, "wb") as out: shutil.copyfileobj(resp, out) except urllib.error.HTTPError as e: _err(f"HTTP {e.code} download failed: {url}") except urllib.error.URLError as e: _err(f"Network error: {e.reason}") shutil.move(str(tmp_out), str(local)) if not zipfile.is_zipfile(local): _err(f"Downloaded content is not a valid ZIP: {local}") return local ``` The archive is checked for path traversal, but no resource limits are applied before extraction: ```python def _safe_extractall(zf: zipfile.ZipFile, dest: Path) -> None: dest_resolved = dest.resolve() for name in zf.namelist(): member_path = Path(name) if member_path.is_absolute(): _err(f"ZIP contains an absolute path: {name}") if ".." in member_path.parts: _err(f"ZIP contains a '..' segment: {name}") target = (dest / name).resolve() try: target.relative_to(dest_resolved) except ValueError: _err(f"ZIP path points outside extraction directory: {name}") zf.extractall(dest) ``` The extraction is then performed directly: ```python _reset_staging(staging) with zipfile.ZipFile(bu ...[truncated 2049 chars]
Remediation
View remediation
MAX_MEMBERS: _err("Archive contains too many members") total = 0 for info in infos: if info.file_size > MAX_MEMBER_SIZE: _err("Archive member exceeds the size limit") total += info.file_size if total > MAX_TOTAL_SIZE: _err("Archive exceeds the total expanded-size limit") if info.compress_size == 0 and info.file_size > 0: _err("Suspicious compression ratio") if info.compress_size and info.file_size / info.compress_size > MAX_RATIO: _err("Suspicious compression ratio") ``` ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
Findings (11)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared purpose centers on preset import and asset management, but the skill also imports credential-like values from package config into repository-root aws.env and rotates backups. This is security-sensitive behavior that is easy for users or reviewers to miss, and it allows a downloaded package to modify local secrets/config state outside the advertised preset directory.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill documents file read, file write, and network behaviors but does not declare an explicit tool scope such as permissions or allowed-tools. That creates an authorization and review gap: operators may trust the manifest surface while the instructions still direct the agent to perform broader actions, increasing the chance of unintended filesystem or network access.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Persisting newly generated business-introduction content from conversations functions as a natural-language log of potentially confidential commercial information. Even if intended as a convenience feature, storing this by default increases exposure if the repository is shared, synced, or later queried in unrelated contexts.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Persisting newly generated business-introduction content from conversations functions as a natural-language log of potentially confidential commercial information. Even if intended as a convenience feature, storing this by default increases exposure if the repository is shared, synced, or later queried in unrelated contexts.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The capabilities section claims all writes are confined to .aws-article/, yet the documented workflow also writes repository-root aws.env and aws.env.bak.*. This inconsistency can mislead users and security controls about where sensitive side effects occur, weakening trust boundaries and increasing the risk of unnoticed credential modification or leakage through backups.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The workflow directs the agent to inspect prior product directories and read stored documents and image notes as source material for current tasks. Without strict relevance and consent checks, this can expose previously provided sensitive information beyond the user's immediate request and broaden access to historical data unnecessarily.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This Python file’s docstring, CLI help text, and runtime log/error messages are written exclusively in Chinese, which effectively constrains interaction to a specific language. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified, which is not stated here.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script extracts secret values from an imported package's config.yaml and writes them into the repository-root aws.env, which is a sensitive side effect beyond simple preset/theme import. Because the package can be downloaded remotely and its contents are trusted after only ZIP/host validation, a crafted bundle can inject or overwrite API credentials and change which external accounts or services later automation uses.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The natural-language description is entirely in Chinese and presents the skill behavior in a single fixed language, with no indication that users can choose another language or that the skill is intended only for a Chinese-language context. This can violate language/locale policy when a skill implicitly enforces one language without opt-in or justification.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The --allow-any-host flag disables the domain allowlist and permits downloading .aws bundles from any HTTPS host. In a tool that imports filesystem content and can also update aws.env secrets from package config, this expands the trust boundary substantially and makes malicious bundle delivery much easier if the flag is exposed or suggested by an agent.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This is a manifest file, so vague-trigger review applies. The description summarizes capabilities and required arguments, but it does not define narrow trigger phrases, invocation scope, or exclusion conditions, which can make natural-language activation ambiguous and increase the chance of unintended invocation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.