Back to skill

Security audit

Triumvirate Protocol

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real multi-model debate tool, but it should be reviewed because it reads local AI credentials and identity data, sends rich context to external providers, and handles some secrets unsafely.

Review before installing. Use only scoped API keys you are comfortable using with this tool, avoid sensitive identity data or private debate content, and assume identity summaries and transcripts may be stored locally and sent to Google or xAI when automated rounds or synthesis run.

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

Warning
Location
protocol.py:162
Finding
Gemini API Key Exposed in Request URL Query String<![CDATA[ ## Vulnerability Details **File Location**: `protocol.py`, lines 162–170 **Vulnerability Type**: API credential exposure through URL query parameters **Risk Level**: Medium ### Vulnerable Code ```python def call_gemini(prompt, api_key, max_tokens=2000): """Call Gemini API.""" url = f"{GEMINI_URL}?key={api_key}" payload = { "contents": [{"parts": [{"text": prompt}]}], "generationConfig": {"maxOutputTokens": max_tokens, "temperature": 0.8}, } req = urllib.request.Request( url, data=json.dumps(payload).encode(), headers={"Content-Type": "application/json"}, method="POST", ) ``` ### Technical Analysis The Gemini API key is appended directly to the request URL as the `key` query parameter. HTTPS protects the URL while it is in transit, but query strings are commonly captured by HTTP client instrumentation, proxy logs, gateway logs, debugging tools, exception telemetry, and monitoring systems. The key is legitimately required to access Gemini, and the request is sent to Google's official API endpoint. Therefore, this is not evidence of intentional credential exfiltration. However, placing the key in the URL creates avoidable exposure beyond the minimum necessary for the Skill's declared functionality. ### Attack Path 1. A user runs an automated debate round or synthesis operation. 2. `call_gemini` constructs a URL containing the user's Gemini API key. 3. A local monitoring tool, instrumented HTTP client, TLS-inspecting proxy, gateway, or diagnostic logger records the complete request URL. 4. An attacker who can access those records extracts the `key` query parameter. 5. The attacker submits requests to the Gemini API using the stolen key, subject to the key's configured API restrictions and quotas. This path requires access to request telemetry, logs, or local monitoring facilities; it is not remotely exploitable from the code alone. ### Impact Assessment A disclosed key may allow unauthorized ...[truncated 308 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Use the provider-supported `x-goog-api-key` request header rather than a URL query parameter: ```python def call_gemini(prompt, api_key, max_tokens=2000): payload = { "contents": [{"parts": [{"text": prompt}]}], "generationConfig": { "maxOutputTokens": max_tokens, "temperature": 0.8, }, } req = urllib.request.Request( GEMINI_URL, data=json.dumps(payload).encode("utf-8"), headers={ "Content-Type": "application/json", "x-goog-api-key": api_key, }, method="POST", ) with urllib.request.urlopen(req, timeout=90) as resp: data = json.loads(resp.read()) return data["candidates"][0]["content"]["parts"][0]["text"] ``` Additional hardening measures: - Configure Google API restrictions so the key can access only the required Generative Language API. - Apply appropriate quotas and billing alerts. - Ensure request headers and exception objects are redacted before logging. - Rotate the key if complete request URLs may already have been retained. - Avoid printing or persisting constructed request objects that may include credentials. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
protocol.py:177
Finding
xAI Bearer Token and Sensitive Debate Payload Exposed Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `protocol.py`, lines 177–196 **Vulnerability Type**: Sensitive information exposure through subprocess command-line arguments **Risk Level**: Medium ### Vulnerable Code ```python def call_grok(prompt, api_key, max_tokens=2000): """Call Grok API via curl (Python 3.9 urllib gets 403 due to TLS fingerprint).""" import subprocess payload = json.dumps({ "model": "grok-4", "messages": [{"role": "user", "content": prompt}], "max_tokens": max_tokens, "temperature": 0.8, }) proc = subprocess.run( ["curl", "-s", "--max-time", "120", "https://api.x.ai/v1/chat/completions", "-H", "Content-Type: application/json", "-H", f"Authorization: Bearer {api_key}", "-d", payload], capture_output=True, text=True, timeout=130, ) if proc.returncode != 0: raise RuntimeError(f"curl failed: {proc.stderr[:200]}") data = json.loads(proc.stdout) ``` ### Technical Analysis The code invokes `curl` with both the xAI bearer token and the complete JSON request body as command-line arguments. The payload can contain: - Structured identity beliefs, traits, and contradictions - The debate topic - Full prior conversation history - Participant prompts and generated context On systems where process command lines are observable, these values may be captured by process-listing utilities, endpoint monitoring agents, audit systems, crash diagnostics, or process telemetry. Although arguments are passed as a list and no shell is enabled—so this is not shell command injection—the exposure of secrets in the process argument vector remains a security weakness. Sending identity context and debate history to xAI is consistent with the Skill's documented multi-provider, identity-aware debate function. The excessive behavior is the use of public process arguments as the transport mechanism, not the provider request itself. ### Attack ...[truncated 1338 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Prefer an in-process HTTPS client so the token and payload are never placed in a child process's argument vector. For example, use `urllib.request` or a carefully maintained HTTP library and provide the token only as an HTTP header. If `curl` is operationally required: - Pass the request body through standard input by using `--data-binary @-`. - Avoid including the bearer token directly in command-line arguments. - Supply sensitive curl configuration through a protected, short-lived file with permissions set to `0600`, then delete it immediately after use. - Ensure temporary files are created securely and are not placed in shared or predictable locations. - Disable or redact process-command telemetry for this operation where organizational policy permits. - Rotate the xAI token if process arguments may already have been collected. - Scope the token to the minimum available permissions and configure usage limits and billing alerts. - Clearly notify users that identity attributes and full debate transcripts are transmitted to external AI providers. - Encourage users to exclude credentials, private keys, personal data, and other secrets from identity graphs and debate messages. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
YOUR RESPONSE (as {my_info['name']}, Round {round_num}):"""

    return prompt


def call_gemini(prompt, api_key, max_tokens=2000):
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The skill advertises multi-provider debates and identity-aware context, but it does not clearly warn users that debate prompts, thread history, and identity snapshots may be transmitted to third-party AI providers. This creates a real privacy and data-governance risk because users may supply sensitive personal or organizational information without informed consent, especially given the persistent thread/history design.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
"max_tokens": max_tokens,
        "temperature": 0.8,
    })
    proc = subprocess.run(
        ["curl", "-s", "--max-time", "120",
         "https://api.x.ai/v1/chat/completions",
         "-H", "Content-Type: application/json",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

External Transmission

Medium
Category
Data Exfiltration
Content
})
    proc = subprocess.run(
        ["curl", "-s", "--max-time", "120",
         "https://api.x.ai/v1/chat/completions",
         "-H", "Content-Type: application/json",
         "-H", f"Authorization: Bearer {api_key}",
         "-d", payload],
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
98% confidence
Finding
The skill builds prompts containing identity graph data and full transcript history, then sends that material to external model providers without any explicit consent, warning, or minimization step. Because identity data may contain sensitive beliefs, traits, contradictions, or profile metadata, this creates a real privacy and data-governance exposure.