Back to skill

Security audit

image-reader-xytest

Security checks for vulnerabilities and agentic risk

Overview

The skill does the OCR task it advertises, but it under-discloses that recognized text is saved locally to a predictable file and that selected images are uploaded to OCR.space.

Install only if you are comfortable sending selected images to OCR.space and having extracted text saved locally under the skill's scripts directory. Avoid using it on IDs, credentials, medical, financial, legal, or confidential business images unless third-party processing and local plaintext retention are acceptable.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/ocr_image.py:9
Finding
Undocumented Plaintext Persistence and Silent Overwrite of OCR Results## Vulnerability Details **File Location**: `scripts/ocr_image.py`, lines 9 and 35-38 **Vulnerability Type**: Unexpected plaintext storage of potentially sensitive OCR data **Risk Level**: Medium ### Vulnerable Code ```python img_name = os.path.splitext(os.path.basename(img_path))[0] output_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), f'{img_name}_ocr.txt') ``` ```python if 'ParsedResults' in result: with open(output_path, 'w', encoding='utf-8') as f: for r in result['ParsedResults']: f.write(r['ParsedText']) print(f'[OCR识别完成,保存到 {output_path}]') ``` ### Technical Analysis The packaged script automatically writes OCR output to a predictable plaintext file under the Skill's `scripts` directory. This differs from the documented workflow in `SKILL.md`, which states that the recognition result is returned and whose embedded example prints the result rather than persisting it. OCR output may contain credentials, personal information, financial records, or other confidential text extracted from an image. Automatically retaining that text creates an unexpected data artifact. The use of write mode (`'w'`) also silently truncates an existing file with the same generated name. The static pre-scan's Base64 concern was reviewed separately. The image is converted to JPEG, Base64-encoded, and submitted over HTTPS to the explicitly declared OCR.space API. Base64 is required as part of the API payload format and is not used here to conceal unrelated data. No collection of credentials, environment variables, or unrelated local files was identified. ### Attack Path 1. A user invokes the Skill with an image containing sensitive information. 2. The script opens and transforms the selected image. 3. The transformed image is sent to the declared OCR.space endpoint for recognition. 4. The returned OCR text is written automatically to `scripts/<image-name>_ocr.txt`. 5. Any local user or process able to read that location ma ...[truncated 681 chars]
Remediation
## Remediation Suggestions - Return OCR text to standard output by default, matching the documented behavior. - Require an explicit command-line option before writing results to disk. - Let the caller choose the destination instead of writing into the installed Skill directory. - Refuse to overwrite an existing file unless an explicit overwrite flag is supplied. - Create output files with restrictive permissions where supported. - Clearly document data retention, destination, overwrite behavior, and the fact that selected images are transmitted to OCR.space. - Warn users not to submit sensitive images unless third-party processing and retention terms are acceptable. - Handle partial API responses and file-writing errors without leaving misleading or incomplete artifacts.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (9)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill performs network access and instructs users to create a script file, but the manifest does not declare tool scope or permissions. This weakens reviewability and informed consent because users and hosting systems cannot easily see that local image data may be transmitted externally and that code has broader capabilities.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The script reads a local image and sends its contents to the third-party OCR.space service, but the skill text does not clearly warn users that image data leaves the local environment. This is dangerous because images may contain sensitive personal, financial, medical, or confidential business information, causing privacy and data-governance violations.

External Transmission

Medium
Category
Data Exfiltration
Content
img_small.save(buf, format='JPEG', quality=80)
b64_data = base64.b64encode(buf.getvalue()).decode()

url = 'https://api.ocr.space/parse/image'
params = urllib.parse.urlencode({
    'base64Image': 'data:image/jpeg;base64,' + b64_data,
    'language': 'chs',
Confidence
96% confidence
Finding
The code transmits base64-encoded image contents to an external endpoint at api.ocr.space. In the context of a local image-reading skill, this is more dangerous because users may reasonably expect local processing, while the uploaded images can contain sensitive information and leave the trust boundary.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The script hard-codes the OCR language parameter to 'chs', and the surrounding text emphasizes Chinese support, but nowhere offers the user a language selection or explains that the skill is intentionally limited to Chinese-only use. This is a natural-language locale policy issue because the behavior imposes a specific language setting without user opt-in.

External Transmission

Medium
Category
Data Exfiltration
Content
img_small.save(buf, format='JPEG', quality=80)
b64_data = base64.b64encode(buf.getvalue()).decode()

url = 'https://api.ocr.space/parse/image'
params = urllib.parse.urlencode({
    'base64Image': 'data:image/jpeg;base64,' + b64_data,
    'language': 'chs',
Confidence
95% confidence
Finding
This skill transmits local image data to an external service over the network. In the context of an image reader for local files, that creates real confidentiality risk because users may process sensitive images and may not expect exfiltration to a third party, especially with a hard-coded public API key and no warning.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The script sends the full image contents to a third-party OCR API, which can expose sensitive local data contained in screenshots, documents, IDs, or other images. In a local-image-reading skill, this is especially significant because users may reasonably expect processing to remain local unless clearly told otherwise.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The request parameter sets language to 'chs', forcing a specific locale regardless of user preference. This is a natural-language policy concern because the skill does not provide opt-in, selection, or a documented region-specific justification.

Tainted flow: 'output_path' from sys.stdin.read (line 10, user input) → open (file write)

Medium
Category
Data Flow
Content
raw = resp.read()
    result = json.loads(raw.decode('utf-8', errors='replace'))
    if 'ParsedResults' in result:
        with open(output_path, 'w', encoding='utf-8') as f:
            for r in result['ParsedResults']:
                f.write(r['ParsedText'])
        print(f'[OCR识别完成,保存到 {output_path}]')
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The program derives an output path and later writes OCR results to that file, but the write behavior is not disclosed until after completion. For this code file, there is no prior prompt, explanatory comment, or docstring warning about creating or overwriting a local file.

Static analysis

No suspicious patterns detected.