Back to skill

Security audit

GitLab Agent Profile

Security checks for vulnerabilities and agentic risk

Overview

The skill largely matches its GitLab profile-statistics purpose, but it uses broad GitLab access, can publish generated assets, adds a persistent scheduled run configuration, and has an under-disclosed npm execution fallback.

Install only if you intend an agent to use your GitLab token to scan the configured group, include private/internal contribution totals in public-facing outputs, and potentially commit and push generated assets. Prefer an explicit project list, a least-privilege token, review before push, and preinstalled pinned image conversion tooling instead of the npm fallback.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The declared description understates the actual behavior: the skill performs broad GitLab API collection across projects, processes sensitive MR/commit/reviewer metadata, includes private/internal activity in aggregated outputs, and generates a records JSON artifact in addition to charts. This mismatch can mislead users into authorizing a seemingly simple profile-maintenance task that actually performs organization-wide data access and publication-related processing.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares no explicit tool scope even though it clearly requires environment access, filesystem reads/writes, network access, and shell execution via `glab` and `python3`. In a capability-driven agent system, missing scope declarations weaken least-privilege controls and can cause the skill to run with broader access than reviewers or operators expect.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The routine instructs the agent to commit and push changed assets, which modifies and publishes repository contents, but it does not require an explicit confirmation step or warning to the user. In an automated or scheduled context, this increases the risk of unintended publication of incorrect, sensitive, or privacy-impacting derived data.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def glab_json(path: str) -> object:
    try:
        result = subprocess.run(
            ["glab", "api", path],
            check=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def current_user() -> str:
    result = subprocess.run(
        [
            "glab",
            "api",
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The script's stated job is maintaining a GitLab profile chart, but it extends its trust boundary by invoking ImageMagick, `convert`, or `npm exec --yes sharp-cli` to render WebP output. In an agent or CI environment, unnecessary external executable use broadens the attack surface and, in the npm case, can introduce network-based supply-chain execution.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
webp_output.parent.mkdir(parents=True, exist_ok=True)
    magick = shutil.which("magick")
    if magick:
        subprocess.run([magick, str(svg_output), str(webp_output)], check=True)
        return
    convert = shutil.which("convert")
    if convert:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'webp_output' from os.environ.get (line 429, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
webp_output.parent.mkdir(parents=True, exist_ok=True)
    magick = shutil.which("magick")
    if magick:
        subprocess.run([magick, str(svg_output), str(webp_output)], check=True)
        return
    convert = shutil.which("convert")
    if convert:
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return
    convert = shutil.which("convert")
    if convert:
        subprocess.run([convert, str(svg_output), str(webp_output)], check=True)
        return
    npm = shutil.which("npm")
    if npm:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'webp_output' from os.environ.get (line 429, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
return
    convert = shutil.which("convert")
    if convert:
        subprocess.run([convert, str(svg_output), str(webp_output)], check=True)
        return
    npm = shutil.which("npm")
    if npm:
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
return
    npm = shutil.which("npm")
    if npm:
        subprocess.run(
            [
                npm,
                "exec",
Confidence
73% confidence
Finding
This branch executes `npm exec --yes sharp-cli`, which can download and run package-managed tooling at runtime if not already present. In a CI or agent context, that increases supply-chain exposure and allows unpinned external code execution beyond the script's core GitLab data collection purpose.

Tainted flow: 'webp_output' from os.environ.get (line 429, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
return
    npm = shutil.which("npm")
    if npm:
        subprocess.run(
            [
                npm,
                "exec",
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/test_profile_stats.py:20