Back to skill

Security audit

BluTranslate

Security checks for vulnerabilities and agentic risk

Overview

The skill is a real Bluente file-translation helper, but its instructions can upload whole folders to a third party, overwrite original documents, and leave the API key in a generated script.

Review before installing or using. Only run it on documents you are allowed to send to Bluente, prefer a separate output directory, keep backups of originals, avoid pointing it at broad folders unless you have reviewed the file list, and rotate the Bluente API key if it was written into a generated script or logs.

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
SKILL.md:58
Finding
Plaintext API Key Embedded in Generated Script<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:58-60` **Vulnerability Type**: Plaintext credential exposure **Risk Level**: Medium ### Vulnerable Code ```python API_KEY = "<API_KEY>" BASE = "https://api.bluente.com/api/20250924/blu_translate" HEADERS = {"Authorization": f"Bearer {API_KEY}"} ``` ### Technical Analysis The Skill instructs the agent to substitute the user's Bluente API key directly into a generated Python script. This leaves the bearer credential in plaintext source code. Depending on how the agent creates and executes the script, the credential may persist in the workspace, temporary files, backups, source-control history, agent transcripts, or tool logs. File permissions are not restricted, and the instructions do not require deletion of the generated script after execution. Sending the key to Bluente in an authorization header is necessary for the declared cloud translation function. Persistently embedding it in generated code is not necessary and exceeds minimum secure credential-handling requirements. ### Attack Path 1. A user provides a valid Bluente API key to the Skill. 2. The agent inserts the key into the generated Python script as `API_KEY = "..."`. 3. The script or its contents remain accessible through the workspace, logs, backups, source control, or agent execution history. 4. An attacker with access to one of those locations extracts the bearer token. 5. The attacker submits authenticated requests to Bluente using the compromised token. ### Impact Assessment Successful exploitation exposes the privileges granted to the Bluente API key. An attacker could consume translation services, incur usage against the victim's account, and potentially access other account-scoped API resources available to that credential. This issue does not grant local operating-system privilege escalation by itself. Its scope is limited primarily to the API permissions associated with the exposed key. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pass the API key through a protected environment variable or standard input rather than embedding it in source code: ```python import os API_KEY = os.environ["BLUENTE_API_KEY"] HEADERS = {"Authorization": f"Bearer {API_KEY}"} ``` 2. Set the environment variable only for the lifetime of the process and avoid placing it in shell history. 3. Never print the key or include authorization headers in errors, debug output, or result summaries. 4. If a temporary script is required, create it with permissions restricted to the current user, such as mode `0600`. 5. Delete temporary scripts and clear temporary environment state immediately after execution. 6. Advise users to rotate any API key that may have been persisted or exposed. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:26
Finding
Translated Output Can Overwrite and Destroy Source Files<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:26, 131-132` **Vulnerability Type**: Unsafe output-path handling and destructive file overwrite **Risk Level**: High ### Vulnerable Code The Skill explicitly allows the output directory to be the source directory: ```text - Options: "Same folder as source" (description: "Save next to the originals"), "Enter path" (description: "I'll specify a custom path in the Other field") ``` The downloaded file is then written using the unchanged source filename: ```python out_path = os.path.join(OUTPUT_DIR, filename) with open(out_path, "wb") as f: f.write(r.content) ``` ### Technical Analysis When `OUTPUT_DIR` is the same directory as the source file, `out_path` resolves to the original source pathname because `filename` is not modified. Opening that path with `"wb"` immediately truncates the original file before writing the downloaded response. The code also fails to call `raise_for_status()`, check the response status, validate the response content type, or verify that the response is a valid translated document. Consequently, an HTTP error page, JSON error response, empty body, or truncated download can replace the original document. The write is performed directly rather than through a temporary file followed by an atomic rename. A network interruption or process termination can therefore leave a partially written and corrupted file. ### Attack Path 1. The user chooses **Same folder as source** for the output location. 2. The Skill uploads a source document and later requests the translated result. 3. The output path is constructed using the source directory and the original filename. 4. The output path consequently equals the source path. 5. `open(out_path, "wb")` truncates the original document. 6. The HTTP response body is written in its place, even if the response is invalid, incomplete, or an API error. 7. The original file is irreversibly lost unless an independent backup exists. ## ...[truncated 496 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Always generate a distinct translated filename, for example: ```python stem, suffix = os.path.splitext(filename) out_path = os.path.join(OUTPUT_DIR, f"{stem}_{TO_LANG}{suffix}") ``` 2. Resolve and compare canonical paths before writing, and reject any output path equal to a source path: ```python if os.path.realpath(out_path) == os.path.realpath(filepath): raise ValueError("Output path must not overwrite the source file") ``` 3. Validate the download before creating the destination file: ```python r.raise_for_status() ``` 4. Check the expected content type, reject empty responses, and validate the downloaded document format where practical. 5. Write the response to a uniquely named temporary file in the destination directory. 6. Flush and synchronize the temporary file, validate it, and then atomically rename it to the final non-source destination. 7. If the desired destination already exists, prompt for confirmation or create a collision-resistant filename instead of overwriting it silently. 8. Preserve source files unchanged and report failed downloads without creating or replacing output documents. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (5)

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The skill instructs users to translate local files through a third-party API but does not clearly warn that document contents will be uploaded off-system. This creates a real privacy and data-handling risk because users may submit sensitive documents without informed consent.

External Transmission

Medium
Category
Data Exfiltration
Content
If the user picks a language NOT in this list, call the supported languages endpoint:
```
GET https://api.bluente.com/api/20250924/blu_translate/supported_languages
Header: Authorization: Bearer <API_KEY>
```
Response format: `{"message": "success", "code": 0, "data": [{"name": "French", "svcCode": "fra", ...}, ...]}`
Confidence
50% 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
If the user picks a language NOT in this list, call the supported languages endpoint:
```
GET https://api.bluente.com/api/20250924/blu_translate/supported_languages
Header: Authorization: Bearer <API_KEY>
```
Response format: `{"message": "success", "code": 0, "data": [{"name": "French", "svcCode": "fra", ...}, ...]}`
Confidence
50% 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
import requests, time, sys, os

API_KEY = "<API_KEY>"
BASE = "https://api.bluente.com/api/20250924/blu_translate"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
FILES = [<list of absolute file paths>]
FROM_LANG = "en"  # or other source language code
Confidence
90% confidence
Finding
The embedded script is designed to upload local files to an external translation service using a bearer API key, creating a real data exfiltration path from the user's machine to a third party. Although this is aligned with the skill's function, it remains security-relevant because the files may contain sensitive information and the script encourages bulk processing of folders.

External Transmission

Medium
Category
Data Exfiltration
Content
continue

    # Start translation
    r = requests.post(f"{BASE}/translate?engine=3", headers=HEADERS,
                      json={"id": task_id, "action": "start", "from": FROM_LANG, "to": TO_LANG})
    resp = r.json()
    if resp.get("code") != 0:
Confidence
92% confidence
Finding
This step initiates translation of user-provided document content via an external API, which necessarily sends potentially sensitive file contents and language metadata to a third party. In the context of a file-handling skill, that is dangerous if not tightly disclosed and consented to, especially for proprietary or regulated documents.

Static analysis

No suspicious patterns detected.