Back to skill

Security audit

openclaw-gitcode-pr-monitor

Security checks for vulnerabilities and agentic risk

Overview

This skill is not clearly malicious, but it needs Review because it automatically uses credentials, runs a general OpenClaw agent on PR content, posts review comments, and sends reports to external chat channels.

Install only if you are comfortable with automatic PR comments and external chat notifications. Use a dedicated least-privilege GitCode token, secure the token file, avoid running it with elevated privileges, consider disabling automatic posting/attachments until reviewed, and prefer an isolated review agent/session for each PR.

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

Error
Location
scripts/code-review-robust.sh:22
Finding
Untrusted PR content is reviewed by a privileged, stateful main agent<![CDATA[ ## Vulnerability Details **File Location**: `scripts/code-review-robust.sh:22-94` **Vulnerability Type**: Indirect prompt injection and excessive agent privileges **Risk Level**: High ### Vulnerable Code ```bash SESSION_ID="gitcode-pr-review-${REPO_OWNER}-${REPO_NAME}-$(date +%Y%m%d)" WORKSPACE_DIR="${OPENCLAW_WORKSPACE:-${HOME}/.openclaw/workspace}" REVIEW_DIR="$WORKSPACE_DIR/reviews/$(date +%Y-%m)" mkdir -p "$REVIEW_DIR" REVIEW_FILE="$REVIEW_DIR/PR-${PR_ID}-${REPO_NAME}.md" LOG_FILE="$WORKSPACE_DIR/logs/code-review-${REPO_NAME}-${PR_ID}.log" TASK="... - API: https://gitcode.com/api/v5/repos/${REPO_OWNER}/${REPO_NAME}/pulls/${PR_ID}/files - Token path: $WORKSPACE_DIR/data/gitcode-token.txt ... - The report must be saved to: ${REVIEW_FILE} ..." AGENT_OUTPUT=$("$OPENCLAW_CMD" agent \ --agent main \ --session-id "$SESSION_ID" \ --message "$TASK" \ --timeout 600 \ --thinking high \ 2>&1) || true ``` The `TASK` excerpt above is an English rendering of the original task text while preserving the security-relevant paths, endpoint, and instructions. ### Technical Analysis The script delegates review of contributor-controlled PR content to the OpenClaw `main` agent. The task directs that agent to retrieve the PR diff, reveals the local GitCode credential path, and directs it to write to a workspace report file. No control shown in the audited code: - Restricts the agent to a dedicated, least-privileged review profile. - Removes filesystem or network tools not required for analysis. - Treats instructions embedded in source code, comments, filenames, or diff text as untrusted data. - Prevents the agent from reading files other than the intended PR data. - Prevents secrets or unrelated workspace content from being included in the generated report. The session identifier is reused for all PRs in the same repository during a given day. Consequently, malicious content encountered while reviewing one PR can potentially influence ...[truncated 2140 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a dedicated review-only agent instead of using `--agent main`. 2. Remove filesystem, shell, credential, messaging, and unrestricted network tools from the review agent. 3. Fetch PR metadata and diffs in a deterministic wrapper, then provide only the required sanitized diff to the model. 4. Do not disclose credential paths or token-handling details in model prompts. 5. Explicitly state that all repository content is untrusted data and that instructions found in code, comments, documentation, filenames, or diffs must never be followed. 6. Use a fresh session for every PR, such as a session identifier containing the immutable repository identity and PR number. 7. Apply output controls before publication: - Scan for tokens, secrets, private keys, and unexpected file contents. - Enforce report size and format limits. - Require human approval before sending reports outside GitCode. 8. Separate review generation from publication. The review agent should not have access to DingTalk, WeCom, or GitCode comment-posting capabilities. 9. Use a narrowly scoped GitCode token with read-only access for diff retrieval. Use a separate narrowly scoped credential for comment submission. 10. Run the review process in a sandbox with an isolated filesystem, no inherited secrets, and an explicit destination allowlist. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gitcode-pr-monitor-agent.sh:96
Finding
Predictable shared temporary PID files can cause arbitrary process termination<![CDATA[ ## Vulnerability Details **File Location**: `scripts/gitcode-pr-monitor-agent.sh:96-121` and `scripts/monitor-gitcode-pr.sh:37-77` **Vulnerability Type**: Unsafe temporary files and untrusted PID-file handling **Risk Level**: Medium ### Vulnerable Code Global monitor lock handling: ```bash LOCKFILE="/tmp/gitcode-monitor.lock" PIDFILE="/tmp/gitcode-monitor.pid" MAX_AGE_SECONDS=1800 cleanup() { rm -f "$LOCKFILE" "$PIDFILE" echo "[$(date '+%Y-%m-%d %H:%M:%S')] Cleaning lock files and exiting" >> "$ALERT_LOG" } trap cleanup EXIT INT TERM if [ -f "$PIDFILE" ]; then OLD_PID=$(cat "$PIDFILE" 2>/dev/null || true) OLD_AGE=$(( $(date +%s) - $(stat -c %Y "$PIDFILE" 2>/dev/null || echo 0) )) if [ -n "${OLD_PID:-}" ] && kill -0 "$OLD_PID" 2>/dev/null; then if [ "$OLD_AGE" -gt "$MAX_AGE_SECONDS" ]; then kill -9 "$OLD_PID" 2>/dev/null || true sleep 1 rm -f "$LOCKFILE" "$PIDFILE" fi fi fi ``` Per-repository lock handling: ```bash SUB_LOCKFILE="/tmp/gitcode-monitor-sub-${REPO_NAME}.lock" SUB_PIDFILE="/tmp/gitcode-monitor-sub-${REPO_NAME}.pid" SUB_MAX_AGE_SECONDS=240 if [ -f "$SUB_PIDFILE" ]; then OLD_PID=$(cat "$SUB_PIDFILE" 2>/dev/null || true) OLD_AGE=$(( $(date +%s) - $(stat -c %Y "$SUB_PIDFILE" 2>/dev/null || echo 0) )) if [ -n "${OLD_PID:-}" ] && kill -0 "$OLD_PID" 2>/dev/null; then if [ "$OLD_AGE" -gt "$SUB_MAX_AGE_SECONDS" ]; then kill -9 "$OLD_PID" 2>/dev/null || true sleep 1 rm -f "$SUB_LOCKFILE" "$SUB_PIDFILE" fi fi fi ``` Comments and log messages have been rendered in English; the executable security-relevant statements are unchanged. ### Technical Analysis The scripts use predictable filenames in the shared `/tmp` directory. They read PID values from those files and send `SIGKILL` after checking only that: - The PID currently exists. - The PID file appears older than the configured timeout. The scri ...[truncated 2009 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace PID-file locking with `flock` on a securely opened file descriptor: ```bash RUNTIME_DIR="${XDG_RUNTIME_DIR:-$HOME/.local/run}/openclaw-gitcode-pr-monitor" install -d -m 700 "$RUNTIME_DIR" exec 9>"$RUNTIME_DIR/monitor.lock" flock -n 9 || exit 0 ``` 2. Keep locks in a directory owned by the executing user with mode `0700`, not directly under shared `/tmp`. 3. Do not terminate a process solely because its PID appears in a file. 4. If stale-process termination remains necessary, verify all of the following: - PID-file ownership and permissions. - Regular-file status and absence of symbolic links. - Process owner. - Expected executable and complete command line. - Process start time, preventing PID-reuse errors. 5. Prefer graceful termination with a bounded wait before considering `SIGKILL`. 6. Validate `REPO_NAME` and `REPO_OWNER` against a strict allowlist such as letters, digits, dots, underscores, and hyphens. 7. Use a hash of the canonical repository identifier for per-repository lock names rather than embedding unchecked values directly. 8. Use `mktemp -d` with restrictive permissions for any temporary workspace that cannot be placed under a private runtime directory. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/monitor-gitcode-pr.sh:90
Finding
Plaintext GitCode token is accepted without ownership or permission validation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/monitor-gitcode-pr.sh:90-101` and `scripts/submit-pr-comment.sh:12-21` **Vulnerability Type**: Insecure local credential storage and validation **Risk Level**: Low ### Vulnerable Code Token use by the monitor: ```bash GITCODE_TOKEN="" if [ -f "$TOKEN_FILE" ]; then GITCODE_TOKEN=$(tr -d '\n' < "$TOKEN_FILE") fi API_URL="https://gitcode.com/api/v5/repos/${REPO_OWNER}/${REPO_NAME}/pulls?state=open&sort=created&direction=desc&per_page=5" if [ -n "$GITCODE_TOKEN" ]; then PR_RESPONSE=$(curl -s -H "PRIVATE-TOKEN: ${GITCODE_TOKEN}" "$API_URL" 2>/dev/null || true) else PR_RESPONSE=$(curl -s "$API_URL" 2>/dev/null || true) fi ``` Token use by comment submission: ```bash WORKSPACE_DIR="${OPENCLAW_WORKSPACE:-${HOME}/.openclaw/workspace}" TOKEN_FILE="$WORKSPACE_DIR/data/gitcode-token.txt" if [ ! -f "$TOKEN_FILE" ]; then echo "GitCode token does not exist: $TOKEN_FILE" exit 1 fi GITCODE_TOKEN=$(tr -d '\n' < "$TOKEN_FILE") ``` User-facing messages have been rendered in English; executable statements are unchanged. ### Technical Analysis The Skill requires a long-lived GitCode token to be stored in a plaintext file. The scripts verify only that the path exists as a file before reading it. They do not verify: - That the token file is owned by the current user. - That its mode prevents group or world access. - That parent directories are private. - That the path is not a symbolic link. - That the file has not been replaced between validation and reading. - That the token is narrowly scoped to only the required repositories and actions. The documentation identifies the storage path but does not require secure creation with mode `0600`. Depending on the user's umask and workspace permissions, the credential may be readable or replaceable by another local account. ### Attack Path 1. A user creates the token file with permissive default permissions, or the workspace data directory perm ...[truncated 1130 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Document secure token-file creation explicitly: ```bash install -d -m 700 "$HOME/.openclaw/workspace/data" install -m 600 /dev/null "$HOME/.openclaw/workspace/data/gitcode-token.txt" ``` 2. Before reading the token, verify that: - The path is a regular file. - The path is not a symbolic link. - The file is owned by the effective user. - Group and other permission bits are unset. 3. Reject insecure files rather than silently continuing. 4. Open and read the validated file in a manner that minimizes check-to-use races. 5. Use a dedicated GitCode token restricted to only the monitored repositories and required API actions. 6. Separate the read-only polling credential from the comment-writing credential. 7. Prefer an operating-system credential store or secret manager where supported. 8. Rotate the token periodically and immediately after suspected local exposure. 9. Ensure logs never include request headers, shell traces, or complete command lines containing the token. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding
The code clearly implements the AI review execution portion of the description: it accepts PR/repo parameters, constructs a review task, invokes the OpenClaw agent, references the GitCode API for PR files, and waits for a review report to be saved. However, the declared purpose claims broader end-to-end behavior: monitoring GitCode PRs, posting PR comments, and sending DingTalk/WeCom notifications. None of those capabilities appear in this script. There is no event polling or webhook handling, no API call to create PR comments, and no messaging integration for DingTalk or WeCom. Because the declared description presents these as core capabilities, while the supplied code chunk only performs report generation/logging, this is a material description-versus-behavior mismatch for the provided code chunk.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The code does implement part of the declared purpose: it monitors GitCode pull requests for a repository and supports parameterization by owner/repo. However, the declared description promises a broader automated workflow: running AI review through OpenClaw Gateway, posting PR comments, and sending DingTalk and WeCom notifications. None of those behaviors appear in this code chunk. Instead, the script only queries the GitCode API for open PRs, compares the latest PR ID against stored local state, logs results, and emits structured text when a new PR is found. This is a material underimplementation relative to the declared behavior, so the description does not accurately represent what this code chunk actually does.

Lp3

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding
The skill advertises and relies on shell-based automation but does not declare any explicit tool scope such as permissions or allowed-tools. In an agent environment, missing capability boundaries can cause the runtime to grant broader execution than reviewers or users expect, increasing the risk of unintended command execution against local files, tokens, cron configuration, and external services.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
Comments, logs, and the generated task prompt are written in Chinese, and the prompt implicitly fixes the review interaction format in that language. This is a natural-language locale constraint without any opt-in, alternative language handling, or documented region-specific justification.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The task instructs the agent to read a local GitCode token file, effectively granting the agent access to a reusable secret from the host environment. In an agent workflow, this expands the trust boundary: prompt injection in PR content, agent misuse, or unexpected tool behavior could lead to secret exposure or unauthorized API actions.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script records full agent output to a persistent log file, and that output is driven by a prompt containing PR metadata and a local credential file path. Because the agent is explicitly instructed to access a token file and may echo prompts, commands, file contents, or error traces, the logs can become a secondary disclosure channel for sensitive operational data and potentially credentials.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The script automatically sends PR metadata, review summaries, and report attachments to external DingTalk and WeCom targets. This creates a real data-exposure risk because repository names, PR titles, URLs, authors, and full review artifacts may contain proprietary code information or sensitive internal context, and the script provides no consent gate, classification check, or explicit disclosure before transmission.

Missing User Warnings

Medium
Confidence
83% confidence
Finding
The script automatically posts review output back to the PR via a comment submission helper without any approval step. This is risky because AI-generated content may leak sensitive analysis details, produce inaccurate findings, or create unintended actions in collaborative development workflows, and the automation is not clearly disclosed or gated here.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This shell script accesses a sensitive token from a local file and sends review content to a remote GitCode API via curl. Although it logs progress, the visible messages do not disclose that credentials are being used or that local review content will be transmitted off-host, which meets the missing-warning criteria for code files.

External Transmission

Medium
Category
Data Exfiltration
Content
API_URL="https://gitcode.com/api/v5/repos/${REPO_OWNER}/${REPO_NAME}/pulls/${PR_ID}/comments"

RESPONSE=$(curl -s -w "\n%{http_code}" \
  -H "PRIVATE-TOKEN: ${GITCODE_TOKEN}" \
  -H "Content-Type: application/json" \
  -X POST \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
User-facing strings throughout the script, including error messages, logs, and notification bodies, are written in Chinese only. This imposes a specific language/locale without any visible opt-in or configuration for alternative languages.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The script's descriptive comments and all user-visible status/error messages are written only in Chinese, which imposes a specific language choice without opt-in. Under the stated policy, fixed language behavior without offering user choice is a natural-language policy concern.

Static analysis

No suspicious patterns detected.