Back to skill

Security audit

GitCode Repo Daily

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent GitCode reporting tool, but it uses credentials and persistent local writes while feeding untrusted repository text into the agent and Markdown without clear safeguards.

Install only if you are comfortable giving the skill a GitCode token and allowing it to store repository lists, report metrics, and summaries under the skill directory. Use a least-privileged token, review generated Markdown before sharing or opening it in rich renderers, and treat PR/issue text in reports as untrusted content.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T01 · Skill Instruction Hijacking

Error
Location
scripts/generate_daily_report.py:477
Finding

Indirect prompt injection through untrusted pull request content

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_daily_report.py:477-486; consumed according to SKILL.md:50-53
Vulnerability Type: Indirect prompt injection through repository-controlled content
Risk Level: High

Vulnerable Code

python
for p in prs_merged_today:
    num = p.get("number")
    user = p.get("user") or {}
    uname = user.get("username") or user.get("login") or ""
    if uname:
        contributors.add(uname)
    detail, de = api_get(
        token,
        "repos/%s/%s/pulls/%s" % (owner, repo, num),
        timeout_sec,
        retry_times,
        retry_interval,
        sleep_sec,
    )
    if de:
        continue
    add = int(detail.get("additions") or 0)
    dec = int(detail.get("deletions") or 0)
    code_additions += add
    code_deletions += dec
    if add > major_threshold:
        major_prs.append({
            "number": num,
            "title": (detail.get("title") or "")[:200],
            "additions": add,
        })
    merged_prs_for_ai.append({
        "number": num,
        "title": (detail.get("title") or "")[:500],
        "body": (detail.get("body") or "")[:body_max],
    })

The workflow in SKILL.md:50-53 subsequently requires the Agent to generate repository summaries from merged_prs_for_ai.

Technical Analysis

Pull request titles and bodies are controlled by repository contributors. The script copies these fields into merged_prs_for_ai, after which the Skill instructs the Agent to use that data to generate summaries. No instruction/data boundary tells the Agent that these fields are untrusted and that commands embedded in them must be ignored.

