Back to skill

Security audit

Moark Ocr

Security checks for vulnerabilities and agentic risk

Overview

This OCR skill has a coherent purpose, but it can upload arbitrary local files or URLs to an external OCR provider with weak input boundaries and avoidable credential-handling risks.

Review before installing. Use this only with non-sensitive images you intentionally want to send to Gitee AI, prefer GITEEAI_API_KEY over passing keys on the command line, avoid remote/internal URLs, and run it in a restricted workspace or virtual environment with pinned dependencies.

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_ocr.py:70
Finding

Arbitrary Local Files Can Be Uploaded to the External OCR Service

Content
View full analysis

Vulnerability Details

File Location: scripts/perform_ocr.py, lines 70–113
Vulnerability Type: Insufficient input validation leading to unauthorized file disclosure
Risk Level: High

Vulnerable Code

python
try:
    filepath = args.image
    
    # Prepare image_url (support both local file paths and URLs)
    if filepath.startswith(("http://", "https://")):
        image_url = filepath
    else:
        if not os.path.exists(filepath):
            print(f"Error: Image file not found at {filepath}", file=sys.stderr)
            sys.exit(1)
        mime_type, _ = mimetypes.guess_type(filepath)
        mime_type = mime_type or "image/jpeg"
        with open(filepath, "rb") as f:
            base64_image = base64.b64encode(f.read()).decode('utf-8')
        image_url = f"data:{mime_type};base64,{base64_image}"

    response = client.chat.completions.create(
        messages=[
            {
                "role": "system",
                "content": "You are a helpful and harmless assistant. You should think step-by-step."
            },
            {
                "role": "user",
                "content": [
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": image_url
                        }
                    },
                    {
                        "type": "text",
                        "text": args.prompt
                    }
                ]
            }
        ],
        model="PaddleOCR-VL-1.5",
        stream=False,
        max_tokens=512,
        temperature=0.7,
        top_p=1,
        extra_body={
            "top_k": 1,
        },
        frequency_penalty=0,
    )

Technical Analysis

The --image argument is treated as either a URL or an arbitrary local file path. For local paths, the script checks only wh ...[truncated 2128 chars]

Remediation
View remediation

Remediation Suggestions

  • Resolve the supplied path with Path.resolve() and require it to be inside an explicitly approved image-input directory.
  • Require a regular file and reject directories, devices, sockets, and symbolic links. Where relevant, use race-resistant file opening to prevent time-of-check/time-of-use path substitution.
  • Validate the actual file signature and decode the file with a trusted image library instead of trusting its extension.
  • Permit only explicitly supported image formats and reject unknown content rather than defaulting it to image/jpeg.
  • Enforce conservative file-size and image-dimension limits before reading or uploading data.
  • Stream or size-check the input rather than loading an unrestricted file entirely into memory.
  • Clearly disclose that selected images are transmitted to Gitee AI and require confirmation before uploading local data.
  • If URL input is not essential, remove it. Otherwise, separately validate URL schemes, destinations, redirects, and network access policy.

T08 · Insecure Dependencies

Warning
Location
scripts/perform_ocr.py:2
Finding

Unpinned OpenAI Dependency Creates Supply-Chain and Reproducibility Risk

Content
View full analysis

Vulnerability Details

File Location: scripts/perform_ocr.py, lines 2–7
Vulnerability Type: Unpinned third-party dependency
Risk Level: Medium

Vulnerable Code

python
# /// script
# requires-python = ">=3.10"
# dependencies = [
#     "openai"
# ]
# ///

The installation documentation also instructs users to install an unpinned package:

bash
pip install openai

Technical Analysis

The Skill declares openai without a fixed version, compatible version range, lock file, or integrity hash. The documentation similarly installs whichever package release is current at installation time.

This makes the effective dependency graph mutable after the Skill has been reviewed. Future releases or changed transitive dependencies may introduce incompatible behavior or security defects. If the package source or a resolved dependency is compromised, package code may execute with the privileges of the user installing or running the Skill.

No dependency confusion, typosquatting, nonstandard package source, or known malicious package was identified in the reviewed files. This finding concerns unsafe dependency resolution rather than evidence that the named package is malicious.

Attack Path

  1. A user follows the documentation or runs the script through a dependency-aware launcher.
  2. The package installer resolves the latest available openai release and its transitive dependencies.
  3. A compromised, vulnerable, or behaviorally incompatible future release is selected because no reviewed version or hash is enforced.
  4. Dependency code executes during installation, import, or normal Skill operation with the executing user's privileges.

