Back to skill

Security audit

council-blackboard

Security checks for vulnerabilities and agentic risk

Overview

The skill appears purpose-built for OpenClaw/Open WebUI council collaboration, but it directly mutates Open WebUI's database and launches/stops background OpenClaw systemd jobs with under-disclosed scope.

Install only if you intentionally want a local Open WebUI/OpenClaw integration that can write Open WebUI chat records, keep council boards on disk, and launch background OpenClaw sessions. Review the configured database path and executable override environment variables first, and prefer running it in a dedicated local account or test WebUI profile until retention and cleanup expectations are clear.

Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (10)

Tainted flow: 'systemctl' from os.environ.get (line 233, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
systemctl = os.environ.get("COUNCIL_SYSTEMCTL") or shutil.which("systemctl")
    if not systemctl:
        return {"available": False, "reason": "systemctl not found"}
    process = subprocess.run(
        [
            systemctl,
            "--user",
Confidence
76% confidence
Finding
The code allows the executable path for systemctl to be overridden by the COUNCIL_SYSTEMCTL environment variable and then executes it. In environments where an attacker can influence process environment or deployment configuration, this becomes arbitrary code execution under the Open WebUI user's privileges rather than a simple systemctl status query.

Tainted flow: 'command' from os.environ.get (line 203, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
def _run(command: list[str], timeout: int = 120) -> str:
    try:
        process = subprocess.run(
            command,
            text=True,
            capture_output=True,
Confidence
80% confidence
Finding
The generic _run wrapper executes commands assembled elsewhere from multiple environment-controlled paths, including PYTHON, helper script paths, and configured binaries. Because these values ultimately feed directly into subprocess.run, an attacker with control over environment variables or skill configuration can redirect execution to arbitrary programs, yielding code execution as the service user.

Tainted flow: 'systemctl' from os.environ.get (line 746, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
unit = (status.get("claim") or {}).get("unit")
            systemctl = os.environ.get("COUNCIL_SYSTEMCTL") or shutil.which("systemctl")
            if unit and systemctl:
                subprocess.run(
                    [systemctl, "--user", "stop", unit],
                    text=True,
                    capture_output=True,
Confidence
76% confidence
Finding
This code path also executes a binary path taken from COUNCIL_SYSTEMCTL without validation, here for stopping a unit. If environment/configuration tampering is possible, the attacker can replace systemctl with any executable and trigger code execution during cancellation flows.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill instructs use of shell execution and environment-driven behavior but does not declare permissions or boundaries for those capabilities. That creates an authorization and review gap: operators may approve the skill as low-risk while it can still invoke local scripts and consume sensitive environment configuration at runtime.

Context-Inappropriate Capability

Medium
Confidence
71% confidence
Finding
The script executes an external helper whose path is partly controlled by environment variables, extending trust beyond the visible code. In a skill context, that means a caller or surrounding environment can redirect execution to an unexpected script or interpreter, turning this council-room utility into an arbitrary local code-execution primitive under the current user's privileges.

Description-Behavior Mismatch

Medium
Confidence
86% confidence
Finding
The code scans for and selects a local Open WebUI SQLite database, including from an environment override, which is broader access than a simple blackboard helper would imply. In this skill context that increases danger because the script is not just managing its own files; it is discovering and preparing to mutate another application's persistent state, which can affect user conversations and application integrity.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
The script directly inserts rows into Open WebUI's chat and chat_message tables, bypassing any higher-level authorization, validation, auditing, or schema invariants that the application would normally enforce. In context this is more dangerous because it silently creates visible conversations on behalf of arbitrary user IDs, enabling spoofed messages, persistent data tampering, and possible corruption or privilege confusion within the WebUI state.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill description suggests collaboration and blackboard management, but this implementation launches external binaries and creates background systemd user services. That expands the skill from a data-coordination tool into a host-execution orchestrator, increasing blast radius if misconfigured or abused and making the operational risk materially higher than the manifest implies.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The cancellation feature reaches beyond council coordination into host control by stopping systemd user units. Even though the intended unit is related to this skill, the capability is broader than the advertised purpose and increases risk if route metadata or environment-controlled systemctl paths are manipulated.

Session Persistence

Medium
Category
Rogue Agent
Content
## Rules

1. Create a fresh board and Open WebUI room for every new council:
   `python skills/council-blackboard/scripts/council.py room --topic "..." --user-id USER_ID`
2. Give the user the returned `chat_url` immediately. The WebUI room is the visible transcript; the JSON board is the auditable source of truth.
3. Validate before every hop. Read the goal, typed entries, revision, next capability, and unresolved questions.
Confidence
84% confidence
Finding
The skill creates a persistent board and a visible WebUI room for each council session, then immediately shares a chat URL. Because the feature is explicitly designed for session handover and cross-model collaboration, it can retain user prompts, decisions, evidence, and operational context beyond the immediate interaction, increasing the risk of data leakage, unintended retention, or exposure to other participants/systems if access controls are weak.

Static analysis

No suspicious patterns detected.