Back to skill

Security audit

Ghost Eye

Security checks for vulnerabilities and agentic risk

Overview

Ghost Eye does what it says, but it can automatically send every inbound image to a third-party vision API and stores OCR results in plaintext by default.

Review this skill before installing. Use explicit tool-call mode instead of global auto-preprocess for sensitive work, set an approved vision endpoint, avoid --image-url unless network egress is constrained, and disable or regularly clear caching when images may contain personal, business, credential, or regulated data.

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

Warning
Location
scripts/analyze.py:103
Finding
Unrestricted Image URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analyze.py:103-106` **Vulnerability Type**: Server-Side Request Forgery and unbounded remote resource loading **Risk Level**: Medium ### Vulnerable Code ```python if args.image_url: req = urllib.request.Request(args.image_url, headers={"User-Agent": "OpenClaw-NexN2/1.0"}) with urllib.request.urlopen(req, timeout=30) as resp: return resp.read() ``` ### Technical Analysis The `--image-url` argument is passed directly to `urllib.request.urlopen` without validating its scheme, destination host, resolved IP address, port, or redirect chain. The implementation does not reject loopback, private, link-local, or reserved network ranges. Although the downloaded data is subsequently checked for image magic bytes, that validation occurs only after the network request and response have completed. It therefore cannot prevent requests from reaching internal services. Internal endpoints returning valid image data could also have their contents processed and transmitted to the configured external vision provider. The response is read in full with `resp.read()` and has no maximum-size restriction. An attacker-controlled endpoint can consequently return an excessively large response and consume substantial process memory. ### Attack Path 1. An attacker or untrusted caller supplies an `--image-url` value targeting a service reachable from the Skill host, such as a loopback address, private-network service, or cloud-local endpoint. 2. The Skill resolves and requests that URL using the host's network access. 3. Redirects may move the request to another internal destination because redirect targets are not revalidated. 4. The entire response is loaded into memory before image validation. 5. If the response contains valid image bytes, its content is Base64-encoded and sent to the configured vision API for OCR and description. 6. The resulting OCR or description is returned to the caller and cached, ...[truncated 945 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Permit only explicitly supported schemes, preferably HTTPS. 2. Resolve the destination hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6. 3. Disable automatic redirects or validate the scheme, hostname, port, and resolved address of every redirect target. 4. Consider an allowlist of trusted image hosts when the deployment permits it. 5. Enforce a strict maximum download size using `Content-Length` where available and incremental bounded reads regardless of that header. 6. Apply separate connection and read timeouts. 7. Restrict destination ports to expected web ports. 8. Run the Skill with network-level egress controls that prevent access to internal services and metadata endpoints. 9. Reject URLs containing embedded credentials and normalize hostnames before validation. 10. Perform content-type and magic-byte validation while streaming, terminating the request as soon as it exceeds limits or fails validation. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/analyze.py:71
Finding
OCR and Image Analysis Results Are Persisted in Plaintext by Default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analyze.py:71-88` **Vulnerability Type**: Insecure storage of potentially sensitive derived image data **Risk Level**: Medium ### Vulnerable Code ```python def _cache_set(md5_hash: str, content: str, model: str, tokens: int): if _env("NEXN2_CACHE_ENABLE", "true").lower() != "true": return os.makedirs(CACHE_DIR, exist_ok=True) ttl_days = int(_env("NEXN2_CACHE_TTL_DAYS", "7")) now = datetime.now(timezone.utc) entry = { "content": content, "cached_at": now.isoformat(), "expires_at": (now + timedelta(days=ttl_days)).isoformat(), "model": model, "tokens_used": tokens, } with open(_cache_path(md5_hash), "w") as f: json.dump(entry, f, ensure_ascii=False) ``` ### Technical Analysis Caching is enabled by default, and the model's complete OCR and visual-analysis output is written as plaintext JSON beneath the project directory. Such output may contain document text, contact details, account information, private correspondence, screenshot contents, or other sensitive information visible in an image. The implementation relies on process defaults for directory and file permissions rather than explicitly creating a private cache directory and owner-only files. In shared or permissively configured environments, other local users or processes may be able to read the cached output. Expired records are deleted only when `_cache_get` is called for the corresponding MD5 key. There is no general cleanup process, so cache records may remain on disk beyond their declared expiration if the same image is not requested again. The audited package also contains three plaintext cache records, demonstrating that runtime-derived OCR data can be retained and included in a distributed artifact. ### Attack Path 1. A user submits an image containing sensitive visual or textual information. 2. The image is analyzed by the remote vision model. ...[truncated 1113 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable caching by default and require explicit opt-in, particularly for screenshots, identity documents, financial records, and other sensitive images. 2. Store runtime data outside the distributable Skill source tree in an operating-system-managed private cache directory. 3. Create the cache directory with owner-only permissions such as `0700`. 4. Create cache files atomically with owner-only permissions such as `0600`, rather than relying on the ambient `umask`. 5. Encrypt cached content at rest when the deployment threat model includes other local principals, backups, or shared storage. 6. Implement periodic cleanup that removes every expired entry independently of whether the same image is requested again. 7. Exclude `cache/*.json` and other runtime artifacts from source-control, release, and packaging workflows. 8. Purge the three cache records already included in the audited artifact before publication. 9. Provide an explicit cache-clear command and document the privacy implications and retention period. 10. Consider caching only non-sensitive metadata or a user-approved subset instead of complete OCR output. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (19)

