Back to skill

Security audit

Harness Engineering

Security checks for vulnerabilities and agentic risk

Overview

The skill is a harness-building guide, but its reusable templates include default unrestricted file and shell tools plus persistent plaintext sessions without enforced sandboxing or approvals.

Install only if you want a Chinese/bilingual reference for building full agent harnesses. Do not copy the runnable templates into a real agent without adding workspace path enforcement, command allowlists or approvals, sandboxing, secret redaction before persistence, secure session-file permissions, and retention controls.

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

T09 · Insecure Skill Coding Practices

Error
Location
references/code-templates.md:400
Finding

Unrestricted Model-Controlled Shell Execution with Bypassable Command Filtering

Content
View full analysis

Vulnerability Details

File Location: references/code-templates.md:400-415, references/code-templates.md:759-770, and references/code-templates.md:944-953
Vulnerability Type: Command injection through unrestricted shell execution
Risk Level: High

Vulnerable Code:

python
class BashTool(BaseTool):
    name = "bash"
    description = "Execute a shell command and return output"
    parameters = BashParams

    async def execute(self, p: BashParams) -> str:
        try:
            r = subprocess.run(
                p.command, shell=True, capture_output=True, text=True, timeout=p.timeout
            )
        except subprocess.TimeoutExpired:
            return f"Command timed out after {p.timeout}s"
        out = r.stdout or ""
        if r.stderr:
            out += f"\nSTDERR:\n{r.stderr}"
python
def setup_security(api: ExtensionAPI):
    @api.on("authorize_tool_call")
    async def block_dangerous(event: ToolCallEvent, ctx):
        if event.name == "bash":
            cmd = event.arguments.get("command", "")
            dangerous = ["rm -rf /", "rm -rf ~", "sudo rm", ":(){:|:&};:"]
            for pattern in dangerous:
                if pattern in cmd:
                    return ToolCallResult(
                        blocked=True,
                        reason=f"Blocked dangerous command: {pattern}",
                    )
        return None  # Do not block
python
tools = ToolRegistry()
for t in (ReadTool(), WriteTool(), EditTool(), BashTool(),
          GrepTool(), FindTool(), LsTool()):
    tools.register(t)

session = Session.create_new()
compaction = CompactionStrategy(max_tokens=200_000, summariser=provider)

agent = Agent(provider=provider, tools=tools, session=session, compaction=compaction)

Technical Analysis

BashTool passes an entirely model-controlled string to subprocess.run() with shell=True. ...[truncated 2147 chars]

Remediation
View remediation

Remediation Suggestions

  1. Run shell operations inside an operating-system sandbox or isolated container by default.
  2. Restrict writable paths to a canonical workspace root and deny access to host credentials, configuration directories, device files, and system paths.
  3. Disable network access by default and grant it only for explicitly approved tasks.
  4. Avoid shell=True. Prefer a structured executable and argument array, with strict validation of the executable and each argument.
  5. Maintain an allowlist of permitted commands and operations rather than a blacklist of dangerous substrings.
  6. Require explicit user approval for commands that mutate state, invoke interpreters, install software, access the network, or cross workspace boundaries.
  7. Apply resource controls for execution time, total tool runtime, process count, memory, output size, and child processes.
  8. Record shell calls, approval decisions, normalized arguments, results, and durations in a protected audit log.
  9. Treat repository files and tool output as untrusted data and ensure they cannot override authorization policy.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
references/code-templates.md:329
Finding

Filesystem Tools Permit Unrestricted Access to Host Paths

Content
View full analysis

Vulnerability Details

File Location: references/code-templates.md:329-390
Vulnerability Type: Missing workspace path authorization and traversal controls
Risk Level: High

Vulnerable Code:

python
class ReadTool(BaseTool):
    name = "read"
    description = "Read a file with line numbers"
    parameters = ReadParams

    async def execute(self, p: ReadParams) -> str:
        try:
            with open(p.path) as f:
                lines = f.readlines()
        except FileNotFoundError:
            return f"File not found: {p.path}"
        start, end = p.offset, min(p.offset + p.limit, len(lines))
        return "".join(f"{i+1:6}\t{lines[i]}" for i in range(start, end)) or "(empty file)"
python
class WriteTool(BaseTool):
    name = "write"
    description = "Write a file (overwrites)"
    parameters = WriteParams

    async def execute(self, p: WriteParams) -> str:
        with open(p.path, "w") as f:
            f.write(p.content)
        return f"Wrote {len(p.content)} chars to {p.path}"
