Back to skill

Security audit

Photo Retouching

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but it also ships an undisclosed Chrome DevTools automation script that can control a local browser session.

Install only if you are comfortable reviewing or removing the Chrome automation script first. Prefer RUNNINGHUB_API_KEY over --save-key, avoid putting API keys on the command line, treat uploaded images as sent to RunningHub, and do not run chrome_automation.py against a normal logged-in browser profile.

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/runninghub_client.py:29
Finding

RunningHub API Key Stored in Plaintext Without Restrictive File Permissions

Content
View full analysis
Remediation
View remediation
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
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (25)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

There is a serious description-behavior mismatch: the skill claims to perform straightforward API-based workflow execution, but static analysis indicates browser DevTools automation, localhost debugging access on 127.0.0.1:9222, raw socket use, and arbitrary JavaScript execution in a browser context. That hidden capability can be used to inspect browser state, access authenticated sessions, or manipulate local browser pages in ways unrelated to the declared purpose.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 108)May include surrounding context.

python
from runninghub_client import RunningHubClient, load_config, get_api_key

# Get API key from config
api_key = get_api_key()

# Initialize client

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill requests or implies capabilities for environment access, local file read/write, and network access without declaring any explicit tool scope or permission boundaries. In an agent setting, this increases the chance of overbroad execution and makes it harder to review or constrain what the skill can do, especially since it handles API keys and local files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill instructs users to persist an API key in a local config file but does not describe file permissions, storage protections, rotation, or multi-user access risks. Storing long-lived credentials in plaintext local configuration can expose them to other local processes, users, backups, or accidental commits.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill encourages uploading arbitrary local images to a third-party cloud service without clearly warning that local data will leave the host and be stored or processed remotely. This can lead to unintended disclosure of sensitive images, embedded metadata, or proprietary content.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill claims to execute RunningHub ComfyUI workflows via API, but this script instead drives a local Chrome instance through the DevTools debugging interface. That materially expands capability from API usage into browser/session control, allowing interaction with logged-in pages and local user context in ways the stated skill purpose does not justify.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script creates pages in a local Chrome instance, connects to the DevTools socket, enables privileged domains, and executes JavaScript in-page. For an API-oriented skill, this is unjustified high-privilege behavior that can access session-backed web content and manipulate a user's browser beyond what is needed to submit cloud workflows.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script immediately creates a new Chrome page through the local DevTools endpoint and attaches to the browser without any confirmation, warning, or runtime consent. Because DevTools access can affect a user's active browser session and logged-in state, silent automation raises meaningful security and privacy concerns even if intended for convenience.

Content

No source excerpt is available for this finding.

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
93% confidence
Finding

This code sends HTTP requests to a localhost Chrome DevTools service, which is an internal network target with powerful browser-control capabilities. Although the destination is fixed to 127.0.0.1 rather than attacker-supplied, internal-service interaction is still security-relevant because it can be used to access and manipulate a local browser session outside the skill's stated API scope.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 86)May include surrounding context.

python
print("[1/5] Creating workflow page...")
    import requests

    resp = requests.put(f"http://127.0.0.1:9222/json/new?{WORKFLOW_URL}")
    page_info = resp.json()
    page_id = page_info.get("id")
    ws_url = page_info.get("webSocketDebuggerUrl")

Tainted flow: 'handshake' from requests.put (line 109, network input) → socket.socket.send (network output)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 110)May include surrounding context.

python
key = base64.b64encode(bytes([0x41] * 16)).decode()
    handshake = f"GET {path} HTTP/1.1\r\nHost: {host}:{port}\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: {key}\r\nSec-WebSocket-Version: 13\r\n\r\n"
    sock.send(handshake.encode())

    response = sock.recv(1024)
    if b"101" not in response:

Tainted flow: 'ws_url' from requests.put (line 89, network input) → socket.socket.send (network output)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 119)May include surrounding context.

python
print("✅ WebSocket connected successfully")

    print("\n[4/5] Enabling Chrome DevTools domains...")
    sock.send(send_ws_command(ws_url, "Runtime.enable", {}, 1))
    sock.send(send_ws_command(ws_url, "DOM.enable", {}, 2))
    sock.send(send_ws_command(ws_url, "Page.enable", {}, 3))
    time.sleep(1)

