Back to skill

Security audit

GitLab MR Code Review

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed GitLab review automation, but its default cron workflow gives an unattended agent broad GitLab posting authority and lets merge-request branch content influence review instructions.

Review carefully before installing. Use a narrowly scoped project or group token, restrict the worker to explicit projects, require HTTPS and a trusted GitLab host, do not load prompt or policy text from untrusted MR branches as agent instructions, and test manually or in dry-run style before enabling the recurring cron worker.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • 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 (4)

T01 · Skill Instruction Hijacking

Error
Location
references/cron-setup.md:12
Finding

Untrusted Merge Request Content Is Loaded as Agent Instructions

Content
View full analysis
b. Read review rules: {baseDir}/references/review-guidelines.md c. Check for custom rules: node {baseDir}/scripts/gitlab-api.js get-file .gitlab-review-prompt.md d. Review each file, skip lock/min/generated files e. For each issue, write JSON to a temp file first, then post inline comment via --file: node {baseDir}/scripts/gitlab-api.js post-comment --file /tmp/comment-N.json IMPORTANT: Never pass JSON directly on the command line! Always use the write tool to create a file, then pass it via --file. f. Post summary note: node {baseDir}/scripts/gitlab-api.js post-note ' g. ⚠️ CRITICAL: Immediately after posting the summary note for this MR, use the read tool to read {baseDir}/mr-reviewed.json, append this MR's record, then use the write tool to write the full file back. You MUST write back after EACH MR — never batch writes after reviewing all MRs. If the file doesn't exist, create it as an empty JSON object first. 4. Process all unreviewed MRs in this run. If no new MRs, reply NO_REPLY. 5. Do not ask for permission — execute directly." ``` The behavior is also declared in `SKILL.md:64-66`: ```markdown ## Review Rules - **Default**: [references/review-guidelines.md](references/review-guidelines.md) — severity levels, output form ...[truncated 2614 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/gitlab-api.js:42
Finding

GitLab Token Can Be Transmitted over Plaintext or to an Untrusted Host

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/gitlab-api.js:78
Finding

Default Worker Scope Includes Every Project Accessible to the Token

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/cron-setup.md:19
Finding

Predictable Shared Temporary Files Permit Payload Tampering and Symlink Attacks

Content
View full analysis
IMPORTANT: Never pass JSON directly on the command line! Always use the write tool to create a file, then pass it via --file. ``` The same predictable naming requirement is repeated at `references/cron-setup.md:36-41`: ```markdown All `post-comment` calls **must** use `--file` mode. Shell encoding may corrupt inline JSON (especially CJK or special chars). Always: 1. `write` the JSON payload to a temp file 2. Pass the file path via `--file` ``` The script consumes the file without validating its ownership or type at `scripts/gitlab-api.js:190-193`: ```javascript "post-comment": () => { if (args[0] === '--file') { const payload = fs.readFileSync(args[1], 'utf8'); return postComment(args[2], args[3], payload); } ``` ### Technical Analysis The prescribed path `/tmp/comment-N.json` is predictable and located in a shared temporary directory. The instructions do not require exclusive file creation, restrictive permissions, ownership validation, symlink protection, or cleanup. A local attacker can pre-create the expected file or replace it between the worker's write and read operations. Depending on the semantics of the agent's write tool, a pre-created symbolic link may redirect the write to another filesystem location writable by the worker. A race condition can also allow an attacker to replace the completed payload before `readFileSync()` consumes it. Because the payload controls the GitLab comment body and position data, local tampering can cause unauthorized content to be posted using the worker's token. ### Attack Path 1. A local attacker predicts that the worker ...[truncated 1182 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (7)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/gitlab-api.js (reported line 14)May include surrounding context.

js
*   node gitlab-api.js post-note <project_id> <mr_iid> '<text>'
 *
 * Env: GITLAB_URL, GITLAB_TOKEN
 *       These can be set in the OS environment or in {baseDir}/.env
 */

// Load .env from the skill base directory (one level up from scripts/)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/gitlab-api.js (reported line 17)May include surrounding context.

js
*   node gitlab-api.js post-note <project_id> <mr_iid> '<text>'
 *
 * Env: GITLAB_URL, GITLAB_TOKEN
 *       These can be set in the OS environment or in {baseDir}/.env
 */

// Load .env from the skill base directory (one level up from scripts/)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/gitlab-api.js (reported line 20)May include surrounding context.

js
// Load .env from the skill base directory (one level up from scripts/)
const path = require("path");
const fs = require("fs");
const envPath = path.resolve(__dirname, "..", ".env");
if (fs.existsSync(envPath)) {
  for (const line of fs.readFileSync(envPath, "utf8").split("\n")) {
    const trimmed = line.trim();

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The skill requires environment access to a GitLab token and performs network operations against GitLab, but it does not declare any explicit tool scope such as allowed-tools or permissions. That creates an overbroad trust boundary where an agent may invoke capabilities not clearly constrained by the skill contract, increasing the risk of unintended secret access or outbound requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The setup instructions tell users to place a GitLab personal access token in a local .env file but provide no warning about credential sensitivity, least-privilege scoping, file permissions, or avoiding commits of that file. In a polling automation skill that continuously accesses GitLab, mishandling this token could expose repository contents and allow unauthorized comments or other API actions depending on token scope.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The cron setup explicitly instructs an automated worker to post comments to GitLab and update a local state file, but the documentation does not prominently warn that enabling it causes unattended writes to external systems and persistent local state changes. In a polling automation context, this can lead to unexpected side effects such as spammy MR comments, accidental writes against the wrong project, or silent state corruption if users deploy it without understanding the write behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This markdown guidance includes Chinese-only instructional text and a Chinese comment body template, which effectively imposes a specific language for reviewer output. The file does not offer a language choice or justify the locale requirement, so it conflicts with the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/gitlab-api.js:29