Back to skill

Security audit

Environment Doc Author

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent environment-documentation purpose, but its probe files can run arbitrary local commands and its generated baselines can preserve sensitive machine details, so it needs review before installation.

Install only if you trust the skill publisher and will treat probe files and baselines as sensitive executable inputs. Do not run it with untrusted probe files, review generated JSON and Markdown before committing or sharing them, and assume outputs may contain local paths, hostnames, PATH entries, and environment-derived secrets unless manually redacted.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/detect_environment.py:899
Finding
Unrestricted Command Execution Through Probe Files<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/detect_environment.py:509-513` - `scripts/detect_environment.py:899-906` - `scripts/detect_environment.js:537-540` - `scripts/detect_environment.js:846-854` - `references/probe-file.md:83-87` **Vulnerability Type**: Arbitrary command execution through trusted configuration **Risk Level**: High ### Vulnerable Code Python probe loading and command execution: ```python def load_probe_file(path: str | None) -> dict[str, Any]: if not path: return {} probe_path = Path(path) return json.loads(probe_path.read_text(encoding="utf-8-sig")) ``` ```python def run_checks(extra_probe_data: dict[str, Any], baseline_data: dict[str, Any] | None) -> dict[str, Any]: existing_checks = deepcopy((baseline_data or {}).get("checks", {})) if not extra_probe_data.get("checks"): return existing_checks for check in extra_probe_data["checks"]: command = check["command"] result = run_command(command, timeout=check.get("timeout", 8), cwd=check.get("cwd")) ``` JavaScript equivalent: ```javascript function loadProbeFile(pathname) { if (!pathname) return {}; return JSON.parse(readText(pathname)); } ``` ```javascript function runChecks(extraProbeData, baselineData) { const existingChecks = deepClone((baselineData || {}).checks || {}); if (!extraProbeData.checks) return existingChecks; for (const check of extraProbeData.checks) { const result = runCommand(check.command, { timeout: check.timeout == null ? 8 : check.timeout, cwd: check.cwd || null, }); ``` The documented command field explicitly permits direct execution: ```markdown - `command` - Command array executed exactly as provided. ``` ### Technical Analysis Probe files are parsed as JSON and then treated as trusted executable configuration. The `checks[].command`, `cwd`, and timeout fields are accepted without command allowlisting, path restrictions, a safety preview, or explici ...[truncated 2009 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every probe file as executable code and clearly document that untrusted probe files must never be used. 2. Add an explicit opt-in flag such as `--allow-command-execution`; reject `checks` unless it is present. 3. Display the complete commands, working directories, and requested environment variables before execution and require interactive or caller-supplied approval. 4. Prefer declarative, built-in read-only probe types over arbitrary commands. 5. Allowlist approved executables and argument forms for common service, port, and file-existence checks. 6. Reject shell interpreters and command processors by default, including `bash`, `sh`, `zsh`, `cmd.exe`, and PowerShell. 7. Restrict `cwd` to an approved project root and reject traversal outside that root. 8. Validate the complete probe-file schema, including field types, array sizes, timeout limits, and command lengths. 9. Execute approved probes in a sandbox with minimal filesystem, environment, and network access where platform support permits. 10. Avoid passing the detector's complete environment to child processes; construct a minimal environment explicitly. ]]>

T02 · Agent Memory Poisoning

Warning
Location
scripts/render_environment_docs.py:179
Finding
Persistent Agent-Policy Injection Through Unescaped Baseline Content<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/render_environment_docs.py:179` - `scripts/render_environment_docs.py:332-350` - `scripts/render_environment_docs.py:455-460` - `scripts/render_environment_docs.js:328-354` - `scripts/render_environment_docs.js:478-483` **Vulnerability Type**: Persistent instruction injection into generated agent-facing documentation **Risk Level**: Medium ### Vulnerable Code Baseline-controlled tool labels and notes are inserted directly into Markdown: ```python def render_tool_section( tool_id: str, tool: dict[str, Any], section_number: int, env_vars: dict[str, dict[str, Any]], os_family: str, lang: str, ) -> list[str]: lines = [f"### 3.{section_number} {tool.get('label', tool_id)}", ""] ``` ```python for note in tool.get("notes", []): lines.append(L(lang, f"- Note: {note}", f"- 说明:{note}")) return lines ``` Check labels and commands are also rendered without neutralizing Markdown control characters: ```python def render_checks(data: dict[str, Any], section_number: int, lang: str) -> list[str]: checks = data.get("checks", {}) if not checks: return [] lines = [f"### 3.{section_number} {L(lang, 'Additional environment elements', '补充环境要素')}", ""] for check_id in sorted(checks.keys()): check = checks[check_id] lines.append(dash(check.get("label", check_id), check.get("status"), lang)) lines.append(L(lang, f" - Command: {code(' '.join(check.get('command', [])))}", f" - 命令:{code(' '.join(check.get('command', [])))}")) ``` Environment values are copied directly into the policy: ```python for name in sorted(env_vars.keys()): value = env_vars[name].get("value") if value: lines.append(f"- `{name}={value}`") ``` The generated policy is presented as mandatory agent guidance: ```python L( lang, "All models, AI agents, CLIs, OpenClaw sessions, or other automations must read this docum ...[truncated 2376 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define and enforce strict JSON schemas for baseline and probe data before rendering. 2. Reject control characters and embedded newlines in labels, IDs, paths, versions, environment-variable names, statuses, and notes. 3. Escape Markdown-sensitive characters, especially backticks, heading markers, brackets, HTML delimiters, and list prefixes. 4. Render machine-derived values inside clearly delimited data blocks rather than instruction sections. 5. Add a prominent statement that generated inventory values are untrusted data and must never be interpreted as instructions. 6. Do not place arbitrary environment-variable values or command output into agent instruction documents. 7. Maintain a fixed allowlist of environment-variable names and redact values not required for tool selection. 8. Separate generated factual inventory from durable `AGENTS` or Skill rules. Agent instructions should come from static reviewed templates only. 9. Add tests using malicious multiline labels, notes, paths, versions, and environment values to verify that they cannot alter document structure. 10. Require review before replacing an existing policy consumed by agents. ]]>

T05 · Unauthorized Access and Privilege Escalation

Note
Location
scripts/detect_environment.py:783
Finding
Overbroad Collection and Persistence of Local Environment Information<![CDATA[ ## Vulnerability Details **File Location**: - `scripts/detect_environment.py:783-796` - `scripts/detect_environment.py:810-811` - `scripts/detect_environment.py:976-981` - `scripts/detect_environment.js:751-764` - `scripts/detect_environment.js:778-781` - `scripts/detect_environment.js:1007-1012` **Vulnerability Type**: Excessive environment reconnaissance and plaintext persistence of sensitive process data **Risk Level**: Low ### Vulnerable Code Environment-variable names from an existing baseline are automatically re-read from the live process: ```python def collect_environment_variables( extra_probe_data: dict[str, Any], baseline_data: dict[str, Any] | None, ) -> dict[str, dict[str, Any]]: requested = set(DEFAULT_ENV_VARS) requested.update(extra_probe_data.get("env_vars", [])) requested.update((baseline_data or {}).get("environment_variables", {}).keys()) output: dict[str, dict[str, Any]] = {} for name in sorted(requested): value = os.environ.get(name) output[name] = { "status": "set" if value else "unset", "value": value, } return output ``` The complete PATH is persisted rather than only the entries needed by selected tools: ```python raw_path = os.environ.get("PATH", "") entries = [canonicalize_path(item) or item for item in raw_path.split(os.pathsep) if item] ``` Host and working-directory information are collected in the baseline context: ```python "context": { "hostname": socket.gethostname(), "platform": platform.platform(), "platform_system": platform.system(), "os_family": family, "python_version": platform.python_version(), "cwd": canonicalize_path(os.getcwd()), ``` The JavaScript implementation performs equivalent collection: ```javascript for (const name of Object.keys(((baselineData || {}).environment_variables) || {})) requested.add ...[truncated 3029 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove hostname collection from the default snapshot unless a caller explicitly requests machine identification. 2. Omit the current working directory or store only a non-sensitive project-relative identifier. 3. Do not persist the complete PATH by default. Store only entries directly associated with verified tools. 4. Never inherit environment-variable names from an untrusted baseline. 5. Use a fixed allowlist of non-secret toolchain variables and require explicit opt-in for each additional variable. 6. Add a denylist for common secret-bearing names such as tokens, passwords, credentials, and private keys as defense in depth. 7. Prefer recording whether a variable is set and whether its referenced path exists rather than storing its raw value. 8. Redact user-home prefixes and other identifying path components where exact absolute paths are unnecessary. 9. Warn users that generated baselines contain machine-specific information and should not be committed or shared without review. 10. Support a privacy-preserving mode and make it the default, with more detailed reconnaissance enabled only through explicit flags. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (29)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
Advertising live detection and baseline refresh when a component may only render existing baseline data can undermine security controls that depend on real-time verification. In this context, the danger is not direct code execution alone but incorrect operational decisions made from stale, incomplete, or assumed environment facts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
Advertising live detection and baseline refresh when a component may only render existing baseline data can undermine security controls that depend on real-time verification. In this context, the danger is not direct code execution alone but incorrect operational decisions made from stale, incomplete, or assumed environment facts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
Advertising live detection and baseline refresh when a component may only render existing baseline data can undermine security controls that depend on real-time verification. In this context, the danger is not direct code execution alone but incorrect operational decisions made from stale, incomplete, or assumed environment facts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
Advertising live detection and baseline refresh when a component may only render existing baseline data can undermine security controls that depend on real-time verification. In this context, the danger is not direct code execution alone but incorrect operational decisions made from stale, incomplete, or assumed environment facts.

Ae1

High
Category
analysis-evasion
Content
- `scripts/detect_environment.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/detect_environment.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/detect_environment.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/detect_environment.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/render_environment_docs.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/render_environment_docs.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/render_environment_docs.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
- `scripts/render_environment_docs.js`
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Hidden Instructions

High
Category
Prompt Injection
Content
# Probe File

Use an extra probe file when the default detector is not enough.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
# Probe File

Use an extra probe file when the default detector is not enough.
Confidence
60% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The script accepts probe-file defined checks and executes their arbitrary command arrays via subprocess.run. That extends the feature from passive environment detection into arbitrary local command execution, which is dangerous if the probe file is untrusted or machine-generated by another agent, especially in a skill intended to inspect host state.

Missing User Warnings

High
Confidence
98% confidence
Finding
The script emits every non-empty environment variable from the baseline into human-readable documents, which can persist secrets such as tokens, passwords, API keys, proxy credentials, or internal endpoints to markdown files. In this skill context, the tool is specifically designed to inventory and publish local environment facts, making accidental secret disclosure more dangerous because the output is likely to be shared with agents, committed to repositories, or stored in broadly readable locations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill instructs agents to read environment state, execute local probes, and write multiple documentation files, but it does not declare any explicit tool scope or permission boundaries. In an agent ecosystem, that omission increases the chance that a caller invokes shell, file read/write, and environment access more broadly than intended, reducing reviewability and enabling unsafe execution against the host.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill is designed to collect and document environment variables, PATH entries, install roots, services, and other machine configuration details, but it lacks a clear privacy warning about the sensitivity of that data. This can lead to inadvertent disclosure of usernames, internal hostnames, filesystem layout, tokens in environment variables, or enterprise infrastructure details through generated JSON and markdown artifacts.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The invocation guidance is broad enough to trigger this skill for many tasks involving local tools, which can normalize unnecessary environment probing, shell execution, and documentation writes. In a security-sensitive agent environment, overly broad routing increases the attack surface and the chance of collecting or persisting sensitive host information when a narrower skill would suffice.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The language rules force output to English whenever the locale cannot be recognized. This is a natural-language policy concern because it imposes a specific language choice without offering the user a choice or requiring opt-in in the fallback case.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script collects and serializes raw values for many environment variables, including locations and potentially sensitive tokens or secrets if a baseline/probe file adds more names. In the context of an environment-documenting skill, this data is likely to be persisted or surfaced to downstream agents, which increases the risk of host information disclosure beyond what is necessary for tool detection.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
When --output is used, the script writes the full environment snapshot to disk, including hostname, PATH-derived details, tool locations, and collected environment-variable values. Persisting this inventory without any warning, redaction, or permission control can leak sensitive workstation metadata and secrets if the file is later committed, shared, or read by other tools.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The probe file can request collection of any environment variable name, and the snapshot stores raw values in JSON. This can exfiltrate secrets or sensitive local configuration such as tokens, credentials, internal paths, or service endpoints under the guise of environment documentation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Configured checks run subprocess commands supplied by configuration, but the CLI description and output behavior frame the tool as environment fact detection rather than code execution. That mismatch increases the chance that users or agents will supply or trust probe files without realizing they authorize command execution on the local machine.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The generated snapshot includes hostname, cwd, PATH entries, tool locations, and raw environment variable values, then writes them to stdout or a file without any interactive warning or redaction step. In the context of an agent skill that may generate shareable baseline documents, this creates a meaningful risk of leaking host metadata and secrets into artifacts, logs, or repositories.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/detect_environment.js:427