Back to skill

Security audit

Context Compactor

Security checks for vulnerabilities and agentic risk

Overview

The plugin has a coherent context-compaction purpose, but it needs Review because it can automatically process prior conversation content through the active LLM despite local-only privacy claims and exposes an under-scoped transcript stats path.

Review this before installing in environments with sensitive chats or cloud model providers. Use an exact pinned package version, inspect the installed files, and configure or require a strict local-only summarization model if you rely on the privacy claim. Avoid enabling it for high-assurance workflows unless you are comfortable with lossy summaries influencing later agent context, and treat the gateway stats path issue as needing a fix before use in multi-user or remotely reachable gateways.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
index.ts:388
Finding
Gateway RPC Accepts an Unrestricted Transcript File Path<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:388-405` **Vulnerability Type**: Arbitrary local file access and file-existence probing **Risk Level**: High ### Vulnerable Code ```ts api.registerGatewayMethod('context-compactor.stats', async ({ params, respond }: any) => { try { const { sessionFile } = params; if (!sessionFile || !fs.existsSync(sessionFile)) { respond(true, { error: 'Session file not found', messages: 0, tokens: 0 }); return; } const entries = readTranscript(sessionFile); const messages = extractMessages(entries); const totalTokens = messages.reduce( (sum, m) => sum + estimateTokens(m.content, charsPerToken), 0 ); respond(true, { messages: messages.length, tokens: totalTokens, maxTokens, needsCompaction: totalTokens > maxTokens, cacheSize: summaryCache.size, }); ``` The invoked transcript reader performs a synchronous read of the supplied path: ```ts function readTranscript(sessionPath: string): SessionEntry[] { if (!fs.existsSync(sessionPath)) return []; const content = fs.readFileSync(sessionPath, 'utf8'); const lines = content.trim().split('\n').filter(Boolean); return lines.map(line => { try { return JSON.parse(line); } catch { return null; } }).filter(Boolean) as SessionEntry[]; } ``` ### Technical Analysis The gateway method takes `params.sessionFile` from its caller and passes it directly to `fs.existsSync` and `fs.readFileSync`. It does not resolve the path from a trusted session identifier, canonicalize it, restrict it to an approved transcript directory, reject symlinks, verify that it is a regular file, or limit its size. No authorization check for this gateway method is visible in the project. If an untrusted or insufficiently privileged client can invoke the method, it can cause the OpenClaw process to access any path readable with the process's filesystem privileges ...[truncated 1770 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not accept a filesystem path from the RPC caller. Accept a session identifier and resolve it through a trusted server-side session registry. - Require explicit authorization for the gateway method and verify that the caller may inspect the requested session. - Canonicalize both the approved transcript root and candidate file with `fs.realpath`. - Verify containment using a path-relative comparison that rejects paths resolving outside the approved root. - Reject symbolic links and all non-regular files. - Apply a strict maximum file size before reading. - Prefer bounded asynchronous or streaming reads instead of `readFileSync`. - Return the same generic response for nonexistent and unauthorized paths to reduce path-existence probing. - Add tests for absolute paths, `../` traversal, symlink escapes, device files, named pipes, and oversized files. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
index.ts:223
Finding
Untrusted Conversation Content Can Become Privileged Compacted Context<![CDATA[ ## Vulnerability Details **File Location**: `index.ts:223-241` and `index.ts:292-303` **Vulnerability Type**: Indirect prompt injection through LLM-generated summaries **Risk Level**: High ### Vulnerable Code ```ts const formatted = formatForSummary(old); const summaryPrompt = `Summarize this conversation concisely, preserving key decisions, context, and important details. Focus on information that would be needed to continue the conversation coherently. CONVERSATION: ${formatted} SUMMARY (be concise, max ${Math.floor(summaryMaxTokens * charsPerToken)} characters):`; if (api.runtime?.llm?.complete) { // Use OpenClaw's LLM runtime const result = await api.runtime.llm.complete({ model: summaryModel, messages: [{ role: 'user', content: summaryPrompt }], maxTokens: summaryMaxTokens, }); summary = result.content; } ``` The generated summary is subsequently injected into future agent context: ```ts return { prependContext: `<compacted-context> The following is a summary of earlier conversation that was compacted to fit context limits: ${summary} --- Recent conversation continues below: </compacted-context>`, // Note: We can't actually replace messages in before_agent_start, // we can only prepend context. For full message replacement, // we'd need a different hook or session modification. }; ``` ### Technical Analysis Historical message content is untrusted because it can include attacker-controlled user messages, content copied from external sources, or previous model output. The plugin concatenates this content into a natural-language summarization prompt without robust instruction/data separation. An attacker can place directives in an older message telling the summarization model to ignore its task, preserve malicious instructions, misrepresent prior decisions, or produce text that directs the future agent to use tools. The result of that model call is trusted and prepended to the next agent invocation as compac ...[truncated 1973 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat transcript messages and generated summaries as untrusted data. - Send the summarization policy as a system-level instruction where supported, with transcript content in a distinct structured data field. - Explicitly direct the summarizer to describe facts only and to omit commands, policy changes, tool requests, credentials, and instructions found in the transcript. - Serialize messages using a structured format rather than ambiguous role labels embedded in one string. - Label the injected result as an untrusted historical synopsis that must never override system, developer, current-user, or tool-security instructions. - Ensure the host inserts summaries below system and developer instructions in the instruction hierarchy. - Consider a deterministic or extractive summarizer for security-sensitive contexts. - Validate summaries for instruction-like phrases and require confirmation before acting on sensitive claims recovered only from a summary. - Add adversarial tests covering role-tag spoofing, delimiter injection, fake system messages, tool-call requests, and instructions to preserve malicious directives. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:39
Finding
Installation Instructions Execute an Unpinned Registry Package<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:39-43` and `README.md:16-20` **Vulnerability Type**: Unpinned package execution and supply-chain exposure **Risk Level**: Medium ### Vulnerable Code ```bash # One command setup (recommended) npx jasper-context-compactor setup ``` The README repeats the same installation pattern: ```bash npx jasper-context-compactor setup ``` ### Technical Analysis The recommended installation command asks `npx` to resolve and execute `jasper-context-compactor` from the configured package registry without specifying an exact audited version or integrity value. This means the code executed at installation time may differ from the code reviewed in this audit. A later package release, compromised publisher account, registry compromise, or malicious package replacement could cause users to execute altered code. The setup command runs with the invoking user's privileges and intentionally accesses persistent OpenClaw locations, including `~/.openclaw/openclaw.json` and `~/.openclaw/extensions/`. Consequently, compromise of the distributed package would provide a direct path to configuration modification and persistent plugin installation. ### Attack Path 1. The package publisher account or package distribution channel is compromised, or a later release contains malicious code. 2. An administrator follows the documented `npx jasper-context-compactor setup` command. 3. `npx` resolves the package version available from the configured registry at execution time. 4. The downloaded package executes under the administrator's user account. 5. Malicious setup code can read or modify files available to that account, including OpenClaw configuration and extension files. 6. Modified extension code may subsequently load whenever OpenClaw starts. ### Impact Assessment The current audited source does not contain a malicious dependency payload, and `package.json` declares no third-party runtime dependencies. The risk arises ...[truncated 544 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Pin documentation to an exact audited version, for example `npx jasper-context-compactor@0.3.8 setup`. - Publish and document package integrity hashes and provenance attestations. - Enable npm package provenance and protect publisher accounts with phishing-resistant multi-factor authentication. - Prefer a verified OpenClaw package or extension installation mechanism that validates signatures or integrity. - Recommend downloading and inspecting the package before executing its setup script in security-sensitive environments. - Maintain reproducible releases that allow users to compare the registry artifact with the public source repository. - Document the files and configuration keys modified by setup so administrators can review changes before applying them. ]]>

other

Warning
Location
README.md:47
Finding
Unconditional Local-Only Privacy Claim Conflicts with Cloud-Capable Summarization<![CDATA[ ## Vulnerability Details **File Location**: `README.md:47-55`, `cli.js:156`, and `index.ts:235-241` **Vulnerability Type**: Privacy control and documented-behavior mismatch **Risk Level**: Medium ### Vulnerable Code and Documentation The README makes an unconditional privacy assertion: ```md ## Privacy 🔒 **Everything runs 100% locally.** Nothing is sent to external servers. The setup only reads your local `openclaw.json` file (with your permission) to detect your model and suggest appropriate limits. ``` The setup command similarly states: ```js console.log(' 🔒 Privacy: Everything runs locally. Nothing is sent externally.'); ``` However, transcript-derived content is sent through the configured LLM runtime: ```ts if (api.runtime?.llm?.complete) { // Use OpenClaw's LLM runtime const result = await api.runtime.llm.complete({ model: summaryModel, messages: [{ role: 'user', content: summaryPrompt }], maxTokens: summaryMaxTokens, }); summary = result.content; } ``` The provider filter is optional: ```ts const summaryModel = cfg.summaryModel; const modelFilter = cfg.modelFilter; // Optional: ['ollama', 'lmstudio', etc.] ``` ### Technical Analysis The plugin does not independently implement an outbound HTTP request, but it submits historical conversation content to `api.runtime.llm.complete`. The configured `summaryModel`, or the session model used when `summaryModel` is absent, may be backed by a remote cloud provider. The optional `modelFilter` does not establish a strict local-only guarantee. It is not configured by the setup script shown in this project, is absent from the plugin configuration schema, and relies on substring matching against a model name rather than verified endpoint locality. As a result, the statement that nothing is sent externally is not enforced by the code. Users relying on that statement may allow sensitive historical conversation content to be summarized without realizing that it can be tran ...[truncated 1202 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace the unconditional local-only statement with an accurate explanation that summaries are sent to the configured LLM provider. - Display a clear warning during setup when the selected session or summary model is remote. - Require explicit opt-in before transmitting historical conversation content to a cloud-backed summarization model. - Provide a strict local-only mode that rejects remote providers instead of relying on documentation. - Resolve provider identity and endpoint locality through trusted runtime metadata rather than model-name substring matching. - Add `modelFilter` to `openclaw.plugin.json` if it remains a supported setting, including validation and user-interface guidance. - Default `summaryModel` to a verified local provider when advertising local-only operation. - Provide a no-LLM fallback option that never sends transcript content through a model runtime. - Document what transcript data is submitted, when submission occurs, and which provider privacy policy applies. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (11)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Remove plugin files
rm -rf ~/.openclaw/extensions/context-compactor

# Remove from config (edit openclaw.json and delete the context-compactor entry)
# Or restore from backup
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Remove plugin files
rm -rf ~/.openclaw/extensions/context-compactor

# Remove from config (edit openclaw.json and delete the context-compactor entry)
# Or restore from backup
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding
The README instructs users to run `npx jasper-context-compactor` without pinning a specific version or integrity-checked source. That causes execution of whatever package version is current at install time, which creates a supply-chain risk if the package is updated maliciously, compromised, or republished with harmful code.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
**The setup will:**

1. ✅ **Back up your config** — Saves `openclaw.json` to `~/.openclaw/backups/` with restore instructions
2. ✅ **Ask permission** — Won't read your config without consent
3. ✅ **Detect local models** — Automatically identifies Ollama, llama.cpp, MLX, LM Studio providers
4. ✅ **Suggest token limits** — Based on your model's contextWindow from config
5. ✅ **Let you customize** — Enter your own values if auto-detection doesn't match
Confidence
75% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The skill automatically summarizes and replaces older conversation content in-session, but insufficient warning about this behavior can cause users to rely on context that has been altered, omitted, or compressed. In security- or safety-sensitive workflows, lossy summarization can drop constraints, prior approvals, or sensitive details, leading to incorrect model behavior or accidental disclosure through malformed summaries.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding
The installation instruction uses `npx jasper-context-compactor setup` without a pinned version, so users will fetch and execute whatever package version is current at install time. That creates a supply-chain risk: if the package is compromised, typo-squatted, or updated maliciously, arbitrary code could run on the user's machine during setup.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The help text instructs users to run `npx jasper-context-compactor` without pinning a specific version. `npx` resolves the latest published package by default, so a compromised maintainer account, malicious new release, or package takeover could cause users to execute unexpected code at install/runtime. Because this file is a setup CLI that copies files and modifies config in the user's home directory, the trust boundary is important and dynamic package resolution increases supply-chain risk.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This second unpinned `npx jasper-context-compactor` reference has the same supply-chain issue: it encourages execution of whatever version is current in the registry at the time of use. Even though it appears in help/usage text rather than executable logic, documentation-driven command execution is a common attack path because users often copy and paste these commands directly.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
When compaction triggers, the plugin forwards older conversation content to an LLM for summarization without any consent flow, notice, or restriction on which model/provider receives that data. In this skill’s context, that can expose sensitive transcript material to a secondary model or remote backend unexpectedly, especially because the feature runs automatically in a pre-agent hook and may process the full prior conversation.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The README states that `charsPerToken` value 4 "works for English," which bakes in a language-specific assumption without offering a user language choice or clearly documenting broader locale implications. This can create a policy concern because non-English users may receive degraded or misleading behavior based on an implicit English default.

Static analysis

No suspicious patterns detected.