Back to skill

Security audit

Moark Doc Extraction

Security checks for vulnerabilities and agentic risk

Overview

This document OCR skill mostly matches its purpose, but it needs Review because it can fetch arbitrary URLs from the user's environment and upload the retrieved content to Gitee AI without clear scoping or safeguards.

Review before installing or running on sensitive documents. Prefer setting GITEEAI_API_KEY through a protected environment or secret manager instead of --api-key, avoid giving the tool URLs, and only process documents you are comfortable sending to Gitee AI. Run it in a restricted network environment if possible.

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/perform_doc_extraction.py:51
Finding

Unrestricted URL Fetching Enables SSRF and Internal Data Disclosure

Content
View full analysis

Vulnerability Details

File Location: scripts/perform_doc_extraction.py:51-54 and scripts/perform_doc_extraction.py:155-159
Vulnerability Type: Server-Side Request Forgery and unintended data disclosure
Risk Level: High

Vulnerable Code

python
if filepath.startswith(("http://", "https://")):
    response = requests.get(filepath, timeout=10)
    response.raise_for_status()
    fields.append(("file", (name, response.content, response.headers.get("Content-Type", "application/octet-stream"))))
python
elif "file_url" in output_data:
    file_url = output_data["file_url"]
    print(f"Downloading result from: {file_url}", file=sys.stderr)
    doc_response = requests.get(file_url)
    doc_response.raise_for_status()
    final_text = doc_response.text

Technical Analysis

The script accepts an arbitrary HTTP or HTTPS URL through --file and retrieves it from the environment where the Skill runs. It does not validate the destination hostname, resolved IP address, port, redirect chain, response type, or response size.

Consequently, the request can target loopback addresses, private network ranges, link-local services, cloud instance metadata endpoints, or internal administrative interfaces. Automatic redirects and DNS changes may also allow an initially public hostname to resolve or redirect to a prohibited internal address.

The content obtained through --file is subsequently inserted into the multipart request and uploaded to the external Gitee AI service. This turns the issue into both SSRF and potential internal-data exfiltration.

The API-controlled file_url is also fetched without a host allowlist. That request has no explicit timeout or response-size limit, creating additional exposure to internal resource access and denial of service.

Attack Path

  1. An attacker causes the Skill to run with a URL such as a loopback, private-network, link-local, metadata-service, or attacker-controlled redirect URL.

...[truncated 1059 chars]

Remediation
View remediation

Remediation Suggestions

  • Prefer accepting local document files only unless remote URL support is essential.
  • If remote URLs are required, enforce an explicit allowlist of trusted HTTPS hosts.
  • Resolve hostnames before connecting and reject loopback, private, link-local, multicast, reserved, and cloud metadata addresses.
  • Disable redirects or validate the hostname and resolved address at every redirect hop.
  • Restrict destination ports to those explicitly required.
  • Protect against DNS rebinding by ensuring the validated address is the address used for the connection.
  • Stream responses while enforcing a strict maximum size instead of reading the complete body into memory.
  • Validate expected document MIME types and file signatures before uploading content.
  • Configure explicit connection and read timeouts for every request.
  • Require result URLs to use HTTPS and belong to documented Gitee AI result-delivery domains.
  • Consider returning an error instead of fetching any API-provided URL that does not meet the allowlist policy.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:22
Finding

API Key Accepted and Promoted as a Command-Line Argument

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:22 and scripts/perform_doc_extraction.py:124-126
Vulnerability Type: Insecure credential handling
Risk Level: Medium

Vulnerable Code

bash
python {baseDir}/scripts/perform_doc_extraction.py --file /path/to/document.pdf --api-key YOUR_API
python
parser.add_argument(
    "--api-key", "-k",
    help="Gitee AI API key (overrides GITEEAI_API_KEY env var)"
)

Technical Analysis

The Skill documentation instructs users to provide the Gitee AI API key directly as a command-line argument. Command-line arguments can be exposed through shell history, process inspection tools, terminal capture, orchestration telemetry, audit logs, and Agent tool-execution records.

Although the script also supports the GITEEAI_API_KEY environment variable, the primary usage example promotes the more readily exposed credential-delivery mechanism. The key is not printed directly by the script, but its presence in the process argument list is sufficient to create a disclosure risk.

Attack Path

  1. A user follows the documented command and supplies a real API key through --api-key.
  2. The complete command is retained in shell history or captured by process monitoring, terminal logging, job telemetry, or Agent execution logs.
  3. Another local user, monitoring service, log reader, or compromised process obtains the key.
  4. The exposed key is reused to issue unauthorized requests to the Gitee AI API.

Impact Assessment

Disclosure of the API key may permit unauthorized document-processing requests under the victim's account. This can consume quotas, create financial costs, interfere with service availability, and expose account-level API activity within the privileges granted to the key.

