Back to skill

Security audit

Content Claw

Security checks for vulnerabilities and agentic risk

Overview

This skill mostly matches its content-generation purpose, but it needs Review because it can fetch arbitrary URLs, write generated files from user-controlled names, and includes a Reddit prompt designed to make AI-written content look like organic human testimony.

Install only after reviewing the Reddit agent and disabling or rewriting it for transparent, fact-backed drafts. Run URL extraction in a sandbox with restricted network access, avoid internal or sensitive URLs, use scoped API keys, prefer verified package installation with a lockfile, and validate brand and recipe names before allowing writes.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (7)

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:53
Finding
Remote Installer Is Downloaded and Executed Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:53-58` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Vulnerable Code ```markdown **uv** is Astral's Python package manager and project runner (https://docs.astral.sh/uv/). It replaces pip, venv, and pip-tools. Install it with: - macOS (recommended): `brew install astral-sh/tap/uv` - pip/pipx: `pipx install uv` - Linux/macOS (alternative): `curl -LsSf https://astral.sh/uv/install.sh | sh` (review the script at https://astral.sh/uv/install.sh before running) After installing uv, run `uv sync` in the skill directory to install all Python dependencies. Then run `uv run playwright install chromium` to set up the headless browser for extraction. ``` ### Technical Analysis The installation command pipes data downloaded from an external URL directly into a shell. The retrieved script is mutable after the Skill has been reviewed, and the command does not pin a version or verify a cryptographic hash or signature. The URL appears to use Astral's official domain, and the documentation advises users to review the script. However, that warning does not enforce review or integrity verification. The remote endpoint, DNS/TLS trust chain, hosting account, or upstream release process could be compromised. This execution method is not necessary for the Skill's declared content-generation functionality because package-manager and verified-download alternatives are available. ### Attack Path 1. An attacker compromises the remote installer endpoint, its hosting infrastructure, or a relevant delivery dependency. 2. The attacker modifies the installer to include arbitrary shell commands. 3. A user follows the documented `curl ... | sh` installation instruction. 4. The shell immediately executes the modified payload without showing or verifying the downloaded file. 5. The payload operates with all permissions available to the user running the command. ### Impact Assess ...[truncated 471 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the pipe-to-shell installation option. - Prefer a trusted platform package manager with a pinned package version. - If a standalone installer is required, download it as a separate file, pin its versioned URL, and verify its vendor-published cryptographic checksum or signature before execution. - Display the downloaded file for local review rather than relying on an advisory comment. - Document that installation must occur as an unprivileged user. - Commit and enforce a lockfile for subsequent Python dependency installation. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/extractors/extract.py:17
Finding
Arbitrary Source URLs Permit Server-Side Request Forgery and Local-Network Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/extractors/extract.py:17-42, 74-84, 246-275` **Vulnerability Type**: Unrestricted outbound URL fetching **Risk Level**: High ### Vulnerable Code ```python def get_page_html(url: str, wait_for: str | None = None) -> str: """Fetch a page's HTML using Playwright with stealth settings.""" from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=[ "--disable-blink-features=AutomationControlled", "--no-sandbox", ], ) context = browser.new_context( user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", viewport={"width": 1280, "height": 800}, locale="en-US", ) page = context.new_page() page.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") page.goto(url, wait_until="domcontentloaded", timeout=30000) ``` ```python resp = httpx.get( url, follow_redirects=True, timeout=60, headers={ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", }, ) ``` ```python url = sys.argv[1] source_type = detect_type(url) extractors = { "web": extract_web, "pdf": extract_pdf, "reddit": extract_reddit, "twitter": extract_twitter, "github": extract_github, } extractor = extractors.get(source_type) ``` ### Technical Analysis The extractor accepts a user-controlled URL and sends it to Playwright or `httpx` without validating the scheme, hostname, resolved IP address, or redirect destination. It does not reject loopback, private, link-local, reserved, multicast, or cloud metadata addresses. The PDF path follows redirects automatically, but each r ...[truncated 1104 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Accept only explicitly supported `http` and `https` schemes. - Resolve destination hostnames before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved addresses for both IPv4 and IPv6. - Explicitly deny common cloud metadata endpoints and hostnames. - Disable automatic redirects or validate every redirect destination before following it. - Address DNS rebinding by connecting only to the validated address and checking all resolved addresses. - Apply outbound network restrictions at the container or operating-system level. - Limit response size, navigation time, redirect count, and subresource access. - Consider an allowlist for supported public source providers where practical. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:328
Finding
User-Controlled Recipe and Brand Names Can Escape the Declared Project Directory<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:328-365, 443-460` **Vulnerability Type**: Path traversal through generated names **Risk Level**: High ### Vulnerable Code ```markdown Once confirmed, save to `BASE_DIR/recipes/<slug>.yaml`. Tell the user: "Recipe saved. You can now run it with: `run <slug> <source-url>`" ``` ```markdown Create YAML files in `BASE_DIR/brand-graphs/<brand-name>/`: - `identity.yaml`: name, positioning, description, services - `audience.yaml`: who, interests, pain_points, stage - `strategy.yaml`: goals, niche_keywords - `visual.yaml`: primary_color, accent_color (if provided) - `feedback.yaml`: empty file with `insights: []` (populated over time) ``` The affected instructions conflict with the declared boundary: ```markdown This skill only reads and writes files within `BASE_DIR`. Do not read, write, or search files outside of `BASE_DIR`. ``` ### Technical Analysis Recipe slugs and brand names are incorporated into filesystem paths without a documented requirement to reject path separators, absolute paths, `.` components, or `..` traversal components. The host Agent is instructed to perform the writes with its `Write` or shell tools. A crafted value such as `../../target` could normalize outside the intended `recipes` or `brand-graphs` directories. The prose-only `BASE_DIR` restriction does not provide a technical boundary if the resulting path is not canonicalized and checked before use. ### Attack Path 1. A user requests creation of a recipe or brand with a name containing traversal components. 2. The Agent derives or retains an unsafe slug or brand name. 3. The unsafe value is interpolated into the documented output path. 4. The path resolves outside the intended project subdirectory and potentially outside `BASE_DIR`. 5. The Agent creates or overwrites files wherever its host filesystem permissions allow. ### Impact Assessment Successful exploitation may create or overwrite user-accessible files outsi ...[truncated 297 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Restrict recipe and brand identifiers to a conservative pattern such as `^[a-z0-9][a-z0-9-]{0,63}$`. - Reject absolute paths, path separators, drive prefixes, null bytes, `.` components, and `..` components. - Resolve the final path before every read or write and verify that it is a descendant of the expected parent directory using a robust path-containment check. - Perform validation in executable code rather than relying only on Agent instructions. - Refuse unsafe values and ask the user to choose a safe identifier. - Use exclusive creation or explicit overwrite confirmation where existing files may be replaced. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/extractors/extract.py:20
Finding
Chromium Sandbox Is Disabled While Rendering Untrusted Pages<![CDATA[ ## Vulnerability Details **File Location**: `scripts/extractors/extract.py:20-31` **Vulnerability Type**: Browser sandbox weakening **Risk Level**: Medium ### Vulnerable Code ```python with sync_playwright() as p: browser = p.chromium.launch( headless=True, args=[ "--disable-blink-features=AutomationControlled", "--no-sandbox", ], ) context = browser.new_context( user_agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", viewport={"width": 1280, "height": 800}, locale="en-US", ) ``` The same unsafe setting is duplicated in `scripts/browser.py:20-29`: ```python BROWSER_ARGS = ["--disable-blink-features=AutomationControlled", "--no-sandbox"] with sync_playwright() as p: browser = p.chromium.launch(headless=True, args=BROWSER_ARGS) ``` ### Technical Analysis The Skill renders arbitrary third-party pages while launching Chromium with `--no-sandbox`. Browser content is inherently untrusted, and the Chromium sandbox is a significant defense-in-depth boundary against browser renderer vulnerabilities. Disabling the sandbox is not required by the declared extraction functionality in a normally configured environment. The stealth configuration also intentionally reduces automation detection, potentially increasing exposure to sites that would otherwise block the browser. ### Attack Path 1. An attacker supplies a URL hosting malicious browser content. 2. Playwright opens the page in Chromium with sandboxing disabled. 3. The page exploits a browser or renderer vulnerability. 4. Because the browser sandbox is disabled, the exploit has a less restricted route to the browser process and host resources. 5. The resulting access is bounded primarily by the operating-system privileges of the Skill process. ### Impact Assessment A successful browser exploit could execute code with the privileges ...[truncated 248 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove `--no-sandbox` from both browser launch implementations. - Run Playwright as a dedicated, unprivileged operating-system user. - Place browser extraction in a hardened container or sandbox with a read-only filesystem, minimal mounted directories, dropped capabilities, and restricted network access. - Keep Chromium and Playwright security updates current. - Avoid stealth settings unless they are demonstrably required and legally permitted. - Fail safely with installation guidance if sandbox support is unavailable rather than silently disabling it. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/extractors/extract.py:88
Finding
Downloaded PDF Files Are Left Behind in Temporary Storage<![CDATA[ ## Vulnerability Details **File Location**: `scripts/extractors/extract.py:88-98` **Vulnerability Type**: Unsafe temporary-file lifecycle **Risk Level**: Low ### Vulnerable Code ```python with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f: f.write(resp.content) tmp_path = f.name doc = pymupdf.open(tmp_path) pages = [] for pg in doc: pages.append(pg.get_text()) doc.close() text = "\n\n".join(pages) ``` ### Technical Analysis The extractor creates the PDF with `delete=False` but never removes it. Consequently, every processed PDF remains in the system temporary directory after successful processing. It can also remain after parsing exceptions because cleanup is not performed in a `finally` block. `NamedTemporaryFile` gives the file a non-predictable name and generally restrictive initial permissions, which reduces direct race risks. The vulnerability is the persistent lifecycle and accumulation of potentially sensitive source data. ### Attack Path 1. A user processes a confidential or large PDF. 2. The entire response body is written to a temporary file. 3. Text extraction finishes or raises an exception. 4. No unlink operation is performed. 5. The file remains available until external cleanup, reboot, or manual deletion. ### Impact Assessment Sensitive document contents may persist beyond the intended Skill run and become accessible through local administrative access, backups, forensic inspection, or platform-specific temporary-directory permission weaknesses. Repeated processing may also consume disk space and cause denial of service. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Use `TemporaryDirectory` or delete the temporary file in a `finally` block. - Ensure the PyMuPDF document is closed before deletion, including on exceptions. - Apply a maximum download size before writing the response body. - Stream downloads with a strict byte limit rather than loading unlimited content into memory. - Use restrictive permissions explicitly where cross-platform behavior may differ. - Add tests confirming cleanup after both successful and failed PDF parsing. ]]>

T08 · Insecure Dependencies

Warning
Location
pyproject.toml:6
Finding
Unpinned Dependencies Make Installations Non-Reproducible<![CDATA[ ## Vulnerability Details **File Location**: `pyproject.toml:6-19` **Vulnerability Type**: Dependency supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```toml dependencies = [ "httpx>=0.27", "pymupdf>=1.24", "readabilipy>=0.2", "playwright>=1.49", "fal-client>=0.5", "exa-py>=1.0", ] [dependency-groups] dev = [ "pytest>=8.0", "pyyaml>=6.0", ] ``` Related installation instructions include: ```markdown - pip/pipx: `pipx install uv` ... After installing uv, run `uv sync` in the skill directory to install all Python dependencies. ``` ### Technical Analysis All dependencies use open-ended lower bounds. No reviewed lockfile was present in the audited directory. As a result, two users installing the same Skill at different times may receive different dependency versions, including future releases that were not part of this audit. The package names appear consistent with the imports, and no dependency-confusion or typosquatting package was confirmed. The issue is the lack of reproducibility and integrity controls, not proof that any listed package is currently malicious. ### Attack Path 1. A future release of a dependency or transitive dependency is compromised or malicious. 2. A user runs `uv sync` without an enforced reviewed lockfile. 3. The resolver selects the new release because it satisfies the open lower bound. 4. Malicious package installation or runtime code executes in the Skill environment. 5. The package receives the same process-level access as the Skill. ### Impact Assessment A compromised dependency could execute arbitrary Python code during installation, import, or runtime. It could access the declared API keys in the environment, source data processed by the Skill, project files, and network resources available to the process. The practical impact depends on the behavior of a compromised upstream package. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Generate, commit, and enforce a `uv.lock` file from a reviewed dependency set. - Use exact versions in release builds where appropriate. - Require hashes or signatures for downloaded distributions where supported. - Pin the bootstrap version of `uv` rather than installing an unrestricted latest version. - Use automated dependency vulnerability and provenance scanning. - Review lockfile changes and transitive dependency additions before release. - Rebuild the lockfile on a controlled schedule so security updates remain deliberate and auditable. ]]>

other

Warning
Location
agents/reddit-human.md:3
Finding
Reddit Agent Encourages Fabricated Human-Like Personal Testimony<![CDATA[ ## Vulnerability Details **File Location**: `agents/reddit-human.md:3-19, 23-59` **Vulnerability Type**: Deceptive content generation **Risk Level**: Medium ### Vulnerable Code ```markdown You are generating a Reddit comment or post that reads like it was typed by a real person on their phone between meetings. Not a content creator. Not a marketer. A person. ``` ```json { "type": "comment | post", "subreddit": "target subreddit", "tone": "helpful | opinionated | curious | casual | frustrated | enthusiastic", "angle": "one sentence: what is this person's take on this topic", "personal_detail": "one specific thing from their experience that makes this real", "length": "short (1-2 sentences) | medium (3-5 sentences) | long (1-2 paragraphs)", "imperfections": "one small imperfection to include: typo, incomplete thought, self-correction, trailing off", "platform": "reddit", "text_fallback": "the actual comment/post text" } ``` ```markdown Take the spec and write the comment. Then break every rule you know about good writing: - Drop a period sometimes - Start a sentence with "like" or "honestly" or "idk" - Use a parenthetical that's longer than the main sentence - Interrupt yourself: "we tried Clay but -- actually wait, this was before they changed their pricing" - Trail off: "might be worth looking into if you're doing high volume outbound tho" - Abbreviate inconsistently: "tbh" in one sentence, "to be honest" in another ``` ### Technical Analysis The prompt explicitly seeks to make generated content appear to be organic commentary from a real person rather than generated or marketing content. It requires a personal experiential detail and artificial imperfections but does not require that the claimed experience be supplied by the user or supported by source material. This design can cause the Agent to fabricate product use, spending, team behavior, results, or limitations and present those claims as firsthand testimony. This is ...[truncated 897 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Prohibit invention of personal experiences, metrics, spending, employment details, or product usage. - Require every experiential claim to come directly from user-supplied, verified facts. - Replace `personal_detail` with an optional `verified_personal_detail` field and omit it when no factual input exists. - Remove instructions whose purpose is to conceal generated or promotional authorship. - Require appropriate disclosure of AI assistance or commercial affiliation. - Add a validation step that rejects unsupported first-person claims before rendering. - Preserve natural platform adaptation without impersonating a nonexistent person. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Rogue AgentSelf-Modification, Session Persistence
Findings (55)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The declared description focuses on transforming content into publish-ready marketing assets and discovering/generating topics and images. This code does not perform content generation at all; its primary purpose is ingestion/extraction of source text from various online resources. While extraction could be a supporting step in a larger content pipeline, the supplied chunk itself implements undeclared scraping/extraction capabilities, including browser-based retrieval with bot-evasion measures, PDF downloading, and API-based GitHub retrieval. It also lacks the core declared behaviors: no Exa integration, no fal.ai calls, no social-post generation, no infographic/diagram creation, and no content recipe logic. Therefore the code chunk is materially mismatched with the declared purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description focuses on generating publish-ready marketing/social content, trend discovery, and image creation. The actual code does none of that. Instead, it tests a content/source extraction pipeline that fetches and classifies URLs and validates returned JSON. This is a materially different primary purpose from the declared skill behavior. While extraction could hypothetically support a larger content workflow, this specific code chunk is centered on extractor testing and source parsing, which is not accurately represented by the declared description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared description focuses on runtime content creation and topic discovery capabilities, but the provided code chunk does not implement any of those behaviors. Instead, it performs offline validation/testing of recipe configuration files and agent file references. While recipe validation could be a supporting development detail in a larger content-generation system, this chunk’s actual primary purpose is test/schema enforcement rather than generating content, discovering topics, or creating images. Therefore, the supplied code does not accurately represent the declared end-user functionality.

Self-Modification

High
Category
Rogue Agent
Content
- **Effort:** S
- **Blocked by:** Recipe YAML schema.

### Write SKILL.md (core skill definition)
- **What:** Write the OpenClaw SKILL.md that teaches the agent the full Content Claw pipeline: recipe execution, brand graph wizard, recipe listing, error handling, all user commands.
- **Why:** This IS the product. The SKILL.md is the instruction set that makes the OpenClaw agent a content engine.
- **Effort:** M
Confidence
93% confidence
Finding
This task explicitly plans for the agent/skill to author or rewrite its own SKILL.md, which is the instruction set governing future behavior. Self-modification of the skill definition is dangerous because it can let untrusted content, prompt injection from sources, or erroneous generations persistently alter agent behavior, expand capabilities, or weaken safety constraints. In a content-generation skill that ingests external web/PDF/social sources, this context makes the issue more dangerous because adversarial source material could influence durable instruction changes.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This agent is materially out of scope for the declared skill purpose of creating publish-ready branded assets: it is optimized for covert Reddit participation disguised as an ordinary user. That mismatch increases risk because it suggests the capability is meant to bypass governance and use a benign manifest as cover for undisclosed social manipulation.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill explicitly instructs the model to generate Reddit content that appears to have been written by a real person, which is deceptive impersonation rather than transparent assistance. In the context of a content-generation skill, this enables covert influence, astroturfing, and evasion of platform or user disclosure expectations.

Natural-Language Policy Violations

High
Confidence
99% confidence
Finding
The line 'reads like it was typed by a real person' is a direct instruction to impersonate a human author and conceal AI involvement. This is dangerous because it facilitates deceptive communication at scale, undermines trust, and can be used for undisclosed marketing, persuasion, or manipulation in public forums.

Natural-Language Policy Violations

High
Confidence
99% confidence
Finding
The repeated stylistic directives—intentional typos, meandering details, inconsistent capitalization, and other 'humanizing' artifacts—are deliberate deception techniques designed to evade detection as AI-generated or coordinated content. In a Reddit-focused agent, this materially increases the likelihood of covert influence operations and policy evasion.

Lp1

High
Category
MCP Least Privilege
Confidence
75% confidence
Finding
The skill uses 'env' capability that is not listed in its permissions. This may indicate deceptive intent or missing permission declarations.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
"""Scoped .env loader for Content Claw. Only loads declared keys."""

import os
from pathlib import Path
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(extra_keys: set[str] | None = None):
    """Load only allowed keys from .env into process environment."""
    allowed = ALLOWED_KEYS | (extra_keys or set())
    env_path = Path(__file__).parent.parent / ".env"
    if not env_path.exists():
        return
    for line in env_path.read_text().splitlines():
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(extra_keys: set[str] | None = None):
    """Load only allowed keys from .env into process environment."""
    allowed = ALLOWED_KEYS | (extra_keys or set())
    env_path = Path(__file__).parent.parent / ".env"
    if not env_path.exists():
        return
    for line in env_path.read_text().splitlines():
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
def load_env(extra_keys: set[str] | None = None):
    """Load only allowed keys from .env into process environment."""
    allowed = ALLOWED_KEYS | (extra_keys or set())
    env_path = Path(__file__).parent.parent / ".env"
    if not env_path.exists():
        return
    for line in env_path.read_text().splitlines():
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp1

High
Category
MCP Least Privilege
Confidence
92% confidence
Finding
This extractor performs broad outbound network access to arbitrary user-supplied URLs via Playwright and httpx, but the capability is not declared or constrained. In an agent skill context, undeclared network access is risky because it can be used for SSRF-style access to internal resources, metadata endpoints, or unintended third-party transmission without clear user awareness.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
f"\n\n{content_description}"
        )

    return prompt


FAL_MODELS = {
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Vague Triggers

Medium
Confidence
97% confidence
Finding
The trigger phrases are broad and overlap with ordinary user requests like 'generate content' or 'make a post from this.' In agent ecosystems with automatic skill routing, that can cause unintended invocation of a skill that performs external fetches, browser automation, file writes, and API-backed actions, expanding the attack surface without deliberate user intent.

Session Persistence

Medium
Category
Rogue Agent
Content
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - Glob
  - Grep
Confidence
76% confidence
Finding
The skill is explicitly designed to persist specs, generated content, metadata, topics, and brand graphs across runs using Write/Edit permissions. Persistent storage is not inherently malicious, but it does create privacy and integrity risks if sensitive source material, URLs, or derived metadata are retained longer than the user expects.

Intent-Code Divergence

Medium
Confidence
96% confidence
Finding
The skill claims it only accesses files within BASE_DIR, but instructs resolution of BASE_DIR by reading symlink targets under the user's home directory. Even limited metadata access outside the declared boundary weakens the trust model and can expose filesystem layout or resolve to an unexpected target if the symlink is tampered with. In a security-sensitive agent environment, boundary contradictions are dangerous because users may rely on the narrower scope guarantee.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
### Auto-discovery during brand creation

After completing the brand graph wizard (all 6 questions answered and files saved), automatically run topic discovery:

1. Tell the user: "Brand graph saved. Now discovering trending topics for <brand-name>..."
2. Run the topic discovery script with the new brand directory
Confidence
88% confidence
Finding
Automatically running topic discovery after brand creation initiates external-network activity and data processing without a separate confirmation step. Because this uses Exa and brand-derived inputs, it can transmit user-provided business context externally and create unexpected side effects, especially if the user only intended to save configuration.

Static analysis

No suspicious patterns detected.