Back to skill

Security audit

Tokenizer

Security checks for vulnerabilities and agentic risk

Overview

This token-optimization skill has useful stated functions, but it also ships under-scoped automatic memory persistence and configurable script execution that users should review before installing.

Install only after reviewing the extra dispatcher and memory-agent files, not just SKILL.md. Use it in a constrained workspace, pin dependencies and model revisions, disable automatic distillation/flush by default, require user review before memory_write or episodic-store writes, and restrict script paths and file paths to trusted directories.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • 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
Findings (4)

T02 · Agent Memory Poisoning

Error
Location
distill_memory.py:17
Finding

Untrusted Conversation Content Can Poison Persistent Agent Memory

Content
View full analysis

Vulnerability Details

File Location: distill_memory.py:17-23, 58-74; memory_agent.py:122-180; SKILL.md:187-193, 343-352
Vulnerability Type: Untrusted content promoted to authoritative persistent memory
Risk Level: High

Vulnerable Code

python
FACT_PATTERNS = [
    # (type, confidence, pattern, content_group)
    ("decision",    "high",   r"(?i)(decided to|we will always|agreed to|let's go with|finalize on)\s+([^.\n]+)", 2),
    ("decision",    "high",   r"(?i)(the final approach is|we are going with|confirmed:\s*)([^.\n]+)",             2),
    ("preference",  "medium", r"(?i)(prefer|don't like|avoids?|wants? to use|hate)\s+([^.\n]+)",                   0),
    ("constraint",  "high",   r"(?i)(must be|must not|requires?|cannot|do not use|only use|never use)\s+([^.\n]+)",0),
    ("next_action", "low",    r"(?i)(todo|to-do|next step|next up|we need to|action item)\s*:?\s*([^.\n]+)",       2),
]
python
for turn_index, msg in enumerate(messages):
    role    = msg.get("role", "unknown")
    content = msg.get("content", "")
    if not isinstance(content, str):
        continue
    for fact_type, confidence, pattern, content_group in FACT_PATTERNS:
        for m in re.finditer(pattern, content):
            extracted = m.group(content_group).strip() if content_group > 0 else m.group(0).strip()
            if len(extracted.split()) < 2:
                continue
            facts.append({
                "id":          str(uuid.uuid4())[:8],
                "type":        fact_type,
                "content":     extracted,
                "confidence":  confidence,
                "source_turn": turn_index + 1,
                "source_role": role,
            })
