Back to skill

Security audit

Clawditor

Security checks for vulnerabilities and agentic risk

Overview

This audit skill is mostly purpose-aligned, but it can copy sensitive memory or log snippets into report files and can be directed to write reports outside the intended workspace.

Review this skill before installing if your workspaces contain secrets, private logs, or sensitive memory. Run it only on workspaces you are comfortable auditing, keep output under a controlled eval directory, inspect generated JSON/Markdown before sharing or committing it, and avoid using overwrite or broad log scanning unless you understand what files may be copied into reports.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/log_scan.py:65
Finding

Unredacted Sensitive Log Content May Be Persisted in Audit Artifacts

Content
View full analysis

Vulnerability Details

File Location: scripts/log_scan.py:65-78, with persistence at scripts/run_audit.py:70
Vulnerability Type: Plaintext sensitive-data exposure
Risk Level: Medium

Vulnerable Code

python
try:
    with f.open("r", errors="ignore") as fh:
        hits = []
        for i, line in enumerate(fh):
            if i >= args.max_lines:
                break
            for regex, label in PATTERNS:
                if regex.search(line):
                    hits.append({
                        "label": label,
                        "line": i + 1,
                        "text": line.strip()[:200]
                    })
        if hits:
            results.append({"file": str(f), "hits": hits})
except OSError:
    continue

The resulting data is written without further sanitization:

python
write_json(out_dir / "log_scan.json", log_scan)

Technical Analysis

The log scanner stores the first 200 characters of every line matching terms such as ERROR, Exception, Traceback, failed, timeout, or retry. It does not detect or redact authorization headers, API keys, access tokens, passwords, URL credentials, connection strings, session identifiers, or personal information.

Operational error messages frequently include request parameters, configuration values, authentication data, or serialized exceptions. Consequently, the generated eval/log_scan.json can contain plaintext copies of sensitive data. This behavior also conflicts with the secret-handling rules in SKILL.md, which state that only the presence and path of keys or tokens should be reported.

Attack Path

  1. A workspace log records a sensitive value on a line containing one of the configured failure keywords.
  2. The Skill scans that log during an audit.
  3. log_scan.py copies up to 200 characters of the matching line without redaction.
  4. run_audit.py serializes the cap ...[truncated 603 chars]
Remediation
View remediation

Remediation Suggestions

  • Apply centralized redaction before any log text is stored or printed.
  • Redact authorization headers, bearer tokens, API keys, passwords, cookies, private keys, URL user information, database connection strings, and known credential formats.
  • Prefer storing only the file path, line number, matched label, and a sanitized message.
  • Replace sensitive values with stable placeholders such as [REDACTED_TOKEN].
  • Add tests containing representative secrets to verify that neither JSON nor console output contains the original values.
  • Consider making raw snippets opt-in and displaying an explicit warning when enabled.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/memory_dupes.py:59
Finding

Unredacted Memory Snippets May Be Copied into Duplicate-Analysis Reports

Content
View full analysis

Vulnerability Details

File Location: scripts/memory_dupes.py:59-66, with persistence at scripts/run_audit.py:69
Vulnerability Type: Plaintext sensitive-data exposure
Risk Level: Medium

Vulnerable Code

python
if score >= args.threshold:
    dup_pairs.append({
        "a": {
            "file": a["file"],
            "index": a["index"],
            "snippet": a["text"][:160]
        },
        "b": {
            "file": b["file"],
            "index": b["index"],
            "snippet": b["text"][:160]
        },
        "score": round(score, 3),
    })

The snippets are then persisted without redaction:

python
write_json(out_dir / "memory_dupes.json", memory_dupes)

Technical Analysis

When two memory paragraphs meet the similarity threshold, the report embeds the first 160 characters of each paragraph verbatim. No secret detection, content classification, or redaction is applied.

Agent memory may contain tokens, private project details, personal information, internal URLs, or other confidential facts. If such content occurs in sufficiently similar paragraphs, it is duplicated into eval/memory_dupes.json. This is inconsistent with the Skill's stated policy against including secrets in report snippets.

Attack Path

  1. Sensitive content is present in two identical or near-duplicate Markdown paragraphs under memory/.
  2. The paragraphs satisfy the configured length and similarity thresholds.
  3. memory_dupes.py copies the first 160 characters of both paragraphs into its result.
  4. run_audit.py writes that result to eval/memory_dupes.json.
  5. Distribution or storage of the evaluation report discloses the copied content to recipients who may not have had access to the original memory files.

Impact Assessment

This issue does not directly grant local code execution or elevated system privileges. Its impact is confidentiality loss within t ...[truncated 244 chars]

Remediation
View remediation

Remediation Suggestions

  • Run all memory previews through the same centralized redaction layer used for log output.
  • Prefer reporting paragraph hashes, file locations, paragraph indexes, lengths, and similarity scores instead of raw text.
  • If previews are necessary, generate sanitized excerpts only after detecting credential and personal-data patterns.
  • Add a configuration option to disable snippets, with snippets disabled by default.
  • Add regression tests confirming that representative tokens, passwords, connection strings, and private data never appear in generated reports.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/run_audit.py:50
Finding

Unconfined Output Path Allows Writes Outside the Audited Workspace

Content
View full analysis

Vulnerability Details

