Back to skill

Security audit

nutcracker

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed local UX research logger, but it broadly records exact interactions in the background and stores sensitive notes without strong opt-in or storage safeguards.

Install only if you intentionally want OpenClaw interactions and survey answers recorded locally for UX research. Avoid using it during sessions involving secrets, credentials, regulated data, or private project details, and review/delete ~/.uxr-observer/ data regularly. There is no artifact-backed evidence of automatic external transmission, but the local logs and reports can contain sensitive verbatim content.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/setup.py:22
Finding

Sensitive Interaction Data Is Stored Without Restrictive Filesystem Permissions or Enforced Redaction

Content
View full analysis

Vulnerability Details

File Location: scripts/setup.py:22-31, 49-55, 67-73; scripts/log_observation.py:29-51; scripts/generate_report.py:324-333
Vulnerability Type: Plaintext sensitive-data storage with process-default permissions
Risk Level: Medium

Complete Code Snippets

From scripts/setup.py:

python
def setup_directories(base_path):
    """Create directory structure."""
    directories = [
        base_path,
        base_path / "sessions",
        base_path / "reports",
    ]
    for d in directories:
        d.mkdir(parents=True, exist_ok=True)
        print(f"✓ Created {d}")
python
config = {
    "study_active": True,
    "study_start_date": datetime.now().isoformat(),
    "survey_frequency": "after_each_task",
    "survey_style": "brief",
    "opted_out_topics": [],
    "participant_id": generate_participant_id()
}

with open(config_path, 'w') as f:
    json.dump(config, f, indent=2)
python
for f in [observations_file, surveys_file]:
    if not f.exists():
        f.touch()

From scripts/log_observation.py:

python
def log_record(record):
    """Append a record (observation or survey) to the appropriate JSONL file."""
    if not isinstance(record, dict):
        raise ValueError("Record must be a JSON object")

    record_type = record.get("_type", "observation")

    if record_type not in ("observation", "survey"):
        raise ValueError(f"Invalid _type: {record_type}. Must be 'observation' or 'survey'")

    # Route to correct file
    if record_type == "observation":
        filename = "observations.jsonl"
    else:
        filename = "surveys.jsonl"

    session_dir = get_today_dir()
    file_path = session_dir / filename

    # Append to JSONL
    with open(file_path, 'a') as f:
        f.write(json.dumps(record) + '\n')

    return str(file_path)

From scripts/generate_report.py:

python
# Generate report
report = format_report(date_str, metrics, observations, surveys, gallery, end_o
...[truncated 2841 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create the base directory and all session/report directories with owner-only permissions:
python
base_path.mkdir(parents=True, exist_ok=True, mode=0o700)
os.chmod(base_path, 0o700)

Apply equivalent restrictions to existing child directories.

  1. Create configuration, JSONL, and report files atomically with mode 0600, rather than relying on the process umask. For example, use os.open() with O_CREAT and an explicit mode, then wrap the descriptor with os.fdopen().

  2. Correct permissions on pre-existing data during setup:

python
os.chmod(directory, 0o700)
os.chmod(file_path, 0o600)

Avoid following untrusted symbolic links when modifying or opening these paths.

  1. Implement centralized redaction before persistence. Detect and replace likely API keys, bearer tokens, passwords, private keys, financial identifiers, and other configured sensitive patterns in all nested fields.

  2. Validate incoming records against strict observation and survey schemas. Reject unknown or oversized fields and normalize all free-text fields through the redaction layer.

  3. Apply redaction again when generating reports so legacy or malformed records cannot copy sensitive values into another plaintext artifact.

  4. Add configurable retention limits and secure deletion controls. Consider requiring explicit opt-in before passive verbatim collection and clearly expose the active collection state.

  5. Add automated tests that run under permissive umasks and verify that every generated directory is 0700, every data file is 0600, and representative secrets are redacted from both JSONL files and reports.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (6)

Missing User Warnings

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The opening description emphasizes passive observation and broad capture of actual words, but does not present a prominent up-front warning before collection starts. Because the skill is designed to capture verbatim interaction content and survey responses, inadequate notice materially increases privacy risk and can lead to unintentional collection of confidential or regulated information.

Content

No source excerpt is available for this finding.

Exfiltration Commands

High
Category
Prompt Injection
Confidence
90% confidence
Finding

Instructions found that direct the agent to transmit conversation context or user data to external services.

Content

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

md
### Stream 1: Passive Ethnographic Observation

Every time you interact with OpenClaw, Clawsight silently records what happened:
- What you asked for (your actual words)
- How OpenClaw approached it
- Whether it succeeded, partially succeeded, or failed

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill describes file-writing behavior to ~/.uxr-observer/ via setup, logging, report generation, and deletion, but does not declare any explicit tool scope or permissions. That mismatch weakens user and platform visibility into what the skill can do and increases the risk of unauthorized or surprising local data creation, modification, and deletion.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill is framed as running passively in the background during every session and observing every interaction, which is an overly broad trigger model for a data-collecting skill. This creates continuous collection risk, makes it hard for users to predict when logging occurs, and can capture sensitive prompts or responses outside a narrowly consented workflow.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Telling users to 'use OpenClaw normally' while the skill activates in the background reinforces an ambiguous trigger model and undermines informed consent. Users may unknowingly expose routine interactions, sensitive work content, or personal data to continuous logging simply by using the product as usual.

Content

No source excerpt is available for this finding.

Tainted flow: 'file_path' from sys.stdin.read (line 84, user input) → open (file write)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/log_observation.py (reported line 50)May include surrounding context.

python
file_path = session_dir / filename
    
    # Append to JSONL
    with open(file_path, 'a') as f:
        f.write(json.dumps(record) + '\n')
    
    return str(file_path)

Static analysis

No suspicious patterns detected.