Back to skill

Security audit

PR Autocheck

Security checks for vulnerabilities and agentic risk

Overview

This PR-check skill is mostly coherent, but it needs Review because it can execute a configurable health-check command and send review/health data to an unvalidated webhook.

Install only in a controlled repository or CI environment where trusted maintainers control HEALTHCHECK_CMD, the healthcheck skill path, and DISCORD_WEBHOOK_URL. Use a protected Discord webhook secret, avoid running it on untrusted PR-controlled configuration, and review generated reports for sensitive health or repository details before publishing them as artifacts.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run.sh:31
Finding

Arbitrary Command Execution Through HEALTHCHECK_CMD

Content
View full analysis

Vulnerability Details

File Location: scripts/run.sh, lines 31–38
Vulnerability Type: Command injection through unsafe command-string execution
Risk Level: High

Vulnerable Code:

bash
HC_DEFAULT="$HOME/.openclaw/workspace/skills/healthcheck/healthcheck.sh"
HEALTH_CMD="${HEALTHCHECK_CMD:-}"
if [ -z "$HEALTH_CMD" ] && [ -f "$HC_DEFAULT" ]; then HEALTH_CMD="bash $HC_DEFAULT --json"; fi
HEALTH_RAW=""; HEALTH_OK=0
if [ -n "$HEALTH_CMD" ]; then
  HEALTH_RAW=$($HEALTH_CMD 2>/dev/null)
  if [ -n "$HEALTH_RAW" ] && printf '%s' "$HEALTH_RAW" | jq -e 'type=="object"' >/dev/null 2>&1; then
    HEALTH_OK=1
  fi
fi

Technical Analysis

HEALTHCHECK_CMD is read from the process environment and expanded directly inside command substitution. Shell word splitting turns the supplied string into an executable and arguments without enforcing an allowlist or trusted executable path.

For example, a value structured as sh -c COMMAND can invoke an arbitrary shell command. The JSON validation occurs only after execution and therefore does not protect against malicious commands.

When the environment variable is unset, the script also automatically executes $HOME/.openclaw/workspace/skills/healthcheck/healthcheck.sh. This is a mutable user-workspace location, and the script performs no ownership, permission, integrity, or symlink checks before execution.

Attack Path

  1. An attacker gains the ability to set HEALTHCHECK_CMD in the CI job, hook environment, scheduler configuration, or parent process.
  2. The attacker assigns a command such as a shell interpreter with a -c argument and an attacker-selected payload.
  3. A user or automated system invokes scripts/run.sh.
  4. Line 37 executes the attacker-selected command.
  5. The payload runs with the operating-system privileges and environment access of the PR autocheck process.

