Back to skill

Security audit

ClawSwarm

Security checks for vulnerabilities and agentic risk

Overview

This forecasting skill does what it claims, but its configurable API endpoint can expose chosen environment secrets and prompt data if a user runs an unsafe config.

Review this before installing if you may run configs from other people or use sensitive environment variables. Only run configs you trust, avoid direct api_key values in shared files, prefer official provider URLs or local Ollama, and keep agent counts and delays within a deliberate budget.

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/swarm_runner.py:98
Finding
Arbitrary Environment Secret Disclosure Through a Configurable API Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/swarm_runner.py`, lines 98 and 106-136 **Vulnerability Type**: Credential disclosure and server-side request forgery through untrusted configuration **Risk Level**: High ### Vulnerable Code ```python api_key = os.environ.get( api_config.get('api_key_env', 'GROQ_API_KEY'), api_config.get('api_key', '') ) base_urls = { 'groq': 'https://api.groq.com/openai/v1/chat/completions', 'openai': 'https://api.openai.com/v1/chat/completions', 'ollama': 'http://localhost:11434/v1/chat/completions', } url = api_config.get('base_url') or base_urls.get( provider, base_urls['groq'] ) headers = {'Content-Type': 'application/json'} if api_key: headers['Authorization'] = f'Bearer {api_key}' payload = { 'model': model, 'messages': [ {'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': user_msg} ], 'max_tokens': max_tokens, 'temperature': agent['temperature'] } try: if HAS_REQUESTS: r = requests.post( url, json=payload, headers=headers, timeout=30 ) ``` ### Technical Analysis The configuration independently controls both `api_key_env` and `base_url`. The program retrieves the value of the named environment variable and places it in the HTTP `Authorization` header without verifying that the destination is authorized to receive that credential. There is no: - Allowlist of approved API hosts. - Binding between a provider, its official endpoint, and its expected credential variable. - Restriction against private, loopback, link-local, or cloud metadata destinations. - HTTPS requirement for custom remote endpoints. - User confirmation before transmitting a credential to an overridden endpoint. - Restriction on which environment-variable names may be selected. Consequently, anyone able to supply or modify the configuration can select an environment variable availabl ...[truncated 2035 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define an explicit endpoint allowlist for every supported provider: ```python PROVIDERS = { "groq": { "url": "https://api.groq.com/openai/v1/chat/completions", "key_env": "GROQ_API_KEY", }, "openai": { "url": "https://api.openai.com/v1/chat/completions", "key_env": "OPENAI_API_KEY", }, } ``` 2. Bind each provider to its expected credential-variable name rather than accepting an arbitrary environment-variable name from configuration. 3. Disable `base_url` overrides by default. If custom endpoints are necessary: - Require an explicit command-line opt-in. - Display the destination hostname before execution. - Require confirmation before attaching credentials. - Maintain a separate credential specifically authorized for that endpoint. 4. Require HTTPS for all non-loopback endpoints. Permit plaintext HTTP only for a verified loopback Ollama address. 5. Resolve the destination hostname and reject loopback, private, link-local, multicast, reserved, and cloud metadata addresses unless an explicit local-provider mode requires them. 6. Revalidate the resolved address after redirects or disable redirects entirely to prevent redirect-based allowlist bypasses. 7. Never forward a provider credential to a host that does not match the provider's approved hostname. 8. Document that configuration files are security-sensitive and must not be accepted from untrusted sources without review. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/swarm_runner.py:74
Finding
Unbounded Agent Expansion and API Execution Permit Resource Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/swarm_runner.py`, lines 74-88 and 163-210 **Vulnerability Type**: Uncontrolled resource consumption and unbounded external API usage **Risk Level**: Medium ### Vulnerable Code ```python def build_agents(config): """Expand agent groups into individual agent specs.""" agents = [] for group in config.get('agents', []): count = group.get('count', 1) t_range = group.get('temperature_range', [0.5, 0.5]) t_min, t_max = t_range[0], t_range[-1] for i in range(count): t = t_min + (t_max - t_min) * ( i / max(1, count - 1) ) if count > 1 else t_min agents.append({ 'role': group['role'], 'model': group.get('model'), 'temperature': round(t, 3), 'index': len(agents) }) return agents ``` ```python def run_swarm(config, dry_run=False): """Run the full swarm prediction pipeline.""" target = config['target'] api_config = config.get('api', {}) consensus_config = config.get('consensus', {}) delay_ms = api_config.get('delay_ms', 1200) agents = build_agents(config) total = len(agents) predictions = [] ok, fail = 0, 0 for i, agent in enumerate(agents): result = call_llm(agent, target, api_config) if result: anchor = target['current_price'] max_dev = consensus_config.get( 'max_deviation', 0.15 ) if abs(result['price'] - anchor) / anchor <= max_dev: predictions.append(result) ok += 1 else: fail += 1 else: fail += 1 if i < total - 1: time.sleep(delay_ms / 1000.0) ``` ### Technical Analysis Configuration values are used without schema validation or upper bounds. In particular, each agent group's `count` is passed directly to `ra ...[truncated 2187 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Validate the complete configuration against a strict schema before creating agents or making requests. 2. Impose conservative limits, including: - Maximum agents per group. - Maximum total agents per run. - Maximum number of groups. - Minimum and maximum delay. - Maximum response-token count. - Valid temperature range. - Positive, finite target prices and consensus values. 3. Require explicit confirmation above a safe agent threshold and display an estimated request count and cost before execution. 4. Add a configurable but hard-capped request budget: ```python MAX_TOTAL_AGENTS = 1000 total_requested = sum(group.get("count", 1) for group in groups) if not isinstance(total_requested, int): raise ValueError("Agent count must be an integer") if total_requested < 1 or total_requested > MAX_TOTAL_AGENTS: raise ValueError("Total agent count is outside the allowed range") ``` 5. Constrain delay values: ```python if not isinstance(delay_ms, (int, float)): raise ValueError("delay_ms must be numeric") if delay_ms < 0 or delay_ms > 60000: raise ValueError("delay_ms must be between 0 and 60000") ``` 6. Consider generating agents lazily instead of materializing the complete list in memory. 7. Add global execution controls such as: - Maximum wall-clock duration. - Maximum failed-request count. - Maximum retry count. - Maximum API spend or token budget. - Graceful cancellation support. 8. Reject non-finite numeric values such as `NaN` and infinity throughout the configuration and consensus input. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (9)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill advertises executable usage that implies shell execution, file reads, environment variable access, and outbound network access, but it does not declare any explicit tool scope or permissions boundary. That omission can cause an agent or user to run the skill with broader capabilities than expected, increasing the risk of unintended command execution, data exposure from local files/env vars, or uncontrolled external requests.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill encourages sending target names, prices, and free-form context to external LLM providers, but the description does not warn users that this data leaves the local environment. In practice, users may include proprietary trading signals, internal research, or sensitive market context, creating an avoidable confidentiality and compliance risk when transmitted to third-party APIs.

