Back to skill

Security audit

GitLab 每日提交汇总

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate reporting purpose, but it handles private GitLab data unsafely and can send reports to webhooks without the confirmation flow it promises.

Review before installing. Use only a narrowly scoped read-only GitLab token, keep config.json out of version control, verify webhook destinations, and avoid running the script without --preview unless you intend to send private repository activity to Feishu. Do not use this on untrusted networks unless TLS verification is fixed.

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/gitlab_report.py:24
Finding

TLS certificate validation is globally disabled for authenticated network requests

Content
View full analysis

Vulnerability Details

File Location: scripts/gitlab_report.py, lines 24–27, 41–48, and 578–586
Vulnerability Type: Improper certificate validation
Risk Level: High

Vulnerable Code

python
_SSL_CTX = ssl.create_default_context()
_SSL_CTX.check_hostname = False
_SSL_CTX.verify_mode = ssl.CERT_NONE
python
def gitlab_get(config, path, max_retries=2):
    url = f"{config['gitlab_url'].rstrip('/')}/api/v4{path}"
    req = urllib.request.Request(
        url,
        headers={"PRIVATE-TOKEN": config["gitlab_token"]}
    )

    for attempt in range(max_retries):
        try:
            with urllib.request.urlopen(
                req,
                timeout=20,
                context=_SSL_CTX
            ) as resp:
                return json.loads(resp.read().decode())
python
def send_feishu(webhook_url: str, message: Dict):
    data = json.dumps(message).encode("utf-8")
    req = urllib.request.Request(
        webhook_url,
        data=data,
        headers={"Content-Type": "application/json"},
        method="POST"
    )
    try:
        with urllib.request.urlopen(
            req,
            timeout=15,
            context=_SSL_CTX
        ) as resp:
            result = json.loads(resp.read().decode())

Technical Analysis

The shared SSL context disables both certificate-chain verification and hostname validation. It is used for authenticated GitLab API requests and outbound webhook requests.

HTTPS only provides endpoint authentication when the client verifies that the certificate was issued by a trusted authority and belongs to the requested hostname. With CERT_NONE and hostname checking disabled, the script accepts any certificate presented by a remote endpoint.

