Back to skill

Security audit

OpenFishy Feed Publisher

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly transparent about generating and publishing media, but its scripts can send API keys and content to insufficiently validated network destinations.

Review before installing. Use this only with non-sensitive prompts and media, set credentials only in a controlled shell, prefer --dry-run first, and do not set VISUAL_STUDIO_API_URL unless you fully trust the destination. The publisher should add strict URL allowlisting and a confirmation gate before normal use.

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

Error
Location
scripts/submit.py:47
Finding

Publishing credential can be transmitted to an unrestricted endpoint

Content
View full analysis
dict: last_error = None for attempt in range(max_retries + 1): raw_body = json.dumps(payload).encode("utf-8") headers = { "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", **build_submit_signature_headers(api_key, raw_body), } req = urllib.request.Request( api_url, data=raw_body, headers=headers, method="POST", ) try: with urllib.request.urlopen(req, timeout=30) as resp: body = resp.read().decode("utf-8") return json.loads(body) if body else {} ``` The destination is obtained directly from an environment variable without validation: ```python api_url = os.environ.get("VISUAL_STUDIO_API_URL", DEFAULT_API_URL) ``` The same configuration pattern is used by the orchestration scripts: ```python api_url = os.environ.get("VISUAL_STUDIO_API_URL", DEFAULT_API_URL) ``` ### Technical Analysis The publishing client accepts an arbitrary value from `VISUAL_STUDIO_API_URL` and immediately sends an authenticated request to it. There is no validation of: - URL scheme - Destination hostname - Port - Submission path - Embedded URL credentials - Redirect destination The request contains the complete `VISUAL_STUDIO_API_KEY` as a bearer credential. It also includes an HMAC signature derived from the same key. If the destination is changed to an untrusted server, the bearer credential is disclosed directly. Sending the key to the declared OpenFishy submission API is necessary for the Skill's documente ...[truncated 2057 chars]
Remediation
View remediation
str: parsed = urlparse(raw_url) if parsed.scheme != "https": raise ValueError("Submission URL must use HTTPS") if parsed.hostname not in ALLOWED_SUBMIT_HOSTS: raise ValueError("Untrusted submission hostname") if parsed.port not in (None, 443): raise ValueError("Unexpected submission port") if parsed.username or parsed.password or parsed.fragment: raise ValueError("Invalid submission URL") if parsed.path != "/api/submit": raise ValueError("Unexpected submission path") return raw_url ``` ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/fal_queue.py:91
Finding

fal.ai credential is forwarded to server-provided polling URLs without origin validation