Impact Assessment

A compromised dependency could access files, environment variables such as GITEEAI_API_KEY, and network resources available to the Skill process. It could also alter OCR requests or results or execute arbitrary code under the i ...[truncated 214 chars]

Remediation
View remediation

Remediation Suggestions

  • Pin openai to a specifically reviewed version or a narrowly controlled compatible range.
  • Maintain a lock file that captures all transitive dependency versions.
  • Use package integrity hashes where supported, such as a requirements file generated for hash-checked installation.
  • Install only from the official package index or another explicitly trusted, authenticated repository.
  • Run dependency vulnerability and license scans as part of release review.
  • Test and deliberately approve dependency updates instead of resolving mutable latest versions automatically.
  • Install dependencies in an isolated, nonprivileged virtual environment.
  • Update SKILL.md so its installation command references the locked or pinned dependency set.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/perform_ocr.py:43
Finding

API Key Accepted Through Observable Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/perform_ocr.py, lines 43–46
Vulnerability Type: Insecure credential handling
Risk Level: Medium

Vulnerable Code

python
parser.add_argument(
    "--api-key", "-k",
    help="Gitee AI API key (overrides GITEEAI_API_KEY env var)"
)

The documented usage encourages this credential-passing method:

bash
python {baseDir}/scripts/perform_ocr.py --image /path/to/image.jpg --prompt "Users requirements" --api-key YOUR_API_KEY

Technical Analysis

Passing an API key through --api-key places the secret in the process command line. Depending on the platform and execution environment, command-line arguments may be visible through process inspection tools, shell history, terminal transcripts, orchestration metadata, audit records, or automation logs.

The script does not print the key, and it supports the preferable GITEEAI_API_KEY environment variable. However, both the parser and documentation promote an avoidable secret-exposure mechanism.

Attack Path

  1. A user follows the documented example and supplies a real Gitee AI key using --api-key.
  2. The shell records the command in history, or the process command line is captured by another local user, monitoring agent, job runner, or logging system.
  3. An unauthorized party retrieves the key from that record.
  4. The party uses the key against Gitee AI until it expires, is revoked, or reaches its service limits.

Impact Assessment

Exposure may permit unauthorized use of the victim's Gitee AI account within the permissions and quotas assigned to the key. Potential consequences include consumption of paid quota, access to API capabilities, service abuse attributed to the victim, and disruption through quota exhaustion.

This does not directly escalate local operating-system privileges. Its scope is bounded by the exposed API key's permissions, account controls, service-side restric ...[truncated 20 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the --api-key option and use the existing GITEEAI_API_KEY environment variable or a platform-managed secret provider.
  • If interactive entry is required, read the credential with a non-echoing mechanism such as getpass, without placing it in process arguments.
  • Revise SKILL.md to remove examples that place real credentials on the command line.
  • Warn users not to include API keys in shell commands, prompts, logs, or source-controlled configuration.
  • Use narrowly scoped, short-lived keys where the service supports them.
  • Ensure CI and orchestration environments inject secrets through protected secret stores and redact them from logs.
  • Rotate any key that has already been passed through a command line or retained in shell history.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
Findings (6)

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_ocr.py (reported line 24)May include surrounding context.

python
from openai import OpenAI

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
88% confidence
Finding

The skill uses environment-based secrets and invokes a bundled script that interacts with an external API, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization and transparency gap: an agent may access sensitive environment data or execute code paths without a clearly bounded capability declaration, increasing the chance of unintended secret exposure or unsafe execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill sends user-supplied images and prompts to an external GITEE AI API, but the description does not clearly warn users that their content leaves the local environment. This is dangerous because images and prompts may contain sensitive personal, business, or regulated data, and users cannot provide informed consent if the external transmission is not prominently disclosed.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The script accepts arbitrary http/https URLs in addition to local image paths, causing user-supplied remote resources to be fetched by an external OCR provider. This expands the skill from local OCR into network retrieval and third-party data disclosure, which can expose internal-only URLs, sensitive query strings, or unintended remote content to the provider.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The skill's stated purpose is OCR on images, but the implementation also accesses process environment state to obtain credentials. While convenient for configuration, reading environment variables is a broader capability than the manifest communicates and is not inherent to OCR itself.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script sets a default OCR instruction in Chinese ("请提取这张图片中的所有文字内容。") without giving the user any explicit language or locale choice. This creates a natural-language locale policy concern because the skill implicitly prefers one language by default rather than being neutral or opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.