Back to skill

Security audit

self-improving agent

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly purpose-aligned, but its optional hook can automatically read session transcripts and persist excerpts with insufficient path scoping and only best-effort redaction.

Install only if you want persistent learning logs. Keep .learnings out of version control, review entries before promoting them into AGENTS.md, TOOLS.md, or SOUL.md, and enable the optional hook only in workspaces where session transcripts may be scanned and retained. Treat uninstall deletion commands carefully because .learnings is user data.

Vulnerability Patterns
  • 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
  • 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 (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
hooks/openclaw/handler.js:213
Finding
Unrestricted Transcript Path Can Read Files Outside the Workspace<![CDATA[ ## Vulnerability Details **File Location**: `hooks/openclaw/handler.js:213-229, 304` **Vulnerability Type**: Improper path validation and filesystem scope enforcement **Risk Level**: Medium ### Vulnerable Code ```js function resolveSessionFilePath(context, workspaceDir) { const sessionEntry = isObject(context.previousSessionEntry) ? context.previousSessionEntry : isObject(context.sessionEntry) ? context.sessionEntry : {}; if (typeof sessionEntry.sessionFile === 'string' && sessionEntry.sessionFile.trim()) { return sessionEntry.sessionFile; } const sessionId = typeof sessionEntry.sessionId === 'string' ? sessionEntry.sessionId.trim() : ''; if (sessionId && workspaceDir) { return path.join(workspaceDir, 'sessions', `${sessionId}.jsonl`); } return undefined; } ``` The resulting path is passed directly to the transcript scanner: ```js const sessionFilePath = resolveSessionFilePath(context, workspaceDir); if (!sessionFilePath) { return; } const excerpts = await scanTranscriptForErrors(sessionFilePath); ``` The scanner opens that path without validating its location: ```js async function scanTranscriptForErrors(sessionFilePath) { let raw; try { raw = await fs.readFile(sessionFilePath, 'utf-8'); } catch { return []; } ``` The equivalent TypeScript implementation appears at `hooks/openclaw/handler.ts:219-239, 320`. ### Technical Analysis The hook treats `context.previousSessionEntry.sessionFile` or `context.sessionEntry.sessionFile` as a trusted filesystem path. It does not canonicalize the path or verify that it is contained beneath `<workspace>/sessions`. The fallback path is also unsafe because `sessionId` is not restricted to a safe identifier format. Values containing `..` or path separators can cause `path.join()` to resolve outside the intended sessions directory. The vulnerability requires an attacker or compromised component to influence OpenClaw hook event metadata. Under ...[truncated 1591 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve the canonical sessions directory and candidate transcript path: ```js const sessionsRoot = await fs.realpath(path.join(workspaceDir, 'sessions')); const candidate = await fs.realpath(sessionFilePath); const relative = path.relative(sessionsRoot, candidate); if ( relative === '' || relative.startsWith(`..${path.sep}`) || relative === '..' || path.isAbsolute(relative) ) { return undefined; } ``` 2. Validate `sessionId` against a strict allowlist before constructing a path, for example: ```js if (!/^[A-Za-z0-9_-]+$/.test(sessionId)) { return undefined; } ``` 3. Do not accept arbitrary absolute `sessionFile` values. If OpenClaw requires absolute paths, verify that their canonical form remains beneath the canonical sessions directory. 4. Consider rejecting symbolic links or opening files using platform-specific no-follow protections where available. 5. Add tests covering: - Absolute paths outside the workspace. - `../` traversal through `sessionId`. - Encoded or platform-specific separators. - Symlinks from the sessions directory to external files. - Valid transcript paths that remain functional after hardening. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
hooks/openclaw/handler.js:81
Finding
Best-Effort Redaction Can Persist Sensitive Transcript Data<![CDATA[ ## Vulnerability Details **File Location**: `hooks/openclaw/handler.js:81-91, 109-125, 158-211, 340` **Vulnerability Type**: Incomplete sensitive-data sanitization before persistent storage **Risk Level**: Medium ### Vulnerable Code The hook relies on a finite set of secret-pattern blocklists: ```js const REDACTION_RULES = [ [/\b(api[_-]?key|token|secret|password|passwd|authorization|credential)s?\b(\s*[=:]\s*)\S+/gi, '$1$2[REDACTED]'], [/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, 'Bearer [REDACTED]'], [/\bgh[pousr]_[A-Za-z0-9]{16,}\b/g, '[REDACTED]'], [/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, '[REDACTED]'], [/\bAKIA[0-9A-Z]{16}\b/g, '[REDACTED]'], [/\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{5,}\b/g, '[REDACTED-JWT]'], [/\b[A-Za-z0-9_-]{40,}\b/g, '[REDACTED-BLOB]'], ]; ``` Matched transcript lines are sanitized only through those rules and truncation: ```js function redactSensitiveText(text) { let result = text; for (const [pattern, replacement] of REDACTION_RULES) { result = result.replace(pattern, replacement); } return result; } function sanitizeExcerptLine(line) { let excerpt = redactSensitiveText(line.trim()).split('```').join("'''"); if (excerpt.length > MAX_EXCERPT_LENGTH) { excerpt = `${excerpt.slice(0, MAX_EXCERPT_LENGTH)}…`; } return excerpt; } ``` The resulting excerpts are persisted: ```js const excerpt = sanitizeExcerptLine(line); if (!excerpt || seen.has(excerpt)) { continue; } seen.add(excerpt); excerpts.push({ excerpt, patternKey }); ``` ```js await fs.appendFile(errorsFilePath, `\n${entry}\n`); ``` Equivalent logic appears in `hooks/openclaw/handler.ts:81-91, 115-129, 164-217, 356`. ### Technical Analysis The hook automatically copies error-matching transcript lines into `.learnings/ERRORS.md`. The redaction strategy is a blocklist of known labels and token formats. Such blocklists cannot reliably recognize every sensitive-data representation. Potentially missed data includes: ...[truncated 1780 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Avoid retaining transcript text by default. Store only the matched pattern key, timestamp, session identifier, and a generic summary. 2. Require an explicit configuration option before storing raw or partially sanitized excerpts. 3. Prefer a structured allowlist of safe fields over attempting to blocklist every secret format. For example, generate a fixed message such as: ```text Detected pattern: deps.npm-error Transcript: sessions/<validated-session-id>.jsonl ``` 4. If excerpts remain necessary: - Remove URLs, query strings, headers, cookies, connection strings, and filesystem home paths. - Detect PEM/private-key headers and suppress the entire surrounding block. - Replace high-entropy strings regardless of provider-specific prefixes. - Normalize multiline records before applying redaction. - Permit users to configure additional organization-specific patterns. 5. Create log files with restrictive permissions, such as mode `0600`, and verify the existing file is not a symlink before appending. 6. Keep `.learnings/` excluded from version control by default and display a clear warning that redaction is not a confidentiality guarantee. 7. Expand tests to cover connection URLs, cookies, multiline private keys, short credentials, database DSNs, authorization headers with unusual schemes, personal data, and provider-specific token formats. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (11)

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill instructs use of shell commands, GitHub/network installation flows, hooks, and cross-session features without declaring corresponding permissions or clearly constraining when they may be used. In a prompt-injected skill system, undeclared capabilities reduce transparency and can lead to unexpected access to workspace data, transcripts, or external resources.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The manifest describes a logging/improvement helper, but the body also defines automatic transcript sweeping, bootstrap prompt injection, synthesized error entry creation, and skill extraction workflows. This mismatch is dangerous because users and policy layers may authorize the skill under a narrower mental model while it performs broader persistence and context-shaping actions.

Description-Behavior Mismatch

Medium
Confidence
84% confidence
Finding
The skill encourages promoting collected learnings into persistent workspace guidance files and later into new reusable skills, which can alter future agent behavior beyond the immediate task. This creates a persistence channel where low-quality, overbroad, or adversarially induced entries can become durable prompt influence across sessions.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
Cross-session transcript access and messaging materially expand the data-access surface of a skill whose stated purpose is simple learning capture. Even with advisory language, these capabilities can expose unrelated session content, propagate tainted summaries, and weaken isolation between tasks if invoked too broadly.

Description-Behavior Mismatch

Medium
Confidence
90% confidence
Finding
The optional hook automatically sweeps ended-session transcripts for error patterns and writes derived entries into persistent files, which is more invasive than manual note logging. Automated transcript processing can capture sensitive context unintentionally and can create persistent records without a specific user request at the time of collection.

Vague Triggers

Medium
Confidence
78% confidence
Finding
Broad correction trigger phrases such as common conversational disagreements can cause over-collection into persistent learning logs from ordinary dialogue, including misleading or adversarial user statements. In this skill's context, that matters because logged items may later be promoted into workspace memory and affect future agent behavior.

Vague Triggers

Medium
Confidence
79% confidence
Finding
The feature-request triggers are generic enough to match normal exploratory conversation, causing the skill to persist user remarks as product requirements without sufficient scope checks. This can pollute logs, create false institutional memory, and indirectly steer future agent actions or generated skills based on casual comments.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This hook persists excerpts from prior session transcripts into a workspace file, which can expose user or agent output beyond the original session boundary without an explicit disclosure or consent check at the moment of write. Although the code attempts redaction and truncation, the redaction is best-effort and may miss sensitive data, so transcript-derived content can still be retained in repository state and later committed, shared, or indexed.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The hook persists excerpts derived from session transcripts into `.learnings/ERRORS.md` automatically, but the write happens without explicit user notification or consent at the time of collection. Although the code attempts redaction and truncation, transcript data can still contain sensitive operational details, internal paths, user inputs, or secrets that do not match the regexes, creating a privacy and data-handling risk.

Session Persistence

Medium
Category
Rogue Agent
Content
## Opt-In and Safety

- The sweep only runs when `<workspace>/.learnings/` exists — create that
  directory to enable it, delete it to disable it
- `ERRORS.md` is created only if missing and is otherwise appended to, never
  overwritten
Confidence
83% confidence
Finding
The hook explicitly persists excerpts from prior session transcripts into `<workspace>/.learnings/ERRORS.md` and appends indefinitely. Even with truncation and some redaction, session transcripts can contain sensitive user inputs, internal paths, stack traces, secrets that do not match the redaction patterns, or proprietary data, so this creates a durable secondary store of potentially sensitive information beyond the original session logs.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
rm -r ~/.openclaw/hooks/self-improvement

# 2. Remove the skill
rm -r ~/.openclaw/skills/self-improving-agent

# 3. Optional — remove captured learnings (REVIEW FIRST, this is your data)
rm -r ~/.openclaw/workspace/.learnings
Confidence
82% confidence
Finding
The uninstall guide includes recursive deletion commands against fixed paths in the user's home directory. While this appears to be legitimate uninstall documentation, `rm -r` is destructive and, if copied blindly, could cause unintended data loss, especially for `.learnings/` which is explicitly user data and for any path that differs due to symlinks or environment assumptions.

Static analysis

No suspicious patterns detected.