python
class EditTool(BaseTool):
    name = "edit"
    description = "Edit a file by finding and replacing exact string"
    parameters = EditParams

    async def execute(self, p: EditParams) -> str:
        try:
            with open(p.path) as f:
                content = f.read()
        except FileNotFoundError:
            return f"File not found: {p.path}"
        count = content.count(p.old_string)
        if count == 0:
            return "String not found. Match exactly including whitespace."
        if count > 1 and not p.replace_all:
            return f"String appears {count} times. Add context or use replace_all=true."
        new_content = content.replace(
            p.old_string, p.new_string, -1 if p.replace_all else 1
        )
        with open(p.path, "w") as f:
            f.write(new_content)
        return f"Suc
...[truncated 2014 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require a configured workspace root for every filesystem tool.
  2. Reject absolute paths and normalize user-supplied relative paths before use.
  3. Resolve the final path with Path.resolve() and verify that it remains beneath the canonical workspace root.
  4. Validate every existing parent and final target against symlink escapes. For sensitive environments, use descriptor-relative APIs and no-follow semantics to reduce time-of-check/time-of-use risks.
  5. Maintain separate read and write policies; write access should be narrower than read access.
  6. Deny access to credential stores, version-control secrets, environment files, device files, sockets, and system configuration.
  7. Require explicit user approval for exceptional out-of-workspace access.
  8. Use atomic writes with secure temporary files and preserve appropriate permissions.
  9. Run the harness under a dedicated, least-privileged operating-system account and inside a sandbox.
  10. Add tests covering absolute paths, traversal sequences, nested symlinks, broken symlinks, and race conditions.

T09 · Insecure Skill Coding Practices

Warning
Location
references/code-templates.md:500
Finding

Sensitive Agent Session Data Is Persisted in Plaintext with Default Permissions

Content
View full analysis

Vulnerability Details

File Location: references/code-templates.md:500-515
Vulnerability Type: Insecure storage of potentially sensitive session data
Risk Level: Medium

Vulnerable Code:

python
class Session:
    session_id: str
    file_path: str
    leaf_id: str = ""
    root_id: str = ""

    @classmethod
    def create_new(cls, dir_path: str = "sessions") -> "Session":
        os.makedirs(dir_path, exist_ok=True)
        fp = os.path.join(dir_path, f"{uuid.uuid4()}.jsonl")
        return cls(session_id=str(uuid.uuid4()), file_path=fp)

    def append(self, entry: Entry) -> None:
        with open(self.file_path, "a") as f:
            f.write(json.dumps(asdict(entry)) + "\n")
        self.leaf_id = entry.id
        if not self.root_id:
            self.root_id = entry.id

Technical Analysis

Session entries are appended to ordinary JSONL files in plaintext. The directory and files are created using process defaults, so their effective permissions depend on the runtime umask and surrounding filesystem configuration.

Session entries can contain user prompts, model responses, tool parameters, command output, source code, file contents, and secrets encountered during agent operation. Result redaction is limited to two narrowly defined token patterns elsewhere in the template and therefore does not provide comprehensive protection. No encryption, secure file mode, retention policy, deletion mechanism, or pre-persistence sanitization is enforced.

The append-only design also retains sensitive historical entries after context compaction, increasing their storage lifetime and exposure.

Attack Path

  1. The agent reads or produces sensitive information during a task.
  2. Messages and tool results containing that information are appended to the session.
  3. The session is written as plaintext JSONL using default filesystem permissions.
  4. Another local account, proce ...[truncated 748 chars]
Remediation
View remediation

Remediation Suggestions

  1. Create the session directory with owner-only permissions, such as mode 0700.
  2. Create session files securely with mode 0600 rather than relying on the process umask.
  3. Apply comprehensive secret detection and redaction before persistence, not only when returning tool results to the model.
  4. Avoid persisting unnecessary command output and full file contents.
  5. Define configurable retention, secure deletion, export, and purge controls.
  6. Encrypt session records at rest when they can contain regulated, proprietary, or credential-bearing data.
  7. Protect encryption keys separately from the stored session data.
  8. Prevent session directories from being included in source-control commits, public artifacts, or broadly accessible backups.
  9. Document that append-only compaction retains original sensitive records and provide a deliberate privacy-preserving deletion workflow.
  10. Add startup checks that reject unsafe ownership or permission settings on an existing session directory.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (16)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

The Bash tool executes model-supplied input via subprocess.run(..., shell=True), which permits arbitrary shell command execution. In an agent harness, this is especially dangerous because LLM-generated tool arguments can be influenced by prompt injection, hostile repository content, or untrusted user/task input, leading to filesystem damage, data exfiltration, or lateral movement.

Content

Scanner excerpt · references/code-templates.md (reported line 406)May include surrounding context.

md
async def execute(self, p: BashParams) -> str:
        try:
            r = subprocess.run(
                p.command, shell=True, capture_output=True, text=True, timeout=p.timeout
            )
        except subprocess.TimeoutExpired:

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · references/code-templates.md (reported line 764)May include surrounding context.

md
async def block_dangerous(event: ToolCallEvent, ctx):
        if event.name == "bash":
            cmd = event.arguments.get("command", "")
            dangerous = ["rm -rf /", "rm -rf ~", "sudo rm", ":(){:|:&};:"]
            for pattern in dangerous:
                if pattern in cmd:
                    return ToolCallResult(

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% 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).

Content

Scanner excerpt · references/code-templates.md (reported line 764)May include surrounding context.

md
async def block_dangerous(event: ToolCallEvent, ctx):
        if event.name == "bash":
            cmd = event.arguments.get("command", "")
            dangerous = ["rm -rf /", "rm -rf ~", "sudo rm", ":(){:|:&};:"]
            for pattern in dangerous:
                if pattern in cmd:
                    return ToolCallResult(

Tool Parameter Abuse

High
Category
Tool Misuse
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).

Content

Scanner excerpt · references/code-templates.md (reported line 764)May include surrounding context.

md
async def block_dangerous(event: ToolCallEvent, ctx):
        if event.name == "bash":
            cmd = event.arguments.get("command", "")
            dangerous = ["rm -rf /", "rm -rf ~", "sudo rm", ":(){:|:&};:"]
            for pattern in dangerous:
                if pattern in cmd:
                    return ToolCallResult(

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill’s trigger phrases are very broad and overlap with many ordinary software-engineering requests, which can cause the skill to activate in contexts where the user did not intend to invoke harness-building guidance. This creates prompt-scope confusion and can steer the agent toward a more powerful or opinionated workflow than necessary, increasing the chance of inappropriate tool-selection or architectural bias.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file is written as a bilingual Chinese/English architecture overview, with headings, prose, and examples mixing both languages. Under the language/locale policy rule, forcing a specific language presentation without user opt-in or a documented justification can be a policy violation for users who expect a single language or locale-consistent skill material.

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 · references/architecture.md (reported line 391)May include surrounding context.

markdown
---
name: commit
description: Create git commits using Conventional Commits format
---
# Commit
Create a commit for the current changes using a Conventional Commits subject:

Skill Enumeration

Medium
Category
Agent Snooping
Confidence
80% confidence
Finding

Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Content

Scanner excerpt · references/architecture.md (reported line 415)May include surrounding context.

commit Create git commits using Conventional Commits format /Users/edd/.agent/skills/commit/SKILL.md ```

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The document is written entirely in Chinese and presents itself as the reference implementation template without offering an alternative language or indicating that the locale is intentionally restricted to a Chinese-speaking context. Under the stated policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown file presents a reusable agent template that enables write, edit, and bash tools by default, which can overwrite files and execute shell commands. The surrounding documentation explains how to assemble and run the harness but does not include a clear warning that using these capabilities may modify files or affect the local system.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/code-templates.md (reported line 764)May include surrounding context.

md
async def block_dangerous(event: ToolCallEvent, ctx):
        if event.name == "bash":
            cmd = event.arguments.get("command", "")
            dangerous = ["rm -rf /", "rm -rf ~", "sudo rm", ":(){:|:&};:"]
            for pattern in dangerous:
                if pattern in cmd:
                    return ToolCallResult(

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The document title and the full instructional content are written in Chinese, which imposes a specific language on readers without any stated opt-in, alternative locale, or region-specific justification. Under the language/locale policy rule, this is a natural-language policy violation because the file does not indicate that Chinese is optional or required for a documented compliance reason.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

该技能文档标题及全文内容均以中文呈现,未见任何提示表明这是可选语言,或该技能仅面向特定中文用户/区域。根据语言/locale 政策,若技能默认强制单一语言而未提供用户选择或明确理由,属于自然语言策略违规。

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
77% confidence
Finding

The primary descriptions and much of the document are written in Chinese with embedded English terminology, but there is no statement that the skill should match the user's preferred language. This can conflict with language-choice policy when the user has not opted into Chinese or bilingual output.

Content

No source excerpt is available for this finding.

Vague Triggers

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The typical usage example is framed so broadly that many normal coding requests could match it, without constraints that distinguish full harness engineering from simpler agent or automation tasks. This can lead to over-application of the skill, unnecessary complexity, and accidental override of more relevant task-specific guidance.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This markdown file is entirely presented in Chinese starting from the title, with no indication that the language choice is optional or region-specific. Under the policy rule, forcing a specific language without user opt-in is a natural-language locale violation.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
references/long-running-patterns.md:355