python
if trigger_report["should_distill"]:
    if not args.history:
        result["distillation"] = {
            "success": False,
            "error": "Distillation triggered but --history path not provided. Cannot distill.",
        }
    else:
        result["
...[truncated 2833 chars]
Remediation
View remediation

Remediation Suggestions

  1. Apply a strict role-based trust policy. Do not promote user, tool, retrieved-document, or unknown-role content to authoritative decisions or constraints.
  2. Store user-derived statements as untrusted claims rather than high-confidence facts.
  3. Require explicit user confirmation before persisting instruction-like decisions, constraints, credentials, destinations, or security settings.
  4. Preserve immutable provenance, including role, turn, session, timestamp, and a hash or reference to the original message.
  5. Add filters for imperative and policy-like content, especially phrases matching the existing decision and constraint patterns.
  6. Separate factual memory from behavioral instructions; persistent behavioral rules should require a dedicated authenticated workflow.
  7. Do not flush the original conversation until the extracted facts have been reviewed and accepted.
  8. Ensure retrieval consumers enforce confidence and role policies rather than trusting every stored fact.
  9. Disable automatic MCP persistence by default and require a confirmation boundary before invoking memory_write.

T07 · Tool Hijacking and Spoofing

Error
Location
skill_runner.py:24
Finding

Externally Controlled Configuration Can Redirect Trusted Tools to Arbitrary Python Scripts

Content
View full analysis

Vulnerability Details

File Location: skill_runner.py:24-30, 39-51, 69-103; memory_agent.py:35-65, 122-142
Vulnerability Type: Configurable tool replacement and execution outside the trusted Skill directory
Risk Level: High

Vulnerable Code

python
CONFIG_CANDIDATES = [
    os.path.join(os.path.dirname(__file__), "..", "orchestrator_config.json"),
    os.path.join(os.path.dirname(__file__), "orchestrator_config.json"),
    os.path.expanduser("~/.openclaw/orchestrator_config.json"),
]
python
def load_config() -> dict:
    for path in CONFIG_CANDIDATES:
        resolved = os.path.abspath(path)
        if os.path.exists(resolved):
            with open(resolved, "r") as f:
                return json.load(f)
python
def resolve_script_path(script_relative: str) -> str:
    """Resolve script path relative to the skills root."""
    candidates = [
        os.path.join(SCRIPT_BASE, os.path.basename(script_relative)),
        os.path.join(SCRIPT_BASE, "..", script_relative),
        os.path.abspath(script_relative),
    ]
    for c in candidates:
        if os.path.exists(os.path.abspath(c)):
            return os.path.abspath(c)
    raise FileNotFoundError(f"Script not found: {script_relative} (searched from {SCRIPT_BASE})")
python
entry = registry[tool_name]
script_rel = entry.get("script")
guardrail = entry.get("guardrail")

try:
    script_path = resolve_script_path(script_rel)
except FileNotFoundError as e:
    return {"success": False, "error": str(e)}
python
cmd = [sys.executable, script_path]
for flag, value in args_dict.items():
    cmd.append(flag)
    if value is not True and value is not None:
        cmd.append(str(value))

proc = subprocess.run(cmd, capture_output=True, text=True, timeout=60)

The memory agent implements a similar unrestricted fallback:

python
candidates = [
    os.path.join(SCRIPT_DIR, rel_path),
    os.path.join(SCRIPT_DIR, os.path.basename(rel_path)),
    os.path.join(SCR
...[truncated 2408 chars]
Remediation
View remediation

Remediation Suggestions

  1. Load the bundled configuration by default and reject external overrides unless the operator explicitly supplies an approved path.
  2. Resolve scripts relative to one immutable trusted directory.
  3. After canonicalization, verify with os.path.commonpath that every script remains inside the trusted directory.
  4. Reject absolute paths, parent traversal, symlinks, non-regular files, and files with unsafe ownership or permissions.
  5. Pin each registered tool to an expected script hash or signed manifest.
  6. Enforce args_schema, including allowed flags, types, cardinality, and required values.
  7. Reject unknown arguments instead of forwarding them.
  8. Run tool scripts in a sandbox with a minimal environment, restricted filesystem access, disabled network access where unnecessary, and reduced operating-system privileges.
  9. Apply the same path and configuration validation to memory_agent.py.
  10. Clearly identify the exact script and verified digest in audit logs before execution.

T08 · Insecure Dependencies

Warning
Location
count_tokens.py:18
Finding

Unpinned Dependencies and Implicit Runtime Model Downloads Create Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: README.md:91-108; count_tokens.py:18-23, 49-56; compress_prompt.py:13-18, 32-38
Vulnerability Type: Unpinned third-party packages and mutable remote model artifacts
Risk Level: Medium

Vulnerable Code

The installation documentation recommends unpinned packages:

bash
pip install tiktoken
bash
pip install transformers sentencepiece
bash
pip install llmlingua

Precise Gemma counting implicitly loads a remote model identifier:

python
def count_tokens_transformers(text: str, model_id: str) -> int:
    from transformers import AutoTokenizer
    os.environ["TOKENIZERS_PARALLELISM"] = "false"
    tokenizer = AutoTokenizer.from_pretrained(model_id)
    return len(tokenizer.encode(text))
python
if "gemma" in mdl or "ollama" in mdl:
    try:
        return count_tokens_transformers(t, "google/gemma-7b")

The compressor similarly identifies a mutable remote model without a fixed revision:

python
compressor = PromptCompressor(
    model_name="microsoft/llmlingua-2-xlm-roberta-large-meetingbank",
    use_llmlingua2=True,
    device_map="cpu"
)

Technical Analysis

Package installation instructions do not specify versions, hashes, a lockfile, or a trusted package-index policy. Reinstalling the Skill at different times can therefore produce different dependency graphs.

The tokenizer and compressor use repository identifiers without pinning an immutable model revision. On first use, the underlying libraries may contact external model repositories and download artifacts that were not present during the Skill audit. The reviewed code does not request remote custom model code explicitly, but mutable runtime downloads still expand the trusted computing base and create integrity and reproducibility risks.

The named packages and models are consistent with the Skill’s advertised token-management functionality. The issue is therefore insecure dependency handling rather t ...[truncated 1175 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin exact dependency versions in a lockfile.
  2. Use hash-verified installation, such as pip install --require-hashes.
  3. Pin model repositories to immutable commit revisions rather than mutable names.
  4. Download and verify model artifacts during a controlled installation phase rather than silently on first use.
  5. Provide an offline mode using approved local artifact paths and local_files_only=True where supported.
  6. Document every operation that can access the network.
  7. Disable remote custom code and unnecessary dynamic loading explicitly.
  8. Use a dedicated virtual environment or container with minimal filesystem and network privileges.
  9. Perform dependency vulnerability and license scanning in CI.
  10. Maintain an allowlist of approved package indexes and model repositories.

T09 · Insecure Skill Coding Practices

Warning
Location
skill_runner.py:92
Finding

Unrestricted Tool Paths Permit Arbitrary Local File Reads and Overwrites

Content
View full analysis

Vulnerability Details

File Location: skill_runner.py:92-103; distill_memory.py:140-164; compress_prompt.py:7-10, 21-24, 67-70; memory_agent.py:197-203
Vulnerability Type: Missing path authorization and argument-schema enforcement
Risk Level: Medium

Vulnerable Code

The runner forwards every provided key without validating it against the configured schema:

python
cmd = [sys.executable, script_path]
for flag, value in args_dict.items():
    cmd.append(flag)
    if value is not True and value is not None:
        cmd.append(str(value))

The memory distiller accepts arbitrary input and output paths:

python
parser.add_argument("--input",  required=True, help="Path to JSON chat history or plain-text transcript.")
parser.add_argument("--output", help="Path to write distilled JSON. Defaults to stdout.")
python
with open(args.input, "r", encoding="utf-8") as f:
    raw = f.read()
python
if args.output:
    with open(args.output, "w", encoding="utf-8") as f:
        f.write(output)

The compressor has the same unrestricted path behavior:

python
with open(args.input, 'r', encoding='utf-8') as f:
    prompt = f.read()
python
if args.output:
    with open(args.output, 'w', encoding='utf-8') as f:
        f.write(compressed_prompt)

State operations also accept arbitrary paths:

python
def load_state(state_path: str) -> dict:
    if os.path.exists(state_path):
        with open(state_path) as f:
            return json.load(f)
    return {"turn": 0, "token_pct": 0.0, "task_complete": False}

def save_state(state_path: str, state: dict):
    with open(state_path, "w") as f:
        json.dump(state, f, indent=2)

Technical Analysis

The registered tools operate directly on user-supplied paths without canonicalization, workspace containment, symlink rejection, file-type validation, or overwrite confirmation. The runner’s configuration contains argument schemas, but these schemas are never enf ...[truncated 1744 chars]

Remediation
View remediation

Remediation Suggestions

  1. Enforce each tool’s configured args_schema and reject unknown flags.
  2. Define separate approved roots for input documents, generated outputs, episodic memory, and state files.
  3. Canonicalize paths before access and verify containment with os.path.commonpath.
  4. Reject absolute paths, parent traversal, symbolic links, device files, sockets, and other non-regular files.
  5. Require explicit confirmation before replacing an existing file.
  6. Use exclusive creation where replacement is unnecessary and atomic temporary-file replacement where updates are required.
  7. Apply file-size limits before reading to prevent memory exhaustion.
  8. Run tools under an operating-system account restricted to the approved workspace.
  9. Avoid returning sensitive source content or reversible derivatives through tool output.
  10. Record security-relevant file operations in an audit log without logging file contents.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (43)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This variant highlights undeclared side effects: the skill describes automatic trigger-based memory consolidation, writing episodic facts, and flushing working memory, yet its headline purpose sounds like a benign optimization helper. Hidden or underemphasized state changes affecting conversation history and external memory stores are dangerous because they can alter, discard, or persist sensitive context without clear operator intent.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 231)May include surrounding context.

md
**Fix:** Edit the `description:` field in the flagged `SKILL.md` frontmatter to be one clean, concise sentence.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest promises broad token analysis and active context-reduction strategies across several context sources. In contrast, the implementation only scans skill metadata files, estimates token cost from frontmatter character count, and reports bloated descriptions; it does not analyze history, tool outputs, or perform any of the claimed reduction strategies.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code automatically distills conversation history and writes episodic memory to disk, which exceeds the manifest's stated token-analysis/context-reduction role. That mismatch is dangerous because users or orchestrators may grant this skill access expecting analysis-only behavior, while it actually persists potentially sensitive conversation data and signals memory flushing autonomously.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file implements a general task router that classifies requests and selects scripts from an orchestrator-wide configuration, which is materially different from the declared token-economy/context-reduction purpose. This kind of capability expansion is dangerous because it can cause the orchestrator to invoke unrelated tools or alter control flow under the guise of a benign optimization skill, increasing the attack surface and enabling hidden behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

This runner can execute any script present in the external tool registry, making the skill a generic execution dispatcher rather than a narrowly scoped token-economy utility. In an agent setting, that broad capability can be abused to invoke unrelated or dangerous scripts, bypass least-privilege boundaries, and expand the skill far beyond its declared context-reduction function.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code builds a command from user-supplied arguments and executes a registered script without meaningful semantic restriction beyond an optional guardrail field. In the context of a token-optimization skill, a generic subprocess launcher is unnecessary and dangerous because it enables arbitrary capability expansion and execution of local code under the agent's privileges.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 77)May include surrounding context.

SSH into your server and run:

bash
# 1. Create the skills directory for your agent
mkdir -p ~/.openclaw/skills/token-economy

# 2. Copy all raw files into the skill folder

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares powerful capabilities through required tools and documented workflows that involve reading files, writing distilled memory files, inspecting environment-controlled paths, and invoking Python scripts, but it does not define any explicit tool scope or allowlist. That creates an avoidable trust gap: a caller may assume the skill is limited to token analysis while it can perform broader filesystem and shell-like actions, increasing the chance of unintended data access or state changes.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Broad trigger phrases like 'optimize memory' or 'distill history' can match ordinary user requests and cause the skill to activate in contexts where the user did not intend filesystem operations, history processing, or memory-state changes. In a skill that can write files and potentially flush working memory, ambiguous activation materially increases the chance of accidental invocation and overreach.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill explicitly describes saving conversation history to a file, generating distilled facts, writing to external memory, and flushing working memory, but it does not present these as high-sensitivity state changes requiring clear user consent. This is dangerous because conversation history can contain secrets, personal data, or proprietary information, and persistence plus flushing can both leak and irreversibly alter the agent's operating context.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
84% confidence
Finding

A token-economy skill focused on auditing and reducing context bloat would be expected to analyze provided content or a declared skills directory. Reading SKILLS_DIR from the environment and inspecting multiple fixed filesystem locations under the current working directory and user home introduces host-environment discovery behavior beyond the manifest's stated purpose.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a full token-economy suite that audits context window usage across skills, history, and tool outputs and applies five creative reduction strategies. This script only reads a single input file and compresses it with LLMLingua-2, with no auditing of context sources or evidence of multiple optimization strategies.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The call to AutoTokenizer.from_pretrained(model_id) can fetch tokenizer files from a remote registry and load them into the local environment, which introduces unexpected network access and supply-chain exposure in a utility whose stated purpose is only local token counting. In an agent skill context, this is more dangerous because analyzing untrusted or user-specified model names can trigger outbound requests, dependency downloads, and potentially execution of complex third-party parsing code outside the expected trust boundary.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The documented workflow explicitly recommends writing conversation-derived strings to long-term storage and then flushing working memory, but it does not mention obtaining user consent, honoring retention limits, or warning about privacy implications. This can cause sensitive user content, preferences, or task data to be persistently retained outside the immediate session, increasing privacy, compliance, and unintended disclosure risk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The module documentation advertises autonomous trigger-based consolidation behavior that conflicts with a user-invoked token-optimization skill. Even though this finding is in documentation, it evidences intended hidden capability expansion and increases the risk that the skill will be deployed with inappropriate trust, permissions, or expectations.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The code creates episodic memory files and may delete generated files automatically without any user-facing warning or confirmation. In a memory-related agent, this is especially dangerous because conversation histories can contain secrets, personal data, or regulated content, and automatic persistence/deletion can violate user expectations, retention policies, or forensic needs.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill spawns an external Python script to process conversation history, a capability beyond simple token auditing. In this context, the danger is not just subprocess use but that the skill can execute additional code paths from configurable locations, increasing attack surface and enabling unreviewed behavior under the guise of context optimization.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · memory_agent.py (reported line 142)May include surrounding context.

python
cmd = [sys.executable, distill_script, "--input", history_path, "--output", output_path]

    try:
        proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
        if proc.returncode != 0:
            return {
                "success": False,