Missing User Warnings

High
Confidence
98% confidence
Finding
The auto-preprocess mode explicitly says the skill fires automatically on inbound images and 'the user never knows it's there,' while sending those images to an external vision model. Hidden third-party processing of user images is a serious privacy and consent issue, especially because images may contain sensitive personal, financial, or confidential business information.

Self-Modification

High
Category
Rogue Agent
Content
{"content": "【OCR文字提取】\n\n← Back to Ghost Eye\n\n# Skill settings\n\nIntegrations  \nAutomation  \nResearch  \nDevelopment  \nProductivity  \nCommunication  \nCreative  \nKnowledge  \nAgents  \nOperations  \nSecurity  \nFinance  \nLifestyle  \n✓ Other\n\nUpdate skill files\n\n## Publish a new version\n\nUpload a replacement release for this skill. New releases get a fresh scan.\n\nNew Version\n\n## Short summary\n\nUpdate the short summary used in cards, search, and previews.\n\nages through any vision model. OCR + visual\n\nSave\n\n## Catalog metadata\n\nChoose browse categories and author topics for this skill.\n\nOther\n\n## TOPICS\n\nAdd a topic\n\n【画面内容总结】\n\n1. 核心主题:  \n   图片展示的是一个名为 “Skill settings” 的技能设置页面,用户正在编辑或配置某个技能的基本信息、分类、摘要、版本发布和主题等元数据。\n\n2. 元素与布局:  \n   - 页面左上角有返回入口 “Back to Ghost Eye”。  \n   - 主标题为 “Skill settings”。  \n   - 页面主要分为左侧设置说明区和右侧操作/输入区。  \n   - 中间偏上位置弹出了一个分类选择下拉菜单,包含 Integrations、Automation、Research、Development、Productivity、Communication、Creative、Knowledge、Agents、Operations、Security、Finance、Lifestyle、Other 等分类。  \n   - 下拉菜单中 “Automation” 被红色边框高亮,表示当前鼠标悬停或正在选择该项。  \n   - 下方当前选中的分类显示为 “Other”,并带有勾选标记。  \n   - 页面右侧有 “Update skill files”、“New Version”、“Save” 等操作按钮。  \n   - 页面底部有 “TOPICS” 主题输入框,占位文字为 “Add a topic”。\n\n3. 关键信息提炼:  \n   - 当前页面用于配置技能设置。  \n   - 用户正在从分类下拉菜单中选择 “Automation”,但当前已选分类仍显示为 “Other”。  \n   - 页面支持发布新版本、更新技能文件、编辑短摘要、设置目录分类和添加主题。  \n   - “Automation” 是下拉菜单中被重点标记的选项,说明用户可能准备将技能分类从 “Other” 改为 “Automation”。", "cached_at": "2026-07-09T15:38:45.194194+00:00", "expires_at": "2026-07-16T15:38:45.194194+00:00", "model": "nex-agi/Nex-N2-Pro", "tokens_used": 4393}
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill documentation describes capabilities to read local files, access environment variables, and send image content over the network, but it does not declare any explicit permission or allowed-tools scope. That gap weakens security review and policy enforcement because operators cannot clearly see or constrain what the skill is allowed to access before enabling it.

Unbounded Output

Medium
Category
Output Handling
Content
⛔ Always prefer `--image-path` to avoid command-line `Argument list too long` errors with large base64 strings. Only fall back to `--image-url` or `--image-base64` when no local path is available.