This does not directly grant operating-system privileges, but it exposes an external-service credential beyond the minimum disclosure necessary to perform document extraction.

Remediation
View remediation

Remediation Suggestions

  • Remove the API key from the documented command-line example.
  • Prefer the existing GITEEAI_API_KEY environment-variable mechanism or an approved secret manager.
  • Consider removing the --api-key option entirely to prevent accidental command-line disclosure.
  • If interactive entry is necessary, use Python's getpass module so the key is not displayed or stored in shell history.
  • Clearly document that API keys must not be placed in shell history, logs, source files, or shared configuration.
  • Ensure execution and error logging never records environment values or credential-bearing request headers.
  • Recommend narrowly scoped, revocable credentials and periodic key rotation.

T08 · Insecure Dependencies

Note
Location
scripts/perform_doc_extraction.py:3
Finding

Third-Party Dependencies Are Installed Without Version or Integrity Constraints

Content
View full analysis

Vulnerability Details

File Location: scripts/perform_doc_extraction.py:3-7 and SKILL.md:19
Vulnerability Type: Unpinned dependency and supply-chain risk
Risk Level: Low

Vulnerable Code

python
# /// script
# requires-python = ">=3.10"
# dependencies = [
#     "requests",
#     "requests-toolbelt"
# ]
# ///
bash
pip install requests requests-toolbelt

Technical Analysis

The project declares and recommends installing requests and requests-toolbelt without exact versions or package hashes. Dependency resolution can therefore select different releases over time, making installations non-reproducible and preventing verification that the installed artifacts are the versions reviewed during the audit.

An incompatible, compromised, or unexpectedly modified future package release could alter request handling or execute arbitrary package code during installation or runtime. The reviewed package names are not apparent typosquatting attempts, but the absence of version and integrity controls leaves avoidable supply-chain exposure.

Attack Path

  1. A user installs or executes the Skill in a fresh environment.
  2. The package resolver selects the latest versions available at that time rather than reviewed versions.
  3. A compromised, malicious, or incompatible dependency release is downloaded.
  4. Package installation hooks or imported runtime code execute with the privileges of the user running the Skill.
  5. The dependency may access documents, environment variables, the API key, or network communications available to the process.

Impact Assessment

A compromised dependency executes within the same process boundary as the extraction script. It could access the Gitee AI API key, read the selected document, alter network requests, manipulate extraction results, or perform actions permitted to the invoking user.

The likelihood is lower than the directly exploitable URL-fetching issue, but the potential scope ...[truncated 82 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin reviewed dependency versions rather than using unconstrained package names.
  • Maintain a lock file containing exact transitive dependency versions.
  • Use package hashes to verify artifact integrity during installation.
  • Install packages only from a trusted and explicitly configured package index.
  • Use isolated virtual environments and avoid running installation with elevated privileges.
  • Add automated dependency vulnerability and provenance scanning.
  • Review and update pinned versions on a controlled schedule after security testing.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (7)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/perform_doc_extraction.py (reported line 28)May include surrounding context.

python
def get_api_key(provided_key: str | None) -> str | None:
    """Get API key from argument, config, or environment."""
    if provided_key:
        return provided_key
    return os.environ.get("GITEEAI_API_KEY")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill invokes a Python script, requires an environment API key, and communicates with an external API, but it does not declare an explicit tool scope such as permissions or allowed-tools. This weakens containment and user transparency, making it easier for the skill to use code execution, environment access, and network access beyond what a reviewer or runtime policy may expect.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill processes user-supplied documents by sending their contents to an external GITEE AI API, but the description and usage text do not clearly warn users that potentially sensitive document data leaves the local environment. In a document-extraction context, this is especially dangerous because PDFs and DOCX files often contain confidential, personal, legal, or proprietary information, so undisclosed transmission creates a substantial privacy and compliance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script sends document contents, including embedded images and base64 image data, to an external cloud API but does not provide a clear in-tool warning or consent checkpoint about data exfiltration. In a document-processing skill, this is especially sensitive because inputs may contain confidential, regulated, or proprietary material.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script accepts arbitrary http/https URLs and fetches them server-side before uploading the content to the external OCR API. This expands a document-extraction tool into a general network retriever, which can be abused for unintended outbound requests, access to internal-only URLs if run in a trusted environment, or processing attacker-controlled remote content outside the stated local PDF/DOCX use case.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Fetching user-supplied URLs is unnecessary for the documented PDF/DOCX extraction purpose and creates SSRF-style risk when the skill runs in environments with broader network reach. Even though only http/https is allowed, the code still performs arbitrary outbound retrieval of attacker-chosen resources and then forwards the content to a third-party service.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The script blindly downloads from a file_url returned by the API without validating the destination, scheme, or size. While this URL comes from the upstream service rather than directly from the user, it still introduces secondary network access and trust in externally supplied URLs, which increases exposure if the API is compromised, misconfigured, or returns unexpected endpoints.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.