Back to skill

Security audit

GoAI PDF to PPT

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to perform the advertised PDF-to-PPT conversion, but it has avoidable risks around sending documents and API keys to configurable endpoints, writing server-influenced files, and automatically opening downloaded presentations.

Install only if you are comfortable uploading PDFs to the GoAI service and sharing result URLs in the agent conversation. Avoid setting GOAI_BASE_URL unless it is a trusted HTTPS endpoint with its own scoped credential, run the skill in a directory where unexpected .pptx writes are low impact, and consider disabling or reviewing automatic opening of downloaded presentations before use.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/common.py:51
Finding

Arbitrary Endpoint Override Can Expose the API Key and Source Document

Content
View full analysis
None: self.skill_name = skill_name self.base_url = os.environ.get("GOAI_BASE_URL", DEFAULT_BASE_URL).rstrip("/") self.api_key = os.environ.get("GOAI_API_KEY", "") ``` ```python def _headers(self, auth_mode: str) -> dict[str, str]: headers = {"Accept": "application/json"} if auth_mode == "auth": headers["Authorization"] = f"Bearer {self.api_key}" return headers ``` ```python def upload_local_file(self, value: str) -> str: path = Path(value).expanduser() if not path.is_absolute(): path = (Path.cwd() / path).resolve() if not path.is_file(): raise GoAIError(f"local file not found or unreadable: {value}") mime_type = content_type_for_file(path) payload = self.json_request( "GET", f"{self.base_url}/api/v2/oss/sign-url", "auth", query={ "filename": path.name, "contentType": mime_type, "folder": "inputs", }, ) self.api_assert_ok(payload) data = payload.get("data") if not isinstance(data, dict): raise GoAIError("invalid upload response") signed_url = str(data.get("signedUrl") or "") final_url = str(data.get("finalUrl") or "") if not signed_url: raise GoAIError("signedUrl missing from upload response") if not final_url: raise GoAIError("finalUrl missing from upload response") try: response = self._http.put( signed_url, headers={"Content-Type": mime_type}, content=path.read_bytes(), ) ``` ### Technical Analysis `GOAI_BASE_URL` is accepted from the environment ...[truncated 1706 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/convert_pdf_to_ppt.py:72
Finding

Server-Controlled Job Identifier Permits Output Path Traversal

Content
View full analysis
str: if not media_url: raise GoAIError("download URL is required") output_path = Path(output_name).expanduser() if not output_path.is_absolute(): output_path = (Path.cwd() / output_name).resolve() output_path.parent.mkdir(parents=True, exist_ok=True) try: response = self._http.get(media_url) except httpx.RequestError: raise GoAIError(f"download failed: {media_url}") from None if response.status_code not in {200, 201}: raise GoAIError(f"download failed: {media_url}") output_path.write_bytes(response.content) return str(output_path) ``` ### Technical Analysis The API-provided `jobId` is incorporated directly into the output filename. The value is checked only for emptiness and is not restricted to safe filename characters. Path separators and `..` components can therefore influence the destination. Calling `Path.resolve()` normalizes traversal components but does not enforce containment within the working directory. The code also creates destination parent directories and uses `write_bytes()`, which overwrites an existing file at the resolved path. Although the filen ...[truncated 1274 chars]
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/convert_pdf_to_ppt.py:35
Finding

Untrusted Downloaded Presentation Is Automatically Opened

