Back to skill

Security audit

Multi-Council Decision Engine

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a legitimate decision-analysis helper, but it sends business prompts to external AI models and writes local prompt/cost logs without enough disclosure or controls.

Install only if you are comfortable sending submitted prompts, campaign briefs, venture ideas, and context to OpenRouter and possible downstream model providers. Avoid pasting secrets, customer records, regulated data, or confidential strategy unless you have an approved data-handling path. Review or disable the local prompt and cost logs, and use a virtual environment with pinned dependencies instead of the suggested system pip command.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
business_mind_tree.py:99
Finding
Unredacted Sensitive Business Data Is Transmitted to an External AI Provider<![CDATA[ ## Vulnerability Details **File Location**: `business_mind_tree.py`, lines 99–125 and 603–611 **Vulnerability Type**: External transmission of potentially sensitive input without data minimization **Risk Level**: Medium ### Complete Code Snippet ```python def _call_openrouter_primary(model: str, system: str, user: str, max_tokens: int) -> tuple: """Primary council backend. Uses OPENROUTER_API_KEY.""" try: from openai import OpenAI except ImportError: raise RuntimeError( "openai package not installed. " "Run: pip install openai --break-system-packages" ) api_key = os.environ.get("OPENROUTER_API_KEY") if not api_key: raise RuntimeError("OPENROUTER_API_KEY not set in environment") or_model = _to_or_model(model) client = OpenAI(api_key=api_key, base_url="https://openrouter.ai/api/v1") resp = client.chat.completions.create( model=or_model, max_tokens=max_tokens, messages=[ {"role": "system", "content": system}, {"role": "user", "content": user}, ], extra_headers={ "HTTP-Referer": os.environ.get("OPENROUTER_APP_URL", "https://github.com/openclaw"), "X-Title": os.environ.get("OPENROUTER_APP_NAME", "Multi-Council Decision Engine"), }, ) ``` The transmitted user value is assembled without filtering: ```python def _run_council(name: str, prompt: str, context: str = "") -> dict: """Generic council runner. Returns structured analysis dict.""" if name not in COUNCILS: return {"council": name, "ok": False, "error": f"unknown council: {name}"} cfg = COUNCILS[name] user = prompt.strip() if context.strip(): user += f"\n\nAdditional context:\n{context.strip()}" ``` ### Technical Analysis The Skill sends the complete caller-supplied prompt and optional context to OpenRouter over its chat-completions API. Gate functions can place venture pro ...[truncated 2726 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a documented data-handling boundary stating that prompts are transmitted to OpenRouter and may be routed to downstream model providers. 2. Require explicit caller confirmation before processing inputs classified as confidential, personal, regulated, or customer-provided. 3. Add a configurable preprocessing layer that detects or redacts: - API keys and bearer tokens - Passwords and private keys - Email addresses, phone numbers, and government identifiers - Payment and financial-account data - Other application-specific sensitive fields 4. Prefer structured inputs with allowlisted fields instead of accepting unrestricted serialized objects. 5. Add a `sensitive_data_policy` or equivalent callback so integrating applications can reject prohibited input before any network request. 6. Offer an approved local or private model backend for sensitive decisions. 7. Clearly expose the selected model and provider before submission, particularly when dynamic model selection can route content to different vendors. 8. Avoid sending identical sensitive material to every council where a minimized or purpose-specific subset would suffice. 9. Add automated tests confirming that known secret and PII patterns are rejected or redacted before `_call_openrouter_primary()` is reached. ]]>

T08 · Insecure Dependencies

Warning
Location
business_mind_tree.py:100
Finding
Unsafe Recommendation to Install an Unpinned Dependency into the System Python Environment<![CDATA[ ## Vulnerability Details **File Location**: `business_mind_tree.py`, lines 100–107 **Vulnerability Type**: Unpinned third-party dependency installation with system package protections bypassed **Risk Level**: Medium ### Complete Code Snippet ```python def _call_openrouter_primary(model: str, system: str, user: str, max_tokens: int) -> tuple: """Primary council backend. Uses OPENROUTER_API_KEY.""" try: from openai import OpenAI except ImportError: raise RuntimeError( "openai package not installed. " "Run: pip install openai --break-system-packages" ) ``` ### Technical Analysis When the `openai` module is unavailable, the Skill instructs the operator to install the latest package resolved under the unbounded name `openai`. The project does not include a lock file, a pinned version, or package hashes in the reviewed files. The command also uses `--break-system-packages`, which bypasses Python's externally managed environment safeguard. That safeguard exists to prevent pip from overwriting or conflicting with packages managed by the operating system. The package name is legitimate and there is no evidence that the Skill intentionally references a malicious or typosquatted package. The risk arises from mutable dependency resolution and the recommended installation context. A compromised package release, compromised transitive dependency, unexpected future version, or unsafe package-index configuration could execute installation or import-time code with the permissions of the operator running pip or the Skill. ### Attack Path 1. The Skill is invoked on a host where the `openai` module is not installed. 2. Importing `OpenAI` raises `ImportError`. 3. The displayed error directs the operator to run: `pip install openai --break-system-packages` 4. Pip resolves the current package and transitive dependencies without a project-controlled version lock or hashes. 5. If the selected package artifa ...[truncated 1287 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--break-system-packages` from all installation guidance. 2. Require installation in an isolated virtual environment, for example: ```bash python3 -m venv .venv . .venv/bin/activate python -m pip install --require-hashes -r requirements.txt ``` 3. Declare the `openai` dependency explicitly in project metadata or a requirements file. 4. Pin an audited compatible version rather than allowing unrestricted latest-version resolution. 5. Use a lock file and verified hashes for the package and its transitive dependencies. 6. Configure trusted package indexes explicitly in deployment documentation. 7. Run dependency vulnerability and provenance checks in continuous integration. 8. Document the supported Python and SDK versions. 9. Prefer a clear startup validation error that references the controlled installation documentation rather than embedding an invasive pip command in the runtime exception. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (12)

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

Critical
Category
Data Flow
Content
"https://openrouter.ai/api/v1/models",
            headers={"Authorization": f"Bearer {api_key}"},
        )
        with urllib.request.urlopen(req, timeout=10) as r:
            catalog = json.loads(r.read().decode())
        by_id = {m["id"]: m for m in catalog.get("data", [])}
        available = []
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose says the skill provides an 8-council decision engine, but the analysis indicates additional undeclared councils, extra analysis actions, live external API/model-catalog access, and local file writes. This mismatch can mislead operators about the skill's real behavior, causing them to approve or run code with broader capabilities and side effects than expected.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares required environment variables and implies code execution, file writes, and network access, but does not declare an explicit tool/permission scope. That weakens user and platform visibility into what the skill can do and increases the chance of overbroad execution in hosts that rely on manifest scoping for safety decisions.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
User prompts and optional context are transmitted to external OpenRouter-hosted models, which can expose sensitive business or personal data to a third-party processor if users are unaware of the data flow. In this skill context, users are likely to submit strategic, competitive, operational, or compliance-sensitive information, making undisclosed external sharing materially risky.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The manifest describes a virtual board of 8 specialized reasoning frameworks: strategy, risk, market, operations, ethics, forecasting, execution, and AI-engineering. This file also defines CONTENT_PROMPT and SOCIAL_MEDIA_PROMPT and wires corresponding councils into COUNCILS, plus adds a competitive_differentiation_analysis function for local-business positioning, which expands the skill beyond the declared decision-engine scope.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The code logs a preview of the user's prompt to local files without explicit notice, which can persist confidential strategy, market, tax, or operational details on disk where other local users, backup systems, or support staff may later access them. Because this skill is designed for decision support on sensitive business matters, even truncated prompt logging can leak valuable or regulated information.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The public API docstring says run_campaign_gate runs a content council, and the implementation passes "content" in the councils list. However, the import block imports content_council but not a symbol named content, creating a mismatch between the documented available councils and what the imported module interface suggests.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The module persistently writes venture_key, gate type, timestamps, and cost data to a local JSON file even though the skill is described as a decision-evaluation/synthesis component. Persistent undeclared storage increases the data-retention and privacy surface, and if briefs or venture identifiers are sensitive this creates an audit artifact that operators may not expect or control.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Campaign briefs, content text, and venture ideas are packaged into prompts and sent to external council functions without any visible disclosure, consent, or data-classification checks in this file. If these councils are backed by remote LLM/services, sensitive business plans, marketing copy, or regulated content may be transmitted off-box unexpectedly, creating confidentiality and compliance risk.

Missing User Warnings

Low
Confidence
85% confidence
Finding
For markdown files, this rule applies when the description omits warnings about behaviors that could affect user data, privacy, or system integrity. The setup instructs users to provide `OPENROUTER_API_KEY`, and later the document notes that usage is logged to `cost_log.json`, but there is no explicit user-facing warning that the skill will use external model services and create a local log file.

Description-Behavior Mismatch

Low
Confidence
82% confidence
Finding
The manifest description focuses on independent reasoning frameworks producing a go/hold/kill verdict. However, the documented behavior also includes dynamic model selection across external models and logging costs to `cost_log.json`, which are extra operational behaviors not conveyed by the manifest description. These may be implementation details, but the file-writing side effect is substantive enough to merit disclosure.

Intent-Code Divergence

Low
Confidence
92% confidence
Finding
The top-level docstring lists the public actions 'registered via get_actions()' and presents a specific set, but the code later defines content_council and social_media_council and exposes content through COUNCILS/listing behavior without documenting it there. This is not just incomplete implementation detail because the documentation explicitly claims to enumerate the registered public actions.

Static analysis

No suspicious patterns detected.