External Transmission

Medium
Category
Data Exfiltration
Content
provider: groq          # groq | openai | ollama
    model: llama-3.3-70b-versatile
    api_key_env: GROQ_API_KEY   # env var name
    base_url: https://api.groq.com/openai/v1/chat/completions  # optional override
    max_tokens: 150
    delay_ms: 1200          # delay between requests
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
provider: groq          # groq | openai | ollama
    model: llama-3.3-70b-versatile
    api_key_env: GROQ_API_KEY   # env var name
    base_url: https://api.groq.com/openai/v1/chat/completions  # optional override
    max_tokens: 150
    delay_ms: 1200          # delay between requests
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The function transmits target data, free-form context, and bearer credentials to a configurable remote endpoint, including an arbitrary base_url override, without any trust boundary checks, allowlisting, or prominent disclosure to the user at execution time. In a skill that may process proprietary market context or internal forecasting data, this creates a real exfiltration risk and can also leak API keys to attacker-controlled endpoints if the config is modified.

External Transmission

Medium
Category
Data Exfiltration
Content
base_urls = {
        'groq': 'https://api.groq.com/openai/v1/chat/completions',
        'openai': 'https://api.openai.com/v1/chat/completions',
        'ollama': 'http://localhost:11434/v1/chat/completions',
    }
    url = api_config.get('base_url') or base_urls.get(provider, base_urls['groq'])
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
try:
        if HAS_REQUESTS:
            r = requests.post(url, json=payload, headers=headers, timeout=30)
            r.raise_for_status()
            data = r.json()
        else:
Confidence
90% confidence
Finding
This POST sends the assembled prompt content, including target name, current price, and arbitrary context, to an external service. Because the destination can be overridden by configuration and the same request may include a bearer token, the call can become a data and credential exfiltration channel if the config is malicious or careless.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
consensus_script = Path(__file__).parent / 'consensus.py'
    if consensus_script.exists():
        try:
            proc = subprocess.run(
                [sys.executable, str(consensus_script)],
                input=json.dumps(consensus_input),
                capture_output=True, text=True, timeout=10
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Low
Confidence
88% confidence
Finding
This markdown file documents both an environment-variable key and a direct `api_key` field, but it does not warn users that putting API keys directly into config files can expose secrets through source control, logs, or shared files. Because this is a skill description file and the documented behavior affects credential privacy, a brief warning is warranted.

Static analysis

No suspicious patterns detected.