Content
View full analysis
None: system = platform.system() try: if system == "Darwin": subprocess.run(["open", path], check=True, capture_output=True) elif system == "Linux": subprocess.run(["xdg-open", path], check=True, capture_output=True) elif system == "Windows": subprocess.run(["start", "", path], check=True, shell=True, capture_output=True) except subprocess.CalledProcessError: pass ``` ```python output_path = client.download_media(download_url, f"goai-pdf-{job_id}.pptx") open_local_ppt(output_path) ``` ```python def download_media(self, media_url: str, output_name: str) -> str: if not media_url: raise GoAIError("download URL is required") output_path = Path(output_name).expanduser() if not output_path.is_absolute(): output_path = (Path.cwd() / output_name).resolve() output_path.parent.mkdir(parents=True, exist_ok=True) try: response = self._http.get(media_url) except httpx.RequestError: raise GoAIError(f"download failed: {media_url}") from None if response.status_code not in {200, 201}: raise GoAIError(f"download failed: {media_url}") output_path.write_bytes(response.content) return str(output_path) ``` ### Technical Analysis The conversion API controls `downloadUrl`, and the downloaded response is saved without validating its final host, size, MIME type, integrity, or internal PPTX structure. The saved content is immediately opened with the operating system's default file handler. A valid PPTX is a ZIP-based Office document, but no check confirms that the response is actually a PPTX package. Autom ...[truncated 1580 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
pyproject.toml:1
Finding

Mutable Runtime Dependency Resolution Without a Lockfile

Content
View full analysis
=3.10" dependencies = [ "httpx>=0.27,<1", ] ``` ```python uv_bin = shutil.which("uv") if uv_bin is None: print(_uv_install_hint(), file=sys.stderr) raise SystemExit(1) os.execvpe( uv_bin, [ uv_bin, "run", "--project", str(skill_dir), "python", str(script_path), *sys.argv[1:], ], os.environ.copy(), ) ``` ### Technical Analysis The project permits any `httpx` version from 0.27 up to, but excluding, 1.0. The runtime bootstrap automatically invokes `uv run`, which can resolve and install dependencies on first execution. No `uv.lock` file is present in the audited project, despite documentation referring to one. As a result, identical Skill source code can execute different dependency versions at different times. This weakens reproducibility and expands supply-chain exposure because future package releases are accepted without a corresponding review of the Skill. The project uses the legitimate `httpx` package name and the reviewed files contain no evidence of typosquatting or a deliberately malicious package. The risk arises from mutable resolution rather than a confirmed malicious dependency. ### Attack Path 1. The Skill is executed in a fresh environment without an already prepared project virtual environment. 2. The bootstrap invokes `uv run`. 3. Because no committed lockfile fixes the dependency artifact, `uv` resolves a version satisfying `httpx>=0.27,<1`. 4. A future vulnerable or compromised package release satisfying that range may be selected. 5. Installed dependency code is imported and executes with the privileges and environment of the Skill process, including access ...[truncated 483 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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The code chunk does not implement or even directly support PDF-to-PPT conversion logic, GoAI API interaction, PDF handling, or PowerPoint generation. Its sole purpose is to ensure the skill runs inside a uv-managed Python environment by detecting the current environment, locating the uv executable, printing platform-specific install instructions, and relaunching the script with uv run. While bootstrapping can be a supporting detail, this chunk's actual behavior is entirely unrelated to the declared end-user function, and the declared description does not mention environment management or process re-execution. Therefore this is a material description-behavior mismatch for the supplied code chunk.

Content

No source excerpt is available for this finding.

os.system() or os exec-family call

High
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

os.system() and os exec-family calls run shell commands with the process's full privileges, enabling arbitrary command execution.

Content

Scanner excerpt · scripts/bootstrap.py (reported line 50)May include surrounding context.

python
print(_uv_install_hint(), file=sys.stderr)
        raise SystemExit(1)

    os.execvpe(
        uv_bin,
        [
            uv_bin,

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/bootstrap.py (reported line 61)May include surrounding context.

python
str(script_path),
            *sys.argv[1:],
        ],
        os.environ.copy(),
    )

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is a concrete tool-parameter abuse issue: the skill passes a potentially attacker-influenced file path into a Windows shell invocation. Because shell=True routes execution through cmd.exe, special characters in the path can alter command semantics and lead to arbitrary command execution on the local machine.

Content

Scanner excerpt · scripts/convert_pdf_to_ppt.py (reported line 48)May include surrounding context.

python
elif system == "Linux":
            subprocess.run(["xdg-open", path], check=True, capture_output=True)
        elif system == "Windows":
            subprocess.run(["start", "", path], check=True, shell=True, capture_output=True)
    except subprocess.CalledProcessError:
        pass

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill invokes shell commands, reads environment variables, uploads files, writes output files, and performs network operations, yet it declares no explicit tool permissions or allowed-tool scope. That increases the blast radius if the skill is invoked in a permissive runtime, because users and orchestrators are not clearly informed of the capabilities being exercised.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill states that local PDFs are uploaded and remote URLs are passed through, but it does not require any explicit user warning or consent before transmitting document contents to an external service. This can expose sensitive or regulated data if a user assumes processing is local or does not realize a public-facing URL may be returned.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
88% confidence
Finding