File Location: scripts/run_audit.py:50-60, with file writes at scripts/run_audit.py:69-72 and scripts/run_audit.py:124-131
Vulnerability Type: Path traversal and arbitrary-location file write
Risk Level: Medium

Vulnerable Code

python
parser.add_argument(
    "--out",
    default="eval",
    help="Output directory under workspace"
)
parser.add_argument(
    "--overwrite",
    action="store_true",
    help="Overwrite draft markdown/json templates"
)
args = parser.parse_args()

root = Path(args.path).resolve()
out_dir = root / args.out
out_dir.mkdir(parents=True, exist_ok=True)

The unvalidated directory is subsequently used for writes:

python
write_json(out_dir / "inventory.json", inventory)
write_json(out_dir / "memory_dupes.json", memory_dupes)
write_json(out_dir / "log_scan.json", log_scan)
write_json(out_dir / "git_stats.json", git_stats)

write_if_missing(out_dir / "exec_summary.md", exec_summary, args.overwrite)
write_if_missing(out_dir / "scorecard.md", scorecard, args.overwrite)
if (out_dir / "latest_report.json").exists() and not args.overwrite:
    pass
else:
    write_json(out_dir / "latest_report.json", latest_report)

Technical Analysis

Although --out is documented as a directory under the workspace, the code does not enforce that boundary. An absolute Path operand replaces the workspace path when combined with root, while relative paths containing .. can traverse outside it. The implementation also does not reject a symlinked output directory that resolves elsewhere.

The Skill creates the selected directory and writes several predictable filenames. When --overwrite is supplied, existing Markdown and JSON report files can be replaced. The writes use generated report content rather than attacker-selected arbitrary bytes, which limits but does not eliminate the impact.

Attack Path

  1. An attacke ...[truncated 974 chars]
Remediation
View remediation

Remediation Suggestions

  • Reject absolute values for --out.
  • Resolve the candidate output path and verify that it remains under the resolved workspace root:
python
if Path(args.out).is_absolute():
    parser.error("--out must be relative to the workspace")

root = Path(args.path).resolve()
out_dir = (root / args.out).resolve()

try:
    out_dir.relative_to(root)
except ValueError:
    parser.error("--out must remain inside the workspace")
  • Detect and reject symlink components or use safe directory/file-opening primitives that prevent symlink traversal.
  • Retain non-overwriting behavior by default and require explicit confirmation or a narrowly scoped flag before replacing existing files.
  • Validate each final destination immediately before writing to reduce time-of-check/time-of-use risk.
  • Add tests for absolute paths, ../ traversal, nested traversal, and symlink-based escapes.
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises a broad auditing/evaluation skill for an OpenClaw workspace, including scanning multiple resource types and writing standardized report artifacts. The actual code chunk only collects basic git repository statistics and prints them or emits JSON. While git inspection could be a supporting component of a larger audit system, this chunk by itself does not implement the declared primary behavior, outputs, or scope. Therefore the description materially overstates what this code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description claims a comprehensive audit skill for an OpenClaw agent workspace with multiple output artifacts and broader analysis domains. The actual code only implements near-duplicate paragraph detection for markdown files in a memory directory. While this could support a memory-quality review, it is only one small subfunction and lacks the core declared behaviors and outputs. Therefore the declared description materially overstates and misrepresents the code chunk’s actual purpose and capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a full auditing and report-generation skill for an OpenClaw workspace, including scanning various resources and producing multiple evaluation artifacts. The actual code does not perform auditing, scoring, patching, workspace scanning, or report generation. It only validates the structure of an already-existing latest_report.json file. While this could be a supporting utility within such a skill, the supplied code chunk's actual purpose is materially narrower and different from the declared primary purpose, so this is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The description promises a higher-level auditing and reporting capability for an OpenClaw agent workspace, including scoring, summaries, JSON reports, and patches based on review of memory/logs/configs/git/artifacts. The actual code only walks a directory tree, skips some common folders, gathers file sizes, aggregates directory statistics, and prints a tree plus largest files. While this could be a supporting utility for a larger audit workflow, on its own it does not implement the declared primary behavior or outputs. Therefore the description materially overstates what this code chunk actually does.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill explicitly instructs use of file reads, file writes, and helper scripts, but it declares no explicit tool scope or permission boundaries. In practice, this increases the chance an agent will execute the audit with broader-than-necessary filesystem or shell access, making accidental overreach, unsafe script execution, or unintended workspace modification more likely.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill mandates writing multiple files under eval/ and even creating or refactoring memory files, but it does not require confirmation before modifying the target workspace. In an auditing context, silent writes can overwrite user content, taint evidence, alter repositories under review, or introduce unreviewed patches into sensitive memory/documentation areas.

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 · scripts/git_stats.py (reported line 12)May include surrounding context.

python
def run(cmd, cwd):
    try:
        out = subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.DEVNULL)
        return out.decode().strip()
    except subprocess.CalledProcessError:
        return ""

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 · scripts/run_audit.py (reported line 14)May include surrounding context.

python
def run_json(script: str, args, cwd: Path):
    cmd = [sys.executable, str(HERE / script), *args, "--json"]
    proc = subprocess.run(cmd, cwd=str(cwd), capture_output=True, text=True)
    if proc.returncode != 0:
        return {
            "error": "command_failed",

Static analysis

No suspicious patterns detected.