```bash
# Preferred: local file path (no size limit)
python3 {baseDir}/scripts/analyze.py --image-path "<absolute path>"

# Fallback: public URL
Confidence
75% confidence
Finding
Documenting image-path input as having 'no size limit' suggests the skill may accept arbitrarily large local files for processing. Even with later compression, unbounded intake can enable denial-of-service through oversized or decompression-heavy images that consume memory, CPU, disk, or API quota.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The example success output uses Chinese section headers, and the documentation explicitly says missing API key errors return a friendly Chinese message. This indicates a language choice is being imposed by default rather than offering the user's preferred language or documenting a justified locale restriction.

External Transmission

Medium
Category
Data Exfiltration
Content
| Variable | Required | Default |
|----------|----------|---------|
| NEXN2_API_KEY | ✅ Yes | — |
| NEXN2_BASE_URL | No | https://api.siliconflow.cn/v1 |
| NEXN2_MODEL_NAME | No | nex-agi/Nex-N2-Pro |
| NEXN2_PROMPT_TEMPLATE | No | Built-in structured template |
| NEXN2_IMAGE_COMPRESS | No | true |
Confidence
92% confidence
Finding
The skill is designed to transmit image data to an external API endpoint, which is a real data egress behavior. In context this is expected functionality, but it remains security-relevant because the transmitted images may contain sensitive content and the default remote endpoint is third-party infrastructure.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The line states that if the API key is missing, the skill returns a friendly Chinese error message. This is a natural-language policy issue because it fixes a specific language for user-facing output without opt-in or justification.

External Transmission

Medium
Category
Data Exfiltration
Content
"enabled": true,
  "apiKey": { "source": "env", "provider": "default", "id": "NEXN2_API_KEY" },
  "env": {
    "NEXN2_BASE_URL": "https://api.siliconflow.cn/v1",
    "NEXN2_MODEL_NAME": "nex-agi/Nex-N2-Pro",
    "NEXN2_IMAGE_COMPRESS": "true",
    "NEXN2_CACHE_ENABLE": "true",
Confidence
92% confidence
Finding
The setup example hardcodes a default third-party base URL, reinforcing that image content will be sent off-box unless reconfigured. Although this aligns with the skill's purpose, it still creates a genuine confidentiality and compliance risk if users are unaware or cannot constrain where their images go.

Vague Triggers

Medium
Confidence
87% confidence
Finding
This JSON file is a manifest-like cache record containing the skill's descriptive content, but it does not define when the skill should activate or what phrases should invoke it. Without explicit trigger scope or exclusion conditions, the activation semantics are ambiguous and could lead to unintended invocation if this content is reused as metadata.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The natural-language content and headings in the stored skill description are exclusively Chinese, including the skill title and summary text. There is no indication that users can opt into this language or that the skill is intentionally restricted to a Chinese-language audience for a documented reason.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation instructs users to enable automatic image preprocessing that sends image content to an external vision model, but it does not warn that screenshots, photos, or documents may contain sensitive personal, corporate, or regulated data. Because this is a global automatic flow, users may unknowingly transmit private content off-platform, increasing privacy and compliance risk.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The tool-call guidance tells the system to analyze user-submitted images and screenshots via an external service, but omits any notice that the image contents and OCR text will leave the local environment. This can cause inadvertent disclosure of sensitive information embedded in screenshots or documents, especially when the instruction is reused verbatim by integrators.

External Transmission

Medium
Category
Data Exfiltration
Content
Environment:
  NEXN2_API_KEY        required
  NEXN2_BASE_URL        default https://api.siliconflow.cn/v1
  NEXN2_MODEL_NAME      default nex-agi/Nex-N2-Pro
  NEXN2_PROMPT_TEMPLATE  optional custom prompt
  NEXN2_IMAGE_COMPRESS  default true
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
Environment:
  NEXN2_API_KEY        required
  NEXN2_BASE_URL        default https://api.siliconflow.cn/v1
  NEXN2_MODEL_NAME      default nex-agi/Nex-N2-Pro
  NEXN2_PROMPT_TEMPLATE  optional custom prompt
  NEXN2_IMAGE_COMPRESS  default true
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
Environment:
  NEXN2_API_KEY        required
  NEXN2_BASE_URL        default https://api.siliconflow.cn/v1
  NEXN2_MODEL_NAME      default nex-agi/Nex-N2-Pro
  NEXN2_PROMPT_TEMPLATE  optional custom prompt
  NEXN2_IMAGE_COMPRESS  default true
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The cache stores extracted analysis content and metadata on local disk without any notice, encryption, access control hardening, or content sensitivity checks. OCR output can contain secrets, personal data, or regulated information, so persisting it silently increases the exposure window beyond the original API call.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The default prompt explicitly instructs the model to produce output in Chinese, and multiple user-facing error messages are also hard-coded in Chinese. This imposes a specific language/locale without any opt-in, language selection mechanism, or documented region-specific justification, which matches the language-policy violation criterion.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script sends full image contents to a third-party API endpoint for analysis, but the code contains no consent, disclosure, or policy gate before transmission. Because images may contain sensitive personal, business, or credential information, silent exfiltration to an external service creates a real privacy and data-handling risk in this skill context.

Intent-Code Divergence

Low
Confidence
93% confidence
Finding
The top-level docstring presents this file as a different tool/product name rather than the declared skill name. While the code still performs image analysis, the embedded documentation contradicts the stated skill identity and creates intent ambiguity about what component this actually is.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
SKILL.md:31