An alternative path is to replace or redirect t ...[truncated 582 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not execute a free-form command string from an environment variable.
  • Configure a trusted executable path separately and invoke it through a Bash array with fixed arguments.
  • If customization is required, accept only a validated executable path and pass arguments through separate, explicitly parsed fields.
  • Require the executable to be a regular file owned by an expected user, not group- or world-writable, and not a symbolic link.
  • Avoid automatically executing scripts from mutable workspace directories. Bundle the health checker with the Skill or verify its integrity before execution.
  • Run the health check under a restricted account or sandbox with a minimal environment, filesystem access, and network access.
  • Apply an execution timeout and validate the returned JSON only as output validation, not as an execution security control.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/notify-discord.sh:65
Finding

Unrestricted Webhook URL Enables Report Exfiltration and Internal Requests

Content
View full analysis

Vulnerability Details

File Location: scripts/notify-discord.sh, lines 65–68
Vulnerability Type: Unvalidated outbound request destination
Risk Level: Medium

Vulnerable Code:

bash
HTTP=$(curl -sS -o /tmp/discord_resp.$$ -w '%{http_code}' \
  -H 'Content-Type: application/json' \
  -X POST "$DISCORD_WEBHOOK_URL" -d "$PAYLOAD")
RC=$?

Technical Analysis

The script describes DISCORD_WEBHOOK_URL as a Discord webhook but sends the payload to the supplied URL without validating the URL scheme, hostname, port, resolved address, or path. Consequently, the destination can be an attacker-controlled host or an internal service reachable from the execution environment.

The transmitted payload contains the repository name, PR label, overall result, code-review summary, health summary, and up to eight finding titles and severities. The full raw health-check object is not included in this Discord payload, which limits but does not eliminate the disclosure.

Attack Path

  1. An attacker or compromised configuration source controls DISCORD_WEBHOOK_URL.
  2. The value is changed to an attacker-operated endpoint or an internal HTTP service.
  3. scripts/run.sh pipes the generated report to scripts/notify-discord.sh.
  4. The notifier constructs the embed payload and POSTs it to the unvalidated destination.
  5. The destination receives project and operational metadata, or the execution environment performs an unintended request against an internally reachable service.

Impact Assessment

Exploitation can disclose repository identifiers, PR metadata, review results, and service-health summaries. It can also provide a limited server-side request capability from the CI or developer environment. The request is a JSON POST with an attacker-selected destination but a script-generated body, so it does not provide unrestricted HTTP request construction or direct arbitrary code execution.

Remediation
View remediation

Remediation Suggestions

  • Require an https URL and reject all other schemes.
  • Allowlist official Discord webhook hostnames and validate the expected webhook path format.
  • Reject URLs containing embedded credentials, unexpected ports, fragments, or malformed hostnames.
  • Resolve the hostname and reject loopback, link-local, private, multicast, and other special-use addresses.
  • Disable redirects with --max-redirs 0, or independently validate every redirect destination.
  • Store the webhook configuration in a protected CI secret rather than accepting it from untrusted PR-controlled configuration.
  • Consider applying an outbound network policy that permits only the required Discord endpoint.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/notify-discord.sh:65
Finding

Predictable Temporary Response File Allows Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/notify-discord.sh, lines 65–70
Vulnerability Type: Unsafe predictable temporary file
Risk Level: Medium

Vulnerable Code:

bash
HTTP=$(curl -sS -o /tmp/discord_resp.$$ -w '%{http_code}' \
  -H 'Content-Type: application/json' \
  -X POST "$DISCORD_WEBHOOK_URL" -d "$PAYLOAD")
RC=$?
BODY=$(cat /tmp/discord_resp.$$ 2>/dev/null); rm -f /tmp/discord_resp.$$
if [ $RC -ne 0 ]; then

Technical Analysis

The response filename is derived only from the process ID. Process IDs are predictable and reused, while /tmp is typically writable by all local users. The script neither creates the file atomically nor checks whether it is a symbolic link.

curl -o opens the path for writing and can follow a pre-existing symbolic link. A local attacker who creates the expected path as a symlink can redirect the response write to another file writable by the Skill account. The subsequent rm removes the symlink path rather than restoring the overwritten target.

Attack Path

  1. A local attacker predicts or observes the notifier's process ID.
  2. Before curl opens the response path, the attacker creates /tmp/discord_resp.PID as a symbolic link to a target file.
  3. The notifier invokes curl -o /tmp/discord_resp.PID.
  4. curl follows the link and truncates or overwrites the target with the webhook response.
  5. The notifier reads the path and removes the temporary symlink, leaving the target file modified.

Exploitation requires local access and successful timing or process-ID prediction.

Impact Assessment

The attacker can overwrite files that are writable by the account executing the Skill. Depending on the selected target, this may corrupt reports, repository files, user configuration, shell initialization files, or other writable application state. It does not bypass filesystem permissions and therefore cannot overwrite files inaccessible to the ...[truncated 15 chars]

Remediation
View remediation

Remediation Suggestions

  • Create the response file using mktemp, for example within ${TMPDIR:-/tmp}.
  • Immediately verify that temporary-file creation succeeded.
  • Set umask 077 before creating temporary files.
  • Install an EXIT, INT, and TERM trap to remove the generated file reliably.
  • Quote every use of the temporary path.
  • Prefer capturing only a bounded response body where possible, and configure curl time and size limits.
  • For stronger isolation, create a private temporary directory with mode 0700 and place all transient files inside it.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/run.sh:43
Finding

Raw Health-Check Data Is Persisted Without Restrictive Permissions or Redaction

Content
View full analysis

Vulnerability Details

File Location: scripts/run.sh, lines 43–45 and 60–66
Vulnerability Type: Insecure storage of potentially sensitive diagnostic data
Risk Level: Low

Vulnerable Code:

bash
HCOUNT=$(printf '%s' "$HEALTH_RAW" | jq -r '(.checks // {}) | length')
HEALTH=$(jq -nc --arg s "$HSTAT" --arg sum "$HCOUNT service(s) checked (max_severity $HSEV)" \
  --argjson raw "$HEALTH_RAW" '{status:$s, summary:$sum, raw:$raw}')
bash
REPORT=$(jq -nc \
  --arg repo "$REPO" --arg pr "$PR" --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
  --arg overall "$OVERALL" --argjson review "$REVIEW" --argjson health "$HEALTH" \
  '{repo:$repo, pr:$pr, timestamp:$ts, overall:$overall, review:$review, health:$health}')

OUT="reports/pr-autocheck-${REPO}-$(date +%Y%m%dT%H%M%S).json"
printf '%s\n' "$REPORT" > "$OUT"

Technical Analysis

The entire health-check JSON object is embedded under health.raw and then persisted in the reports directory. No field allowlist or redaction is applied. The file mode is determined by the caller's ambient umask; the script does not ensure that only the invoking user can read the report.

Although the contents depend on the external health checker, diagnostic output commonly includes hostnames, service names, internal endpoints, software versions, failure details, or other operational metadata. The report also remains on disk without retention or cleanup controls.

Attack Path

  1. The configured health checker emits JSON containing sensitive diagnostic or infrastructure data.
  2. run.sh stores the complete object in health.raw.
  3. The combined report is written under reports/ using ambient permissions.
  4. Another local user, CI artifact consumer, or process with access to the workspace reads the retained report.

Impact Assessment

Exploitation may disclose operational metadata and any sensitive values included by the health checker. The exact ...[truncated 143 chars]

Remediation
View remediation

Remediation Suggestions

  • Set umask 077 before creating the reports directory or report files.
  • Create reports with explicit owner-only permissions and verify that reports is not an unsafe symbolic link.
  • Do not persist the full health-check object by default.
  • Construct an allowlisted health summary containing only required status, severity, and count fields.
  • Redact credentials, tokens, URLs containing credentials, internal addresses, environment values, and verbose error output.
  • Add configurable retention and secure cleanup for generated reports.
  • Review CI artifact publication rules so reports are not exposed to untrusted users or public build outputs.
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This second description-behavior mismatch likewise indicates that the skill may be presented as a complete PR autocheck workflow while actually functioning as a narrower CLI over git refs. In a CI or post-submit setting, that gap can cause teams to believe service health validation, report combination, and Discord delivery occurred when they did not, undermining enforcement and incident visibility.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

This second description-behavior mismatch likewise indicates that the skill may be presented as a complete PR autocheck workflow while actually functioning as a narrower CLI over git refs. In a CI or post-submit setting, that gap can cause teams to believe service health validation, report combination, and Discord delivery occurred when they did not, undermining enforcement and incident visibility.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run.sh --base origin/main --head HEAD --repo myrepo --pr 130

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run.sh --base origin/main --head HEAD --repo myrepo --pr 130

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
bash scripts/run.sh --base origin/main --head HEAD --repo myrepo --pr 130

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
1. `scripts/review.sh BASE HEAD` — deterministic review of the diff. Flags

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
3. `scripts/notify-discord.sh` — builds a color-coded Discord embed from the

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% 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 · scripts/notify-discord.sh (reported line 70)May include surrounding context.

sh
-H 'Content-Type: application/json' \
  -X POST "$DISCORD_WEBHOOK_URL" -d "$PAYLOAD")
