Back to skill

Security audit

raccoon ppt skill

Security checks for vulnerabilities and agentic risk

Overview

This PPT skill appears to do what it claims, but it can send your API token and presentation content to a configurable remote host and stores job details locally in plain text.

Review before installing. Use only with a trusted RACCOON_API_HOST, preferably the default service, and avoid passing the token through --token or shell history. Do not submit confidential business, customer, personal, or financial material unless you are comfortable sending it to the configured PPT service and retaining job metadata locally. Periodically clear the skill's output/jobs state and registry files if they contain sensitive topics or download links.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/main.py:209
Finding

Bearer Token and User Content Can Be Sent to an Untrusted or Unencrypted API Host

Content
View full analysis
str: return f"{self.host}/api/open/office/v2" def _request(self, method: str, path: str, payload: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: url = f"{self.base_url}{path}" body = None headers = { "Authorization": f"Bearer {self.token}", "Accept": "application/json", } if payload is not None: body = json.dumps(payload).encode("utf-8") headers["Content-Type"] = "application/json" req = request.Request(url, data=body, headers=headers, method=method) try: with request.urlopen(req, timeout=self.REQUEST_TIMEOUT) as resp: ``` The same destination and credential values can be supplied directly through command-line arguments: ```python parser.add_argument("--host", help="覆盖 RACCOON_API_HOST") parser.add_argument("--token", help="覆盖 RACCOON_API_TOKEN") ``` ### Technical Analysis The client accepts an API host from the `RACCOON_API_HOST` environment variable or the `--host` command-line option without validating its scheme or destination. The supplied bearer token is then attached to every request made to that host. There is no enforcement that: - The destination uses HTTPS. - The destination belongs to the documented `xiaohuanxiong.com` service. - The destination is not localhost, a private network address, or another untrusted endpoint. - The URL does not contain unexpected components such as embedded credentials. Sending presenta ...[truncated 1757 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/main.py:321
Finding

Presentation Content and Signed Download URLs Are Persisted in Plaintext State Files

Content
View full analysis
None: path = Path(state_path) path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(state, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") ``` The local registry retains presentation content and access-bearing download URLs: ```python entry = { "job_id": job_id, "status": state.get("status", ""), "prompt": state.get("prompt", ""), "role": state.get("role", ""), "scene": state.get("scene", ""), "audience": state.get("audience", ""), "question": state.get("question", ""), "download_url": state.get("download_url", ""), "error_message": state.get("error_message", ""), "state_path": state_path, "updated_at": utc_now(), } ``` The high-level generation path persists both records automatically: ```python save_state(state, state_path) upsert_registry_entry(state, state_path, registry_path) ``` ### Technical Analysis The task state can contain: - The complete presentation prompt. - Follow-up answers stored through state normalization. - Speaker role, scene, and audience. - Service questions and error messages. - Internal job identifiers. - Presigned download URLs returned by the API. `Path.write_text()` creates a regular plaintext file using permissions derived from the process umask. The code does not explicitly require mode `0600`, verify permissions on an existing file, encrypt sensitive fields, or constrain `state_path` to a private application directory. The registry uses a temporary-file replacement mechanism, but its contents remain unencrypted and include duplicated p ...[truncated 1649 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (24)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
RACCOON_API_TOKEN="$CLEAN_TOKEN" python3 scripts/main.py ...

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
RACCOON_API_TOKEN="$CLEAN_TOKEN" python3 scripts/main.py ...

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
RACCOON_API_TOKEN="$CLEAN_TOKEN" python3 scripts/main.py ...

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
RACCOON_API_TOKEN="$CLEAN_TOKEN" python3 scripts/main.py ...

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
RACCOON_API_TOKEN="$CLEAN_TOKEN" python3 scripts/main.py ...

Vague Triggers

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill enables implicit invocation and uses a broad trigger description covering PPT/slides/presentation requests, which can cause the agent to invoke this external-content generation workflow without sufficiently explicit user intent. In practice, this increases the chance of unintended third-party API calls, accidental data disclosure in prompts, and surprising autonomous actions on loosely related requests.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill clearly instructs use of environment variables, local state files, shell commands, and remote API access, but the manifest does not declare a restrictive tool scope. That mismatch weakens sandboxing and reviewability: an agent may be allowed to read env, write files, and make network requests without an explicit least-privilege declaration.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The skill is explicitly designed to continue prior tasks and the body further states that task state is saved locally and reused via find-recent-job and resume operations. Session persistence can expose prior user data across turns or users if state files are insufficiently isolated, especially because PPT topics may contain sensitive business content.

Content

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

md
---
name: raccoon-ppt
description: >
  Raccoon (小浣熊) PPT generation skill powered by the PPT OpenAPI. Create PPT
  decks from a natural-language topic. Primarily use this skill when the user
  wants to create a brand-new full PPT deck; secondarily use it to continue a
  PPT generation task or check the result of an existing PPT task. Keywords:

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill sends user-supplied presentation content to an external PPT generation API but does not clearly warn that prompts and business content will leave the local environment. For enterprise slide generation, prompts may contain sensitive internal strategy, financial data, or customer information, so missing disclosure materially increases privacy and compliance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill instructs the agent to inspect and manipulate API token environment variables, including printing whether variables are set and rewriting the token for command execution, but gives no user-facing credential handling warning. This increases the risk of accidental secret exposure in logs, terminal output, transcripts, or debugging flows.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill metadata says it is for creating, continuing, or checking PPT generation tasks, but the documentation also tells the agent to download and open generated files locally. Expanding behavior beyond the declared purpose increases the chance of unintended local file handling and unsafe opening of untrusted content returned by an external service.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The instructions require the assistant to tell the user a fixed Chinese message, imposing a specific language regardless of the user's language preference. This is a natural-language locale policy issue because no opt-in or language-selection behavior is provided.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file prescribes fixed user-facing phrasing in Chinese, including recommended responses and wording constraints, but does not offer user language selection or state that the skill is intentionally limited to Chinese-speaking users. This creates a natural-language policy issue because the skill appears to enforce a specific language by default.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The predefined category options exposed by the CLI are written entirely in Chinese, and later validation/error flows also use Chinese-only messaging. For a general-purpose skill, this imposes a specific language/locale on users without any visible opt-in or alternate locale path, which matches the policy's language/locale violation criterion.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The skill sends user-provided prompt content to a third-party remote API, but the code provides no user-facing disclosure or consent mechanism at the point of transmission. Because prompts for PPT generation may contain sensitive business, personal, or confidential material, users may unintentionally exfiltrate data outside the local environment. The skill context increases the risk because presentation requests often include internal plans, financials, customer data, or strategy content.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

Follow-up answers provided during waiting_user_input are also transmitted to the remote service without any user-facing warning. These replies are especially likely to contain clarifications, internal details, or confidential context requested by the service, creating the same data-exposure risk with even less user awareness. In this skill context, iterative clarification can progressively reveal more sensitive project information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

This markdown file states that task status is saved to ./output/jobs/{job_id}.json, which is a user-data-affecting file write. While the behavior is mentioned, the document does not frame it as a caution or warning about local persistence, retention, or sensitivity of stored task metadata.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

Earlier guidance says that when the task succeeds, the assistant should notify the user and provide a download link. The later example shows a different behavior: '正在下载' followed by downloading and opening the file and saving it to a local path, which actively conflicts with the stated intended behavior.

Content

No source excerpt is available for this finding.

Scope Creep

Low
Category
Excessive Agency
Confidence
70% confidence
Finding

Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.

Content

Scanner excerpt · agents/openai.yaml (reported line 17)May include surrounding context.

yaml
- role: speaker identity (max 10 chars)
     - scene: usage scenario (max 10 chars)
     - audience: target audience (max 10 chars)
     - Note: API accepts any string value, not limited to predefined enums

  2. Call `python3 scripts/main.py generate` (takes ~2-3 min to return, this is normal API behavior)

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The file's natural-language instructions and examples are entirely in Chinese, which can amount to a language-policy constraint if the skill documentation implicitly forces a specific language without user opt-in. There is no note that the skill is China/Chinese-only or that other languages are supported.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
81% confidence
Finding

This markdown file describes using a presigned S3 download_url and explicitly suggests requests.get(download_url) or opening it in a browser. Because this causes network access to an external endpoint and may transfer/download generated user content, the skill description should include a brief warning about external download behavior or handling of the returned file.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The skill persists prompt content and job metadata to local state files without notifying the user. Even if the remote API is trusted, local plaintext storage can expose sensitive topics, download URLs, and task context to other local users, backups, logs, or later processes. The danger is somewhat moderated by the local-only scope, but PPT topics often contain business-sensitive information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The registry stores task summaries and metadata locally without prior disclosure, creating an additional persistence surface beyond the main state file. This can unintentionally retain sensitive prompt fragments, statuses, and file paths over time, increasing exposure through local compromise, shared environments, or backups. The skill context makes this relevant because presentation summaries may themselves reveal confidential project intent.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/main.py (reported line 566)May include surrounding context.

python
data = client.reply_job(state["job_id"], answer)
        state = normalize_state({"prompt": answer, **data}, state)
    else:
        missing = [name for name in ["prompt", "role", "scene", "audience"] if not getattr(args, name)]
        if missing:
            raise APIError(f"缺少创建任务所需字段: {', '.join(missing)}")
        role_info = normalize_category("role", args.role)

Static analysis

No suspicious patterns detected.