T09 · Insecure Skill Coding Practices
- Location
scripts/selfie.py:145- Finding
Unvalidated API-Controlled Image URL Enables Client-Side SSRF and Resource Exhaustion
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly a coherent image-generation tool, but it includes under-controlled instructions to update public avatars and persist profile-asset history.
Review before installing in environments with connected social accounts or persistent agent memory. Use the generator manually unless avatar updates are explicitly approved each time, avoid putting secrets or sensitive identity data in personality prompts, prefer pinned/verified install commands, and treat the generated local gallery as untrusted if personality input can come from someone else.
scripts/selfie.py:145Unvalidated API-Controlled Image URL Enables Client-Side SSRF and Resource Exhaustion
scripts/selfie.py:153Stored HTML Injection Through Unescaped Personality Prompt
Generated with agent-selfie by @IISweetHeartII
""" (out_dir / "index.html").write_text(html, encoding="utf-8") ``` ### Technical Analysis The `name`, `style`, and `vibe` properties supplied through inline personality JSON or a personality file are incorporated into the generated prompt. The prompt is then interpolated directly into a `` element without HTML escaping. An attacker-controlled value can close the existing element and insert arbitrary markup, including script-capable content. For example, a malicious personality name containing `` would be written into the generated `index.html`. Because the payload is persisted, execution occurs when the user later opens the generated gallery. The precise access available to injected JavaScript depends on the browser's treatment of local `file:` origins and its security settings, but arbitrary page modification and attacker-directed network requests remain possible. ### Attack Path 1. An attacker supplies or modifies a personality JSON file, inline personality value, or automation input consumed by the Skill. 2. A personality field contains malicious HTML or JavaScript-capable markup. 3. `build_prompt()` incorporates that field into the prompt. 4. `write_gallery()` inserts the prompt into `` without escaping it. 5. The scrip ...[truncated 766 chars]INSTALL.md:5Unpinned npx Installer Introduces Supply-Chain Execution Risk
The documented purpose understates important behavior: the skill writes files locally and appears to create additional artifacts like prompts.json and index.html, while also advertising 'automatic style evolution' that is not actually implemented. This mismatch is dangerous because users and orchestrators may trust the description when deciding whether to run the skill, leading to unexpected filesystem side effects and incorrect assumptions about what data is generated or persisted.
The heartbeat extends an image-generation skill into actions that affect external accounts and persistent state: updating social-media avatars and writing asset paths to memory. This creates side effects beyond the skill's stated purpose, increasing the chance of unauthorized public profile changes or unintended retention of generated content metadata.
Updating Discord/Twitter/AgentGram avatars is an external account action that is not necessary for a self-portrait generation skill and can change public-facing identity without explicit authorization. In this context, the skill's purpose makes the instruction more suspicious because it crosses from content creation into account management.
The markdown instructs the agent to update public social avatars without any warning, confirmation, or user-consent step. Because profile-image changes are externally visible and can affect branding, identity, or trust, omitting safeguards makes accidental or unauthorized public changes more likely.
The install instruction uses npx clawhub install agent-selfie without pinning a specific version of the clawhub package. This causes users to fetch and execute whatever version is current at install time, which creates a supply-chain risk if the package is compromised, maliciously updated, or replaced upstream.
The update instruction again invokes npx clawhub update agent-selfie without pinning the clawhub version, so users may execute newly published code implicitly during update. In a skill distribution context, this expands supply-chain exposure because the package manager command is presented as the normal maintenance path.
The README instructs users to run npx clawhub install agent-selfie without pinning a specific version of the clawhub package. This can cause users to execute whatever package version is current at install time, increasing supply-chain risk if a malicious or compromised release is published or if dependency resolution changes unexpectedly.
The skill declares no explicit tool scope even though its documented behavior clearly requires environment access, network access, and local file writes. In an agent ecosystem, missing scope declarations can cause the runtime or user to grant broader capabilities than expected, reducing transparency and making misuse or accidental overreach harder to detect.
The examples show personality JSON, mood, theme, and style prompts being sent to a remote image generation provider, but the documentation does not warn users that this potentially sensitive identity or profile data leaves the local environment. In a self-portrait/identity skill, prompts may contain personal, brand, or proprietary descriptive data, so the omission creates a meaningful privacy and data-governance risk.
The quickstart instructs users to execute npx clawhub install agent-selfie without pinning a specific version of the package. This creates a supply-chain risk because npx will fetch the latest published package at runtime, so a compromised or malicious future release could execute unexpected code during installation. In this skill context, the risk is more meaningful because the package is presented as the default installation path for users who may also configure sensitive API credentials.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
import urllib.request
from pathlib import Path
API_BASE = "https://api.heybossai.com/v1"
DEFAULT_PERSONALITY = {
"name": "Agent",
The script builds a prompt from user-supplied personality data and sends it to the SkillBoss API in a POST request. Although the CLI description mentions the API service, the code provides no explicit warning at the point of use that personal or profile-like content from --personality will be transmitted off-machine.
Logging generated asset paths to memory introduces persistent retention of content metadata without any notice about privacy or retention boundaries. While lower impact than external profile updates, persistent memory can expose user or agent activity patterns and enable unintended reuse of historical assets.
No suspicious patterns detected.