RC=$?
BODY=$(cat /tmp/discord_resp.$$ 2>/dev/null); rm -f /tmp/discord_resp.$$
if [ $RC -ne 0 ]; then
  echo "DELIVERY_FAILED: curl error $RC" >&2; exit 1
fi

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · scripts/notify-discord.sh (reported line 70)May include surrounding context.

sh
-H 'Content-Type: application/json' \
  -X POST "$DISCORD_WEBHOOK_URL" -d "$PAYLOAD")
RC=$?
BODY=$(cat /tmp/discord_resp.$$ 2>/dev/null); rm -f /tmp/discord_resp.$$
if [ $RC -ne 0 ]; then
  echo "DELIVERY_FAILED: curl error $RC" >&2; exit 1
fi

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill advertises and invokes shell-based execution but does not declare any tool scope such as permissions or allowed-tools. In an agent environment, this creates ambiguity about what execution capabilities the skill is expected to use, increasing the risk of over-broad command execution, unsafe orchestration, or accidental use in contexts that should forbid shell access.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The script transmits a synthesized report to an external destination via a webhook URL taken from the environment. This is expected functionality for a Discord notification helper, but it still creates a real data-exfiltration path because repo, PR, review summary, health summary, and findings are sent off-host to whatever URL is configured.

Content

Scanner excerpt · scripts/notify-discord.sh (reported line 66)May include surrounding context.

sh
exit 3
fi

HTTP=$(curl -sS -o /tmp/discord_resp.$$ -w '%{http_code}' \
  -H 'Content-Type: application/json' \
  -X POST "$DISCORD_WEBHOOK_URL" -d "$PAYLOAD")
RC=$?

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script executes HEALTHCHECK_CMD via command substitution without constraining it to a fixed executable or validated argument list. Because this skill is intended for automated PR/post-submit use, any actor who can influence the environment can trigger arbitrary code execution in the runner context, which exceeds the stated purpose of health aggregation and may expose repo contents, CI secrets, or network access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The override command is executed silently with no user-facing disclosure or confirmation, which makes dangerous behavior easy to hide in automation. In a CI or agent setting, this increases the chance that operators unknowingly run attacker-controlled shell commands supplied through environment configuration.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The script automatically sends the combined PR review and health report to a Discord webhook with no interactive disclosure at send time. In an automated post-submit context, this can leak sensitive code-review findings, repository metadata, or service health details to an external endpoint if the webhook is misconfigured, attacker-controlled, or unexpectedly enabled.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.