Content
View full analysis
tuple[int, dict[str, Any]]: headers = { "Authorization": f"Key {fal_key}", "Accept": "application/json", } if extra_headers: headers.update(extra_headers) body: bytes | None = None if payload is not None: headers["Content-Type"] = "application/json" body = json.dumps(payload).encode("utf-8") req = urllib.request.Request(url, data=body, headers=headers, method=method) try: with urllib.request.urlopen(req, timeout=timeout_s) as resp: raw = resp.read().decode("utf-8", errors="replace").strip() return resp.getcode(), json.loads(raw) if raw else {} ``` The initial queue response supplies complete status and response URLs: ```python request_id = str(body.get("request_id", "")).strip() status_url = str(body.get("status_url", "")).strip() response_url = str(body.get("response_url", "")).strip() if not request_id or not status_url or not response_url: raise FalQueueError(f"unexpected fal submit response: {body}") return FalQueuedRequest(request_id=request_id, status_url=status_url, response_url=response_url) ``` Those URLs are subsequently used with the credential attached: ```python status_url = queued.status_url if include_logs: # fal supports enabling logs via `?logs=1` on the status endpoint. status_url = f"{status_url}?logs=1" last_status: str | None = None while True: _, status_body = _json_request( url=status_url, metho ...[truncated 3048 chars]
Remediation
View remediation
str: parsed = urlparse(raw_url) if parsed.scheme != "https": raise FalQueueError("fal URL must use HTTPS") if parsed.hostname not in ALLOWED_FAL_HOSTS: raise FalQueueError("Untrusted fal URL hostname") if parsed.port not in (None, 443): raise FalQueueError("Unexpected fal URL port") if parsed.username or parsed.password or parsed.fragment: raise FalQueueError("Invalid fal URL") return raw_url ``` ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (18)

Tainted flow: 'req' from os.environ.get (line 56, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/quality_check.py (reported line 65)May include surrounding context.

python
},
        method="POST",
    )
    with urllib.request.urlopen(req, timeout=30) as resp:
        body = json.loads(resp.read().decode("utf-8"))
        text = body["choices"][0]["message"]["content"].strip()
        return extract_score(text)

Tainted flow: 'req' from os.environ.get (line 56, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
92% confidence
Finding

The request destination is influenced by the environment variable VISUAL_STUDIO_API_URL, allowing untrusted runtime configuration to redirect a POST containing the bearer API key and HMAC-style signature headers to an attacker-controlled endpoint. In this skill context, the script is specifically designed to publish externally and includes sensitive authentication material in the request, so SSRF-style exfiltration of credentials is a realistic and serious risk.

Content

Scanner excerpt · scripts/submit.py (reported line 63)May include surrounding context.

python
method="POST",
        )
        try:
            with urllib.request.urlopen(req, timeout=30) as resp:
                body = resp.read().decode("utf-8")
                return json.loads(body) if body else {}
        except urllib.error.HTTPError as exc:

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The combination of a misleading destination name, authenticated submission behavior, and undeclared external endpoint details creates a meaningful exfiltration and trust-boundary risk. Even if the endpoint is legitimate, operators may authorize bearer-token network submission to an external service they did not intend to trust because the skill's stated purpose obscures the real integration details.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The combination of a misleading destination name, authenticated submission behavior, and undeclared external endpoint details creates a meaningful exfiltration and trust-boundary risk. Even if the endpoint is legitimate, operators may authorize bearer-token network submission to an external service they did not intend to trust because the skill's stated purpose obscures the real integration details.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The combination of a misleading destination name, authenticated submission behavior, and undeclared external endpoint details creates a meaningful exfiltration and trust-boundary risk. Even if the endpoint is legitimate, operators may authorize bearer-token network submission to an external service they did not intend to trust because the skill's stated purpose obscures the real integration details.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The combination of a misleading destination name, authenticated submission behavior, and undeclared external endpoint details creates a meaningful exfiltration and trust-boundary risk. Even if the endpoint is legitimate, operators may authorize bearer-token network submission to an external service they did not intend to trust because the skill's stated purpose obscures the real integration details.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The combination of a misleading destination name, authenticated submission behavior, and undeclared external endpoint details creates a meaningful exfiltration and trust-boundary risk. Even if the endpoint is legitimate, operators may authorize bearer-token network submission to an external service they did not intend to trust because the skill's stated purpose obscures the real integration details.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill claims to publish to the OpenFishy feed API, but this file retrieves credentials from VISUAL_STUDIO_API_KEY and allows overriding the endpoint via VISUAL_STUDIO_API_URL. That mismatch is a strong indicator of deceptive credential targeting or covert exfiltration, because a user invoking an OpenFishy publisher would not reasonably expect Visual Studio-named secrets to be required or sent to a configurable endpoint.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises executable scripts that read environment variables and perform outbound network operations, but it declares no explicit tool scope or permission boundary. This makes the skill harder to govern and increases the risk of unintended credential use or network access when invoked in an agent environment.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The activation text uses broad phrases like creating visual content or running a generation cycle, which can cause the skill to trigger for general creative requests outside the narrow publishing workflow. Over-broad invocation increases the chance that users unintentionally send prompts, media URLs, or credentials into an executable, networked skill when a safer local-only capability would have sufficed.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring claims the script submits generated media to 'Visual Studio' even though the skill metadata says it publishes to the OpenFishy feed API. In an agent skill, this kind of destination mismatch is dangerous because it can mislead operators and reviewers about where generated content and associated metadata will be sent, increasing the risk of unintended exfiltration or use of the wrong credentials.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The imported submission path and identifiers (DEFAULT_API_URL, submit_to_visual_studio, VISUAL_STUDIO_API_KEY, VISUAL_STUDIO_API_URL) implement a Visual Studio-oriented publishing flow that conflicts with the declared OpenFishy purpose. In a skill that will be invoked based on manifest metadata, this discrepancy can cause content and metadata to be posted to an unintended external service using unrelated credentials, which is a real integrity and data-handling risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script sends generated media URLs, prompts, profile/theme selections, tags, model identifiers, and generator metadata to external services automatically, without any interactive confirmation or explicit notice in this file. Given the skill context, users may believe they are only generating content, while the script also performs network publication, making accidental disclosure and unauthorized posting more likely.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

The manifest describes a skill for generating AI images/videos and publishing them to the OpenFishy feed API. This helper script adds a separate capability of pulling OpenAI credentials from the process environment to invoke an external vision model, which is not explicitly justified by the stated purpose and goes beyond simple generation/publishing behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script sends the user-supplied image URL and prompt text to an external third-party API for evaluation without any visible consent, notice, or minimization controls. If prompts or media URLs contain private, sensitive, or proprietary information, this can create an unintended data disclosure channel outside the stated publishing destination.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% 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/quality_check.py (reported line 57)May include surrounding context.

python
}

    req = urllib.request.Request(
        "https://api.openai.com/v1/chat/completions",
        data=json.dumps(payload).encode("utf-8"),
        headers={
            "Content-Type": "application/json",

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The module docstring claims this submits to a Visual Studio ingestion API, while the skill metadata says it should publish to the OpenFishy feed API. This branding mismatch is suspicious because it can mislead reviewers and operators about where generated content and secrets are being sent, increasing the chance of unnoticed data exfiltration or misuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The default endpoint is a Visual-Studio-branded URL even though the skill is described as publishing to the OpenFishy feed API. In context, this mismatch is more dangerous because the skill handles generated media, prompts, and API credentials; sending them to an unrelated third-party endpoint could leak sensitive content and tokens outside the declared platform.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.