Back to skill

Security audit

Agent-first Marketing Image Generation

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its image-generation purpose, but live mode can spend account credits without enforcing its own local limits.

Review before installing if you plan to enable live mode. Use a minimally scoped Rynjer token, avoid sensitive or regulated content in prompts, estimate cost before generation, and place server-side or wrapper limits around count and polling until the runtime enforces its declared schema.

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
src/mock-runtime.js:343
Finding
Unenforced Input Limits Permit Excessive Paid Generation and Polling## Vulnerability Details **File Location**: `src/mock-runtime.js:343-352`, `src/mock-runtime.js:382-389`, and `src/mock-runtime.js:409-416` **Vulnerability Type**: Missing runtime input validation and resource-consumption controls **Risk Level**: Medium The tool schema declares limits for security-sensitive and cost-sensitive fields in `src/tools.json:91-101`, including a maximum image count of 4, a maximum of 10 polling attempts, and a polling interval between 200 and 10,000 milliseconds. The executable runtime does not validate parsed input against this schema. **Vulnerable code:** ```javascript const body = { request_id: requestId, model, prompt: input.prompt, product: 'image', units: { count: input.count || 1, resolution: input.resolution || '1K', aspect_ratio: input.aspect_ratio || '1:1' }, scene: input.scene || 'text-to-image' }; ``` ```javascript const attempts = input.poll_attempts || 3; const intervalMs = input.poll_interval_ms || 1500; let lastPoll = null; for (let i = 0; i < attempts; i++) { await sleep(intervalMs); lastPoll = await pollImageResult({ request_id: requestId }); if (!lastPoll.ok) return { ...out, auto_poll: true, poll_error: lastPoll }; if (!lastPoll.pending) { return { ...out, auto_poll: true, final_result: lastPoll }; } } ``` ```javascript async function main() { const [,, toolName, rawInput] = process.argv; if (!toolName) { console.error('Usage: node src/mock-runtime.js <tool_name> <json_input>'); process.exit(1); } const input = rawInput ? JSON.parse(rawInput) : {}; let result; if (toolName === 'rewrite_image_prompt') result = rewritePrompt(input); else if (toolName === 'estimate_image_cost') result = await estimateCost(input); else if (toolName === 'generate_image') result = await generateImage(input); else if (toolName === 'poll_image_result') result = awai ...[truncated 2889 chars]
Remediation
## Remediation Suggestions 1. Validate every invocation against the corresponding schema in `src/tools.json` before dispatch. Use a maintained JSON Schema validator or equivalent explicit validation. 2. Reject unknown properties and enforce all declared types, required fields, enumerations, and numeric ranges. 3. Add independent defensive checks inside `generateImage()`: - Require `count` to be an integer from 1 through 4. - Require `poll_attempts` to be an integer from 1 through 10. - Require `poll_interval_ms` to be an integer from 200 through 10,000. - Allow only supported resolutions, aspect ratios, quality modes, scenes, and models. 4. Do not silently clamp cost-sensitive values unless the caller is explicitly informed. Prefer rejecting invalid paid-operation requests before any network call. 5. Add an account-level or invocation-level credit budget and require explicit approval when a request exceeds it. 6. Add request timeouts, an overall auto-poll deadline, and cancellation support so polling cannot retain the process indefinitely. 7. Add regression tests that invoke the executable entry point with boundary, oversized, negative, fractional, and wrong-type values, verifying that no live request is made when validation fails. 8. Keep server-side limits on the Rynjer API because client-side validation alone cannot protect the service from modified clients.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (10)

Credential Access

High
Category
Privilege Escalation
Content
## Live mode error behavior

The runtime now handles these cases explicitly:
- missing access token when live mode is enabled
- owner-granted scope mismatch during API key creation
- non-200 responses
- invalid or unexpected JSON responses
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The document explicitly directs the skill to use live production endpoints and bearer-authenticated generation flows, but does not warn that prompts, request metadata, and generated-content requests will be transmitted to a third-party backend. In an agent skill context, this omission is security-relevant because users or deployers may assume local-only processing and unknowingly expose sensitive prompt contents or operational data.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The autonomous auth flow describes generating keys, registering the agent, minting an account-scoped bearer token, and then using that token directly against generation endpoints, but it does not include handling guidance for secrets, token storage, rotation, or least-privilege risks. In an agent ecosystem, such documentation can lead to insecure credential handling and unauthorized use of account-linked generation capabilities if the token is exposed.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The live-mode instructions tell users to set credentials and invoke real API calls, but they do not explicitly warn that prompts, request IDs, and related metadata will be transmitted to the external Rynjer service. In an agent setting, operators may unknowingly send sensitive user content or internal workflow context off-platform, creating privacy, compliance, and data-handling risk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
When live mode is enabled, the code sends the user-supplied prompt, request ID, model choice, and generation metadata to a remote service at BASE_URL. In an image-generation skill, prompts can contain sensitive business data, personal information, or proprietary creative material, and this file provides no disclosure, consent gate, or minimization before transmission.

Natural-Language Policy Violations

Low
Confidence
68% confidence
Finding
The natural-language instructions point users to an `/en/` UI path, which implies a fixed English locale. Because the file does not mention that other locales are supported or that English is only an example, this may conflict with language-choice policy expectations.

Natural-Language Policy Violations

Low
Confidence
94% confidence
Finding
Line L009 presents a key descriptive statement in Chinese while the rest of the skill is primarily in English. This creates an implicit language constraint for users who may not understand Chinese, and the file does not offer a language option or explain that the skill is intended for a Chinese-speaking audience.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The polling path transmits request identifiers to the remote API, which can expose linkage to prior generation jobs and associated metadata if identifiers are sensitive or guessable. While lower risk than sending full prompts, the absence of disclosure and data-handling controls still creates a privacy and operational transparency issue.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
This JSON contains user-facing natural-language descriptions in Chinese while template names and other guidance are in English. That creates an implicit language constraint without any documented opt-in or language selection, which can violate language/locale policy expectations for multilingual users.

Static analysis

No suspicious patterns detected.