Tainted flow: 'ws_url' from requests.put (line 89, network input) → socket.socket.send (network output)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 120)May include surrounding context.

python
print("\n[4/5] Enabling Chrome DevTools domains...")
    sock.send(send_ws_command(ws_url, "Runtime.enable", {}, 1))
    sock.send(send_ws_command(ws_url, "DOM.enable", {}, 2))
    sock.send(send_ws_command(ws_url, "Page.enable", {}, 3))
    time.sleep(1)

Tainted flow: 'ws_url' from requests.put (line 89, network input) → socket.socket.send (network output)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 121)May include surrounding context.

python
print("\n[4/5] Enabling Chrome DevTools domains...")
    sock.send(send_ws_command(ws_url, "Runtime.enable", {}, 1))
    sock.send(send_ws_command(ws_url, "DOM.enable", {}, 2))
    sock.send(send_ws_command(ws_url, "Page.enable", {}, 3))
    time.sleep(1)

    while True:

Tainted flow: 'ws_url' from requests.put (line 89, network input) → socket.socket.send (network output)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 151)May include surrounding context.

python
})()
    """

    sock.send(
        send_ws_command(
            ws_url,
            "Runtime.evaluate",

Internal Network Request

Medium
Category
Server-Side Request Forgery
Confidence
90% confidence
Finding

The cleanup request also targets the internal localhost DevTools service, continuing unauthorized interaction with a powerful local control plane. While less severe than page creation and script execution, it still reflects out-of-scope access to internal browser-debugging infrastructure and could impact user browsing context if misused.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 205)May include surrounding context.

python
sock.close()

    requests.get(f"http://127.0.0.1:9222/json/close/{page_id}")

    print("\n" + "=" * 70)

Tainted flow: 'page_id' from requests.put (line 88, network input) → requests.get (network output)

Medium
Category
Data Flow
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.

Content

Scanner excerpt · scripts/chrome_automation.py (reported line 205)May include surrounding context.

python
sock.close()

    requests.get(f"http://127.0.0.1:9222/json/close/{page_id}")

    print("\n" + "=" * 70)

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/hybrid_automation.py (reported line 26)May include surrounding context.

python
print("=" * 70)

    for attempt in range(max_attempts):
        resp = requests.post(
            query_url, headers=headers, json={"taskId": task_id}, timeout=10
        )

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/hybrid_automation.py (reported line 80)May include surrounding context.

python
print("=" * 70)

    try:
        resp = requests.post(url, headers=headers, json=payload, timeout=10)
        result = resp.json()

        if result.get("taskId"):

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The client uploads arbitrary local image files to a remote third-party service without an explicit privacy or data-transmission warning at the point of upload. Users may unintentionally transmit sensitive local content, especially because the feature operates directly on filesystem paths and returns externally hosted URLs.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/runninghub_client.py (reported line 135)May include surrounding context.

python
}

        try:
            response = requests.post(
                url, headers=self.headers, json=payload, timeout=30
            )
            return response.json()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script saves the API key to a local config file and only prints a success message, without warning that the credential will persist on disk. In shared environments or developer workstations, plaintext credential storage can lead to accidental disclosure through backups, repository inclusion, or local compromise.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring states the script is 'For automated image upload and workflow execution.' However, later output states that due to browser security restrictions it 'cannot directly upload local files via CDP,' and the implemented JavaScript only checks for file inputs/buttons rather than performing an upload. This is an active contradiction between the file’s stated intent and its actual behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script emits all primary user-facing status and usage text in English, including the workflow banner and option descriptions, without any opt-in or locale selection. Under the stated policy, forcing a specific language without user choice is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The manifest describes a client for submitting ComfyUI workflows, checking status, and retrieving results from RunningHub. In addition to those API operations, the code implements local credential storage in config.json via save_config(), which is a broader behavior not mentioned in the manifest description.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

The manifest focuses on executing workflows, submitting tasks, querying status, and retrieving results. The code additionally reads local files and uploads them to RunningHub as media inputs, which is an extra capability not explicitly described at the manifest level.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.