The GitLab Personal Access Token is placed in the PRIVATE-TOKEN request header. A network attacker capable of intercepting traffic can impersonate the co ...[truncated 1925 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove the globally insecure SSL context:

    python
    _SSL_CTX = ssl.create_default_context()
    

    Do not alter check_hostname or verify_mode.

  2. For private GitLab deployments using an internal certificate authority, support an explicit CA bundle:

    python
    ca_file = config.get("ca_bundle")
    ssl_context = ssl.create_default_context(cafile=ca_file)
    
  3. Do not provide a configuration option that disables certificate validation. If an exceptional development-only override is unavoidable, it must be disabled by default, produce a prominent warning, and never be permitted in production.

  4. Require HTTPS for GitLab and webhook URLs.

  5. Rotate any GitLab token that may previously have been transmitted over an intercepted or untrusted network.

  6. Use a narrowly scoped project or group access token with only the read permissions required by the report.

  7. Add automated tests that verify invalid, expired, self-signed, and hostname-mismatched certificates are rejected.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gitlab_report.py:694
Finding

Private repository report data is transmitted by default to insufficiently validated webhook destinations

Content
View full analysis

Vulnerability Details

File Location: scripts/gitlab_report.py, lines 599–602 and 694–704
Vulnerability Type: Unsafe default network transmission and insufficient destination validation
Risk Level: Medium

Vulnerable Code

python
parser.add_argument(
    "--style",
    choices=["concise", "detailed", "executive"],
    default="detailed"
)
parser.add_argument("--preview", action="store_true")
parser.add_argument("--raw", action="store_true")
python
if not args.preview:
    for repo_data in all_data:
        message = format_feishu_message(
            repo_data,
            date_label,
            args.style
        )

        for webhook in config["feishu_webhooks"]:
            if webhook.startswith("http"):
                success, msg = send_feishu(webhook, message)
                if success:
                    print(f"  OK: {repo_data['project_name']}: {msg}")
                else:
                    print(f"  ERROR: {repo_data['project_name']}: {msg}")

Technical Analysis

The transmission model is opt-out rather than opt-in. Because store_true arguments default to False, running the script without --preview enters the sending branch. This conflicts with the Skill's declared consent rule that report delivery should occur only after explicit user confirmation.

Destination validation only checks whether the string starts with http. This accepts:

  • Plaintext http:// destinations.
  • Arbitrary Internet domains.
  • Attacker-controlled collection servers.
  • Internal network endpoints accessible from the host.
  • URLs containing misleading hostname text outside the actual authority component.

Sending repository reports to Feishu is necessary only when explicitly requested. Automatic transmission to every configured webhook exceeds the minimum privilege and disclosure scope needed for previewing or generating a report.

Attack Path

...[truncated 1365 chars]

Remediation
View remediation

Remediation Suggestions

  1. Make local preview the default behavior.

  2. Require an explicit send option:

    python
    parser.add_argument(
        "--send",
        action="store_true",
        help="Explicitly send reports to approved webhook destinations"
    )
    
    if args.send:
        # Perform transmission.
    
  3. Reject conflicting or ambiguous options and require user confirmation before sending when running interactively.

  4. Parse destinations with urllib.parse.urlsplit and require:

    • Scheme exactly equal to https.
    • A non-empty hostname.
    • An approved hostname such as open.feishu.cn.
    • The expected Feishu webhook path prefix.
    • No embedded username or password.
  5. If custom webhook services are a required feature, maintain an explicit destination allowlist and require separate administrative approval.

  6. Display destination hostnames and the categories of data to be transmitted before confirmation without printing webhook secrets.

  7. Add tests proving that:

    • Running without --send never performs a POST.
    • Plain HTTP is rejected.
    • Unapproved domains are rejected.
    • Multiple webhooks require explicit authorization.

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:12
Finding

Documented consent workflow and data-handling commands are not implemented

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 12–15, 57–60, and 101–106; scripts/gitlab_report.py, lines 599–602 and 652–690
Vulnerability Type: Security-relevant documentation and implementation mismatch
Risk Level: Medium

Vulnerable Documentation and Code

The declared preview workflow is:

bash
python gitlab_report.py --preview

The documentation states that this operation saves report data to:

text
latest_data.json

The declared delivery workflow uses:

bash
python gitlab_report.py --send-ai-summary

However, the implemented arguments are limited to:

python
parser.add_argument(
    "--style",
    choices=["concise", "detailed", "executive"],
    default="detailed"
)
parser.add_argument("--preview", action="store_true")
parser.add_argument("--raw", action="store_true")

Raw report data is only printed to standard output:

python
if args.raw:
    raw_output = {
        "date": date_label,
        "summary": {
            "total_commits": total_commits,
            "active_members": len(total_members),
            "repositories": [
                d["project_name"] for d in all_data
            ]
        },
        "projects": []
    }

    for repo_data in all_data:
        proj = {
            "name": repo_data["project_name"],
            "commits": {
                "total": repo_data["commits_analysis"]["total"],
                "by_category": repo_data["commits_analysis"]["by_category"],
                "by_author": repo_data["commits_analysis"]["by_author"],
                "active_members": list(
                    repo_data["commits_analysis"]["authors"]
                )
            }
        }
        raw_output["projects"].append(proj)

    print(json.dumps(raw_output, ensure_ascii=False, indent=2))

Technical Analysis

The documented --send-ai-summary option does ...[truncated 1946 chars]

Remediation
View remediation

Remediation Suggestions

  1. Align the implementation with the documented two-step workflow.

  2. Implement explicit local output:

    python
    parser.add_argument(
        "--output",
        default="latest_data.json"
    )
    

    Write the JSON using restrictive permissions and an atomic replacement operation.

  3. Implement an explicit summary-delivery interface, for example:

    python
    parser.add_argument(
        "--send-ai-summary",
        metavar="FILE"
    )
    

    Validate file size and structure before sending.

  4. Require a separate --send option or interactive confirmation even when a summary file is supplied.

  5. If persistence is unnecessary, remove all claims that latest_data.json is created and document the actual standard-output workflow.

  6. Ensure latest_data.json, config.json, and generated summary files are excluded from version control and created with owner-only permissions because they may contain private repository metadata.

  7. Add integration tests covering the exact commands shown in SKILL.md, including assertions that preview mode performs no webhook requests and that send mode transmits only the reviewed summary.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (15)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/README.md (reported line 30)May include surrounding context.

md
| 字段 | 说明 |
|------|------|
| `gitlab_url` | 私有 GitLab 地址,如 `https://gitlab.yourcompany.com` |
| `gitlab_token` | Personal Access Token,需要 `read_api` 权限。在 GitLab → 头像 → Preferences → Access Tokens 中创建 |
| `repositories` | 要监控的仓库列表,格式为 `"命名空间/仓库名"`,例如 `"team/backend"` |
| `feishu_webhooks` | 飞书群机器人 Webhook 地址列表(可配多个群) |
| `timezone_offset` | 时区偏移,默认 `8`(北京时间) |

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/README.md (reported line 30)May include surrounding context.

md
| 字段 | 说明 |
|------|------|
| `gitlab_url` | 私有 GitLab 地址,如 `https://gitlab.yourcompany.com` |
| `gitlab_token` | Personal Access Token,需要 `read_api` 权限。在 GitLab → 头像 → Preferences → Access Tokens 中创建 |
| `repositories` | 要监控的仓库列表,格式为 `"命名空间/仓库名"`,例如 `"team/backend"` |
| `feishu_webhooks` | 飞书群机器人 Webhook 地址列表(可配多个群) |
| `timezone_offset` | 时区偏移,默认 `8`(北京时间) |

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_report.py (reported line 354)May include surrounding context.

python
def check_risks(commits: List[Dict]) -> List[str]:
    """检查高风险代码变动"""
    risks = []
    sensitive_patterns = [r"\.env", r"sql/", r"security/", r"config/credentials", r"\.key$", r"password"]
    
    for c in commits:
        # 检查敏感文件

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill directs the agent to automatically run python gitlab_report.py --preview, which performs network access to GitLab and writes retrieved data to latest_data.json, without an explicit consent, warning, or prerequisite check. In an agent setting, this can cause unintended external access and local persistence of potentially sensitive repository activity data, especially because the workflow says it requires no user intervention.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill explicitly targets private GitLab repositories and pushes summarized repository activity to Feishu webhooks, but it does not warn users that commit messages, issue titles, MR metadata, and pipeline status may contain sensitive internal information. This creates a real risk of unintended data disclosure to third-party messaging infrastructure or overly broad chat audiences.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The configuration section instructs users to place a GitLab access token and Feishu webhook URLs into config.json without guidance on secure storage, file permissions, rotation, or secret handling. In a skill that integrates private source-control data with external webhooks, omission of basic credential-handling warnings materially increases the chance of token leakage and unauthorized outbound data transmission.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
79% confidence
Finding

The configuration section states the Personal Access Token needs only read_api permission, which frames the tool as a read-only reporting workflow. Later, the README's example webhook handler executes git pull, introducing code-modifying/update behavior on the host that is not consistent with that read-only framing.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The function uses a PRIVATE-TOKEN header from configuration to query the GitLab API and retrieve repository data. Although network access is inherent to the tool's purpose, this file does not clearly disclose that it reads a GitLab token and transmits it to a remote server as part of operation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The inline comments describe checking sensitive file changes and large deletions, but the implementation only reads commit metadata and commit titles, then never appends anything to the risks list. This is an active contradiction between the documented intent of the function and its real behavior, which means downstream users may believe risk detection is happening when it is effectively a no-op.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Raw-output mode prints structured repository activity data for downstream AI analysis, including commit categories, author activity, MR blocking details, and pipeline failures. In shared terminals, CI logs, or agent pipelines, this can disclose sensitive internal project metadata to unintended viewers or external log collectors.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script sends repository-derived activity data, including commit titles, authors, MR details, and pipeline status, to arbitrary Feishu webhooks from configuration with no consent prompt, allowlist, or data-minimization control at send time. In a security-sensitive environment, this can cause unintended exfiltration of internal engineering metadata to external systems, especially if webhook destinations are misconfigured or attacker-controlled.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language instructions and required interaction phrases are entirely in Chinese, which implicitly forces a specific language for use of the skill. The file does not offer the user an alternative language or explain that the skill is intentionally limited to a Chinese-speaking environment.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

All user-facing instructions, headings, examples, and output text are presented exclusively in Chinese, with no indication that another language is supported or that the language choice is optional. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation unless clearly justified.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The example config sets timezone_offset to 8, which implicitly enforces a specific timezone/locale context. Because this is a natural-language/config policy concern applicable to all file types, it should either be presented as user-selectable or documented as a justified regional requirement.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

Natural-language strings throughout the script, including the generated Feishu payload under the zh_cn locale key, are fixed in Chinese. There is no option for users to select another language or explicitly opt into the locale, which conflicts with the language-choice policy described in the audit rules.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.