The skill permits uv to create a local environment, install dependencies, and even download Python on first run, which introduces persistent changes to the host and pulls executable components from external sources. In constrained or enterprise environments, that can violate change-control expectations and increase supply-chain exposure if the runtime bootstrap is not explicitly approved.

Content

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

md
This package currently targets the production PPT service at `https://ppt.mustgoai.com`. Override `GOAI_BASE_URL` only when you intentionally need a different endpoint.

This skill now uses a single cross-platform Python entrypoint through `uv`. Treat `uv` as the only runtime dependency the user needs to install manually. On first run, `uv` may create a local environment, install `httpx`, and download Python if the machine does not already have a usable interpreter. That first-run setup is expected and should not be described as an error.

# Script Rules

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

md
- macOS: `brew install uv`
- Windows: `winget install astral-sh.uv`

After `uv` is installed, rerun the same command. Do not ask the user to install Python packages by hand; `uv` is responsible for preparing Python and the skill dependencies.

If execution reports a missing Python module such as `httpx`, do not run `pip install`, `pip install --user`, or `pip install --break-system-packages`. Re-run the skill through `uv`; the dependency set comes only from `pyproject.toml` and `uv.lock`.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code uploads a user-supplied local file to a remote signed URL and returns a remote final URL, but the function itself provides no explicit disclosure, consent check, or policy guard before exfiltrating local content. In a skill that may be invoked by an agent on behalf of a user, that increases the risk of unintended transmission of sensitive local documents if the calling layer passes a local path without clearly informing the user.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This function has the same security property as the image uploader: it reads a local file path, obtains a signed remote upload URL, and transmits the file contents off-host without any built-in warning or confirmation step. Because this skill is specifically for converting PDFs to PPT via an external API, local PDFs may contain confidential data, so silent upload is materially risky in agent workflows.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The CLI sets --language to zh by default, which forces a specific language/locale choice unless the user explicitly overrides it. The policy allows locale constraints only when they are opt-in or clearly justified, neither of which is evident in this file.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill automatically launches the generated PPT in a local application, which exceeds the stated purpose of converting and downloading a file. Opening untrusted office documents can trigger local attack surface in the associated application, surprise the user, and reduce the containment expected from a conversion tool.

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

python
system = platform.system()
    try:
        if system == "Darwin":
            subprocess.run(["open", path], check=True, capture_output=True)
        elif system == "Linux":
            subprocess.run(["xdg-open", path], check=True, capture_output=True)
        elif system == "Windows":

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

python
if system == "Darwin":
            subprocess.run(["open", path], check=True, capture_output=True)
        elif system == "Linux":
            subprocess.run(["xdg-open", path], check=True, capture_output=True)
        elif system == "Windows":
            subprocess.run(["start", "", path], check=True, shell=True, capture_output=True)
    except subprocess.CalledProcessError:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

On Windows the code uses subprocess.run with shell=True and includes a path derived from remote content, which creates a command-injection risk if the filename or path contains shell-metacharacters interpreted by cmd.exe. In this skill, the file is downloaded from an API-controlled URL and then auto-opened, so a malicious or compromised upstream service could potentially influence the saved path and trigger arbitrary command execution.

Content

Scanner excerpt · scripts/convert_pdf_to_ppt.py (reported line 48)May include surrounding context.

python
elif system == "Linux":
            subprocess.run(["xdg-open", path], check=True, capture_output=True)
        elif system == "Windows":
            subprocess.run(["start", "", path], check=True, shell=True, capture_output=True)
    except subprocess.CalledProcessError:
        pass

Unverifiable Dependency: httpx has 2 known advisory(ies) (CVE-2021-41945 (Improper Input Validation in httpx); CVE-2021-41945 (Encode OSS httpx <=1.0.0.beta0 is affected by improper input validation in `http)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code downloads remote content from a URL and writes it directly to a local path with no explicit user-facing warning and no validation of content type, size, or destination safety. While writing an output file is expected for a conversion skill, this still creates risk of unexpected local file creation or overwrite in agent contexts if the output path or media URL is not tightly controlled by the caller.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.