Back to skill

Security audit

Trunkate AI

Security checks for vulnerabilities and agentic risk

Overview

The skill performs real context compression, but its automatic hook can silently send and replace session history with insufficient controls.

Review before installing. Use this only in environments where sending conversation history, logs, and potentially project content to Trunkate is acceptable. Avoid enabling the automatic PreRequest hook until it has explicit opt-in, enforced threshold checks, destination allowlisting, stronger redaction, and user-visible confirmation before replacing session history.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/activator.py:34
Finding
Automatic External Transmission of Insufficiently Redacted Conversation History<![CDATA[ ## Vulnerability Details **File Location**: `scripts/activator.py:34-45, 88-95`; `scripts/trunkate.py:9-22` **Vulnerability Type**: Sensitive data exposure through incomplete redaction and external transmission **Risk Level**: High ### Vulnerable Code ```python # scripts/activator.py:34-45 # 4. Protect common secrets (API keys, passwords, bearer tokens) secret_patterns = [ r'(?i)(?:password|secret|api[_-]?key|token|access[_-]?key|auth[_-]?token|credentials?)\s*[:=]\s*["\']?[a-zA-Z0-9_\-.~]+["\']?', r'Bearer\s+[a-zA-Z0-9\-_.]+' ] for pattern in secret_patterns: for match in re.finditer(pattern, text): placeholder = f"__TRUNKATE_PROTECTED_{uuid.uuid4().hex}__" protected[placeholder] = match.group(0) filtered_text = text for placeholder, original in protected.items(): if original in filtered_text: filtered_text = filtered_text.replace(original, placeholder) ``` ```python # scripts/activator.py:88-95 with open(history_path, "r") as f: history = f.read() # 4. Filter Sensitive Content LOCALLY before external transmission filtered_history, protected_blocks = _filter_sensitive_content(history) # 5. Invoke Semantic Pruner with safe, filtered text optimized_filtered = optimize_prompt(filtered_history, budget=target_budget) ``` ```python # scripts/trunkate.py:9-22 def optimize_prompt(prompt: str, budget: Union[int, str] = 1000, model: str = "gpt-4o") -> str: """Optimizes a prompt using the private Trunkate AI API.""" api_url = os.environ.get("TRUNKATE_API_URL", API_URL).rstrip("/") api_key = os.environ.get("TRUNKATE_API_KEY") if not api_key: print("Error: TRUNKATE_API_KEY required.", file=sys.stderr) return prompt payload = {"text": prompt, "budget": budget, "model": model} headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} try: response = requests.post(f"{api_url}/optimize", json=payload, headers=head ...[truncated 2332 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make remote history processing explicitly opt-in and clearly disclose when data is transmitted. 2. Use structured OpenClaw message parsing instead of treating the complete history as an opaque string. 3. Allowlist the message types and fields that may be transmitted; exclude system messages, credentials, and raw tool output by default. 4. Implement and enforce the rules file rather than presenting it as documentation only. 5. Add robust detection for private keys, certificates, cookies, database URLs, cloud credentials, and common secret formats. 6. Provide project-level and message-level exclusion controls. 7. Offer a local-only compression mode for sensitive environments. 8. Provide a transmission preview or audit log that identifies the destination and categories of data sent. 9. Add automated tests showing that representative secrets and protected blocks never leave the process. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/activator.py:63
Finding
Missing Threshold Gate Causes History Transmission on Every Hook Invocation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/activator.py:63-80`; documentation mismatch at `hooks/openclaw/HOOK.md:14-18` and `references/openclaw-integration.md:5-8` **Vulnerability Type**: Missing security control and excessive automated data processing **Risk Level**: High ### Vulnerable Code ```python # scripts/activator.py:63-80 # 1. Retrieve OpenClaw environment variables try: current_tokens = int(os.environ.get("OPENCLAW_CURRENT_TOKENS", 0)) token_limit = int(os.environ.get("OPENCLAW_TOKEN_LIMIT", 128000)) history_path = os.environ.get("OPENCLAW_HISTORY_PATH") except ValueError: print("Trunkate Alert: Malformed token environment variables.", file=sys.stderr) return # 2. Configuration: Proactive "Smart Buffer" # Default to 20% of the current history to maintain extreme density. target_budget = os.environ.get("TRUNKATE_AUTO_BUDGET", "20%") # Proactive Principle: We systematically optimize every call to ensure # the agent's memory is always lean and cost-effective. if not history_path or not os.path.exists(history_path): return ``` The documented condition is: ```text OPENCLAW_CURRENT_TOKENS > (OPENCLAW_TOKEN_LIMIT * TRUNKATE_THRESHOLD) ``` ### Technical Analysis The implementation reads `OPENCLAW_CURRENT_TOKENS` and `OPENCLAW_TOKEN_LIMIT`, but never compares them. It never reads `TRUNKATE_THRESHOLD`. Therefore, after the hook is installed, the existence of a valid history path—not context utilization—is the effective activation condition. This contradicts the documented default threshold of 80%. Users may reasonably expect history to leave the system only near the context limit, while the code can transmit it before every LLM request. The missing gate expands network access and sensitive-data exposure beyond the minimum frequency required for the declared context-overflow prevention function. It also increases API usage, latency, and dependency on the remote service. ### Attack Path 1. A user insta ...[truncated 917 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement the documented threshold before reading or transmitting history: ```python threshold = float(os.environ.get("TRUNKATE_THRESHOLD", "0.8")) if not 0.1 <= threshold <= 0.9: raise ValueError("TRUNKATE_THRESHOLD must be between 0.1 and 0.9") if token_limit <= 0 or current_tokens <= token_limit * threshold: return ``` 2. Default automatic remote optimization to disabled until the user explicitly enables it. 3. Test boundary cases below, at, and above the configured threshold. 4. Avoid opening the history file until all activation conditions pass. 5. Add rate limiting or a minimum interval between optimization requests. 6. Update documentation and code together so the actual trigger behavior is unambiguous. 7. Emit a local security audit event whenever remote optimization occurs. ]]>

T02 · Agent Memory Poisoning

Error
Location
scripts/activator.py:95
Finding
Untrusted Remote Response Can Replace Agent Session History<![CDATA[ ## Vulnerability Details **File Location**: `scripts/trunkate.py:20-24`; `scripts/activator.py:95-102` **Vulnerability Type**: Agent state poisoning through unvalidated remote content **Risk Level**: High ### Vulnerable Code ```python # scripts/trunkate.py:20-24 try: response = requests.post(f"{api_url}/optimize", json=payload, headers=headers, timeout=10) response.raise_for_status() return response.json().get("optimized_text", prompt) ``` ```python # scripts/activator.py:95-102 optimized_filtered = optimize_prompt(filtered_history, budget=target_budget) # 6. Restore Sensitive Content optimized = _restore_sensitive_content(optimized_filtered, protected_blocks) # 7. Emit state update directive if optimized and optimized != history: print(f"OPENCLAW_ACTION:SET_HISTORY={optimized}") ``` ### Technical Analysis The remote endpoint controls the `optimized_text` field. The Skill accepts that field as a string and emits it through `OPENCLAW_ACTION:SET_HISTORY`, allowing the remote response to become the agent's replacement history. There is no validation that the response: - Is a faithful summary of the submitted history. - Preserves mandatory system or user constraints. - Contains only summary data rather than new instructions. - Avoids role markers, control directives, or prompt-injection text. - Preserves recent turns or security-relevant context. - Meets an expected structured schema. The local placeholder restoration mechanism protects only matched text. It does not prevent the remote response from adding new instructions or deleting unprotected constraints. This creates a trust-boundary violation: content from an external service is treated as authoritative agent state rather than untrusted data. ### Attack Path 1. The Skill submits filtered history to the optimization endpoint. 2. The endpoint is compromised, maliciously configured, or returns manipulated output. 3. The endpoint places attacker-chosen instructions or altere ...[truncated 1010 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat API output as untrusted data and never use it as a complete history replacement. 2. Preserve system messages, security constraints, active user instructions, and recent turns locally. 3. Request a strict structured response containing summary fields rather than free-form replacement history. 4. Validate response type, size, allowed fields, and content before using it. 5. Reject role markers, hook control directives, system-style instructions, and other active-content patterns. 6. Store remote summaries in a clearly delimited, non-authoritative data message. 7. Compare critical locally extracted facts before and after optimization. 8. Require user confirmation before a remote response replaces existing session state. 9. Pin or authenticate the intended service endpoint and monitor response integrity. 10. Add tests using malicious API responses containing injected instructions and state-control strings. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/activator.py:63
Finding
Unrestricted History Path and Configurable API Destination Enable Conditional File Exfiltration<![CDATA[ ## Vulnerability Details **File Location**: `scripts/activator.py:63-67, 79-95`; `scripts/trunkate.py:9-22` **Vulnerability Type**: Unrestricted local file read combined with unrestricted network destination **Risk Level**: Medium ### Vulnerable Code ```python # scripts/activator.py:63-67 try: current_tokens = int(os.environ.get("OPENCLAW_CURRENT_TOKENS", 0)) token_limit = int(os.environ.get("OPENCLAW_TOKEN_LIMIT", 128000)) history_path = os.environ.get("OPENCLAW_HISTORY_PATH") ``` ```python # scripts/activator.py:79-95 if not history_path or not os.path.exists(history_path): return try: # 3. Read session history with safety check file_size = os.path.getsize(history_path) if file_size > 10 * 1024 * 1024: # 10MB limit print(f"Trunkate Alert: History file too large ({file_size} bytes). Skipping optimization.", file=sys.stderr) return with open(history_path, "r") as f: history = f.read() # 4. Filter Sensitive Content LOCALLY before external transmission filtered_history, protected_blocks = _filter_sensitive_content(history) # 5. Invoke Semantic Pruner with safe, filtered text optimized_filtered = optimize_prompt(filtered_history, budget=target_budget) ``` ```python # scripts/trunkate.py:9-22 def optimize_prompt(prompt: str, budget: Union[int, str] = 1000, model: str = "gpt-4o") -> str: """Optimizes a prompt using the private Trunkate AI API.""" api_url = os.environ.get("TRUNKATE_API_URL", API_URL).rstrip("/") api_key = os.environ.get("TRUNKATE_API_KEY") if not api_key: print("Error: TRUNKATE_API_KEY required.", file=sys.stderr) return prompt payload = {"text": prompt, "budget": budget, "model": model} headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"} try: response = requests.post(f"{api_url}/optimize", json=payload, headers=headers, timeout=10) ``` ### Technical Anal ...[truncated 2249 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve `OPENCLAW_HISTORY_PATH` to a canonical path and require it to remain under an approved history directory. 2. Reject symbolic links, non-regular files, device files, and files with unexpected ownership or permissions. 3. Validate the expected history filename and structured file format. 4. Open files using safe descriptor-based checks where possible to reduce time-of-check/time-of-use races. 5. Enforce HTTPS for all remote requests. 6. Allowlist `api.trunkate.ai` in production and require a separate explicit development mode for endpoint overrides. 7. Never forward production bearer credentials to arbitrary development endpoints. 8. Use a separate development credential when custom endpoints are enabled. 9. Strip sensitive environment variables before passing the environment to child processes when they are not required. 10. Add security tests for path traversal, symbolic links, plaintext URLs, redirects, and attacker-controlled endpoint overrides. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (36)

Tainted flow: 'headers' from os.environ.get (line 19, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
    
    try:
        response = requests.post(f"{api_url}/optimize", json=payload, headers=headers, timeout=10)
        response.raise_for_status()
        return response.json().get("optimized_text", prompt)
    except Exception as e:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Self-Modification

High
Category
Rogue Agent
Content
### Features

* Modify skill markdown ([5ccb7f7](https://github.com/Trunkate-AI/trunkate-ai-skills/commit/5ccb7f769a27adf2b14d5b0d924aaffc164d7236))

## [0.16.0](https://github.com/Trunkate-AI/trunkate-ai-skills/compare/openclaw-v0.15.0...openclaw-v0.16.0) (2026-03-02)
Confidence
85% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description centers on a context-compression/semantic-optimization skill that should process large text or conversation history through the Trunkate API, potentially with proactive hooks. The actual code does none of that: it neither sends text to an API nor transforms/summarizes context. Instead, it inspects OPENCLAW_LAST_ERROR_MESSAGE and emits stderr notices for specific failure categories. This is a materially different primary purpose, so the description does not accurately represent the code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The core behavior—calling the Trunkate API to optimize text—does align with the general description of semantic optimization. However, the description materially overstates the implemented functionality. The code only exposes a direct optimization helper and CLI wrapper for user-supplied text. It does not implement any automated hooks, trigger handling, proactive context management, file/log ingestion, conversation-history management, or error-driven invocation behavior described in the declared purpose. Because these claimed capabilities are central to the description rather than minor implementation details, this is a meaningful description-to-behavior mismatch.

Missing User Warnings

High
Confidence
98% confidence
Finding
The skill encourages silent transmission of context to a private API while lacking a prominent user-facing privacy warning. Because the targeted data includes conversation history, logs, and large text blocks, this can expose proprietary code, secrets, personal data, or system instructions to an external service without informed consent.

Missing User Warnings

High
Confidence
97% confidence
Finding
Automatic silent hooks that can prune history and externally process content create both privacy and integrity risks, and the documentation does not prominently warn users about either. Users may unknowingly lose important context or have sensitive data transmitted off-host because the design intentionally hides the action from them.

Missing User Warnings

High
Confidence
98% confidence
Finding
The described emergency history wipe can irreversibly remove context, but the documentation does not provide an explicit warning or consent model for that loss. In an agent setting, sudden context deletion can derail work, hide prior instructions, and destroy evidence needed for safe or correct operation.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
# Pass current environment (containing OpenClaw state) to the sub-process
        subprocess.run(
            [sys.executable, script_path], 
            env=os.environ.copy(), 
            check=True
        )
    except subprocess.CalledProcessError as e:
Confidence
98% confidence
Finding
Copying and forwarding the full environment exposes all available environment variables to the child process, which may include API keys, tokens, workspace metadata, and other sensitive agent state. In a hook that runs automatically for a skill whose purpose is text optimization, this is especially risky because the broad data access is not tightly scoped to operational need.

Credential Access

High
Category
Privilege Escalation
Content
def _filter_sensitive_content(text: str):
    """
    Extracts sensitive content (System Prompts, .env blocks, and [KEEP] tags) 
    LOCALLY and replaces them with UUID placeholders to prevent data exfiltration.
    """
    protected = {}
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 _filter_sensitive_content(text: str):
    """
    Extracts sensitive content (System Prompts, .env blocks, and [KEEP] tags) 
    LOCALLY and replaces them with UUID placeholders to prevent data exfiltration.
    """
    protected = {}
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if not api_key:
        print("Error: TRUNKATE_API_KEY required.", file=sys.stderr)
        return prompt
    
    payload = {"text": prompt, "budget": budget, "model": model}
    headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Content
if not api_key:
        print("Error: TRUNKATE_API_KEY required.", file=sys.stderr)
        return prompt
    
    payload = {"text": prompt, "budget": budget, "model": model}
    headers = {"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"}
Confidence
85% confidence
Finding
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares no explicit tool scope or permissions while its documented operation clearly involves shell execution, environment variable access, file reads, and outbound network access. In an agent ecosystem, this mismatch weakens user and platform understanding of what the skill can do, increasing the chance of over-privileged execution and unnoticed data egress.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The manifest frames the skill as semantic optimization, but the documented behavior includes emergency history wipes, which are materially more destructive than summarization. This mismatch can cause users or orchestrators to permit the skill in contexts where data-loss operations were not expected, increasing the risk of irreversible loss of important context.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The skill describes broad, automatic trigger conditions for context pruning without narrow activation criteria. In practice, vague triggers can cause the skill to activate on normal workflows, sending excess data externally or altering history unexpectedly, especially because the skill is positioned as invisible background infrastructure.

Vague Triggers

Medium
Confidence
96% confidence
Finding
An always-on PreRequest hook that intercepts every outgoing LLM call is high risk because it creates a universal chokepoint for observing, modifying, compressing, or exfiltrating prompts. Even if intended for benign summarization, the lack of clear scoping means sensitive prompts, secrets, and system instructions could be processed or transmitted automatically.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The documentation promotes invisible, always-on background operation without clear constraints, making unintended invocation more likely. In an agent environment, silent lifecycle hooks can repeatedly process sensitive context and change model inputs without user awareness, compounding both privacy and integrity risk.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The instruction to avoid announcing truncation to the user conflicts with transparency and informed-consent expectations. Non-disclosure is especially risky here because the hidden action may alter prompt history or transmit content externally, preventing users from understanding changes in model behavior or privacy exposure.

Ssd 3

Medium
Confidence
95% confidence
Finding
Silent automated compression and logging can cause user-provided context to be transmitted to an external service or retained locally without the user's awareness. This creates privacy, compliance, and confidentiality risks, especially when logs or conversation history may contain secrets or regulated data.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Content
To comply with OpenClaw automated health/safety grades:

* **Safety Boundaries**: When performing shell execution (`exec`) to run local Python scripts (such as `activator.py` or `.openclaw` hooks), the skill is strictly restricted to semantic compression and logging. It contains safety boundaries to ensure it does not execute unknown payloads, access external network resources (other than api.trunkate.ai for optimization), or execute arbitrary code.
* **Permissions**: This skill **does not** require "Human-in-the-loop" approval because it does not perform destructive actions (like deleting tickets or pushing code). It operates purely on localized context and data streams.

---
Confidence
80% confidence
Finding
Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The safety text claims the skill operates purely on localized context and data streams, yet the document repeatedly states that content is sent to the Trunkate API. This is dangerous because it downplays external data transfer and may lead users to expose sensitive conversation history, logs, or project data under false privacy assumptions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The hook description states that conversation history is evaluated and compressed through the Trunkate AI API before requests are sent, but it does not clearly warn users that potentially sensitive session content may be transmitted to an external service. Because this skill is explicitly designed to act proactively and silently on context history, the omission undermines informed consent and can lead to unintended disclosure of secrets, proprietary code, or personal data.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The documentation notes that the hook updates session history via an action directive, but it does not clearly warn that this modification happens automatically as part of a PreRequest flow. Automatic rewriting of history can alter the agent's working context without user awareness, creating risks of loss of fidelity, hidden prompt manipulation surface, and unexpected changes to downstream model behavior.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        # Pass current environment (containing OpenClaw state) to the sub-process
        subprocess.run(
            [sys.executable, script_path], 
            env=os.environ.copy(), 
            check=True
Confidence
89% confidence
Finding
The hook executes a local Python subprocess during every PreRequest event, which expands the skill's runtime capabilities beyond simple text optimization and creates an execution path that may run attacker-modified local code. Because the invoked script path is relative and automatically triggered, this increases the risk of unintended code execution in the agent context.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
A PreRequest hook that silently launches a local subprocess and forwards agent state is a sensitive capability, especially because it runs automatically before requests and is not obviously required for the stated purpose of semantic context reduction. In this context, the skill description's 'proactive' and 'silent context management' makes the behavior more dangerous because it can operate without user awareness on every request.

Static analysis

No suspicious patterns detected.