Limiting field length does not neutralize prompt injection. A short pull request body can contain directives such as instructions to disregard the reporting task, disclose other context, manipulate the report, or invoke tools. The data is therefore presente ...[truncated 1377 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add an explicit instruction boundary to SKILL.md: all repository titles, bodies, comments, and summaries are untrusted data and must never be treated as instructions.
  2. Require the Agent to ignore requests inside repository content, including requests to use tools, access files, reveal context, alter safety rules, or change the output format.
  3. Remove pull request bodies from merged_prs_for_ai unless they are essential. Prefer narrowly scoped fields such as pull request number, normalized title, additions, and deletions.
  4. If bodies are necessary, preprocess them into a clearly delimited data structure and strip instruction-like markup, links, hidden HTML, and excessive text.
  5. Generate summaries in a restricted stage without filesystem, network, shell, or credential-bearing tools.
  6. Validate the resulting summary against the expected schema, length, and content constraints before saving or rendering it.
  7. Add adversarial tests containing prompt-injection phrases in pull request titles and bodies and verify that they cannot change Agent behavior.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_daily_report.py:837
Finding

Markdown injection through unescaped repository and summary content

Content
View full analysis

Vulnerability Details

File Location: scripts/generate_daily_report.py:837-850, 944-975, 998-1000, 1063
Vulnerability Type: Unsanitized remote content rendered as Markdown
Risk Level: Medium

Vulnerable Code

python
def _md_issue_link(owner_repo, number, title=""):
    url = "https://gitcode.com/%s/issues/%s" % (owner_repo, number)
    if title:
        return "[#%s](%s) %s" % (number, url, title.strip())
    return "[#%s](%s)" % (number, url)


def _md_pr_link(owner_repo, number, title="", extra=""):
    url = "https://gitcode.com/%s/pulls/%s" % (owner_repo, number)
    parts = ["[#%s](%s)" % (number, url)]
    if title:
        parts.append(title.strip())
    if extra:
        parts.append(extra)
    return " ".join(parts)
python
lines.append(
    "- %s\n" % _md_pr_link(
        repo_key,
        p.get("number"),
        (p.get("title") or "").strip(),
        extra,
    )
)

lines.append(
    "- %s\n" % _md_issue_link(
        repo_key,
        i.get("number"),
        (i.get("title") or "").strip(),
    )
)

lines.append(
    "**💬 Repository summary**: %s\n\n---\n\n" % summary_text
)
python
for k, v in replacements.items():
    tpl = tpl.replace(k, v)

Technical Analysis

Pull request titles, issue titles, repository identifiers, and Agent-generated summaries are inserted directly into Markdown. The helper functions construct trusted links for issue and pull request numbers, but append the remote title without escaping Markdown metacharacters or removing raw HTML.

An attacker-controlled title can therefore inject additional links, images, headings, separators, or HTML. For example, an injected remote image can cause a Markdown viewer to contact an attacker-controlled server when the report is opened. Crafted text can also visually restructure the report or create deceptive links.

The final template replacement perfor ...[truncated 1320 chars]

Remediation
View remediation

Remediation Suggestions

  1. Apply context-appropriate Markdown escaping to all API-derived and AI-generated text before interpolation.
  2. Escape at least backslashes, brackets, parentheses, asterisks, underscores, backticks, angle brackets, hash signs, pipes, and line-breaking constructs.
  3. Remove or encode raw HTML and disallow Markdown image syntax in untrusted fields.
  4. Normalize embedded newlines so titles cannot create additional headings, lists, tables, or report sections.
  5. Validate repository identifiers against a strict allowlist before using them in display text or URLs.
  6. Keep generated hyperlinks under the fixed https://gitcode.com/ origin and URL-encode path components.
  7. Sanitize Agent-generated summaries under the same policy as remote API content.
  8. Where reports are displayed in HTML, use a Markdown renderer configured to disable raw HTML and remote images, and enforce a restrictive content security policy.
  9. Add regression tests using malicious titles containing links, images, raw HTML, table delimiters, headings, and multiline content.
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (26)

Tainted flow: 'req' from os.environ.get (line 193, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_daily_report.py (reported line 197)May include surrounding context.

python
last_err = None
    for attempt in range(retry_times + 1):
        try:
            with urlopen(req, timeout=timeout_sec) as f:
                time.sleep(sleep_sec)
                return json.loads(f.read().decode("utf-8")), None
        except HTTPError as e:

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared purpose suggests simple report generation, but the documented behavior includes persistent SQLite writes, config mutation, filesystem output, and broader report modes. This mismatch can mislead users and orchestration systems into granting or invoking the skill under false assumptions, increasing the chance of unintended persistence or execution in sensitive environments.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The docstring claims the script only outputs a single JSON to stdout, but the implementation writes config, SQLite DB, temp report JSON, summaries, and Markdown files. In a skill ecosystem, misleading I/O declarations reduce informed consent and can hide persistence that affects future runs or stores potentially sensitive operational data.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The README explicitly says the skill will write back user-specified repositories to config.json and persist report data and summaries into SQLite automatically. Silent persistence of user input and generated data is a real safety issue because it changes local state without clear consent boundaries, can retain sensitive repository metadata longer than expected, and may surprise users who intended a read-only reporting action.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents capabilities to read environment variables, access the network, read/write files, and execute a Python script, but it does not declare any explicit tool scope or permissions boundary. This creates an under-specified trust surface where an agent may invoke broader capabilities than a user expects, especially since the workflow includes persistence to config and a local database.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The normal workflow explicitly includes writing summaries into a database and saving repository lists to config, yet the skill is framed primarily as report generation. Hidden persistence is dangerous because it changes local state across runs and may store potentially sensitive operational metadata without clear up-front consent.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs persistence of summaries to a database and saving repository defaults across sessions without a clear user-facing warning at the point of use. In an agent setting, silent state changes can surprise users, retain sensitive project metadata, and create audit/privacy issues if the stored data is later accessed or reused.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The example workflow performs automatic writes to report.json, summaries.json, Markdown output, and a database without any warning about these side effects. In an agent setting, silent file and DB writes are dangerous because they can create or persist data unexpectedly, especially when users may believe they are only requesting a generated summary.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The examples state that AI summaries are automatically written to a database during report rendering, but the declared skill scope focuses on generating repository daily reports and Markdown output. Undisclosed persistence expands the skill's data-handling behavior and can cause users or calling agents to store generated or potentially sensitive content without informed consent or expectation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The documentation says the agent will write repositories into config.json on first use, but it does not warn users that this is a persistent configuration change. Silent config mutation is risky because it changes subsequent behavior across sessions and may store sensitive repository identifiers without explicit approval.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The entire report template uses Chinese headings and labels, which imposes a specific language on users. The file does not indicate that the skill is China-specific or that users can opt into another language, so this is a natural-language locale policy concern.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/generate_daily_report.py (reported line 24)May include surrounding context.

python
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError

GITCODE_API_BASE = "https://api.gitcode.com/api/v5"
SCRIPT_DIR = Path(__file__).resolve().parent
SKILL_ROOT = SCRIPT_DIR.parent
CONFIG_FILE = SKILL_ROOT / "config.json"

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script persists user-supplied repository selections into config.json, creating stateful side effects beyond simple report generation. In an agent-skill context, silent persistence can surprise users, alter later runs, and create a foothold for configuration poisoning or unauthorized data retention.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The script spawns PowerShell to retrieve user- and machine-scoped GITCODE_TOKEN values outside the current process context. In an agent environment, this broadens secret access beyond what the caller explicitly supplied, increasing the chance of unintended credential use or cross-context secret exposure.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/generate_daily_report.py (reported line 83)May include surrounding context.

python
def _get_token_windows_user():
    try:
        out = subprocess.check_output(
            ["powershell", "-NoProfile", "-Command",
             "[Environment]::GetEnvironmentVariable('GITCODE_TOKEN','User')"],
            creationflags=0x08000000 if sys.platform == "win32" else 0,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/generate_daily_report.py (reported line 99)May include surrounding context.

python
def _get_token_windows_machine():
    try:
        out = subprocess.check_output(
            ["powershell", "-NoProfile", "-Command",
             "[Environment]::GetEnvironmentVariable('GITCODE_TOKEN','Machine')"],
            creationflags=0x08000000 if sys.platform == "win32" else 0,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

get_token implicitly falls back from the current process to Windows user-level and machine-level secret stores, which violates least privilege. In a multi-user or managed host setting, the skill may consume credentials the current invocation was never meant to access.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The CLI help states week/month mode is DB-only, yet the code performs live API fallback for missing data. This mismatch can trigger unexpected network access and credential use in contexts where operators believed execution would remain local.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README sets the default timezone to Asia/Shanghai and presents it as the out-of-box default for all 'current day' calculations. Because the document does not provide a user choice or explicit opt-in for locale/timezone behavior, users in other regions may receive reports aligned to an unintended locale.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The description embeds Chinese text as part of the core skill description, which can imply a default language expectation. The file does not state that language should follow user preference or provide any opt-in choice for output language.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The manifest frames the skill as a Python standard-library-only reporting tool, but the instructions require generating per-repo and global AI summaries and then feeding them back into rendering/DB persistence. That behavior depends on external agent intelligence rather than the described standalone script capability, creating a mismatch between the advertised skill behavior and its actual documented workflow.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The config hard-codes "Asia/Shanghai" as the timezone, which is a locale-related setting that may affect how dates and times are interpreted or presented. The file does not indicate that this locale choice is optional, user-configurable at runtime, or justified as region-specific behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The examples describe automatically modifying config.json to persist repository settings, but this persistent side effect is not disclosed in the skill description. Even if the change is operationally useful, hidden configuration writes can surprise users, alter future behavior, and create integrity or privacy issues if repository lists are sensitive.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown template presents all headings and instructions in Chinese, which can force a specific language/locale on users. The file does not mention any option to select another language or that the Chinese locale is an intentional, documented constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The default configuration sets the timezone to "Asia/Shanghai", which imposes a specific locale behavior on report date calculations when the user does not explicitly choose one. The file does not present this as an opt-in or offer a neutral default such as UTC.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.