Back to skill

Security audit

project-init

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do the advertised Gitea repository setup, but it handles powerful repository credentials and shared workflow state in ways that need review before installation.

Review this before installing, especially for production or shared Gitea organizations. Require HTTPS, use a minimally scoped and rotated bot token, mask token entry, avoid system-wide dependency installation, validate usernames and helper paths, and replace the shared temp state with per-user or per-session protected state.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/init_repo.py:45
Finding

Gitea access token transmitted over unencrypted HTTP

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Unpinned dependencies are installed into the system Python environment

Content
View full analysis
=2.28.0 python-dotenv>=1.0.0 ``` ```bash pip3 install -r "$SKILL_DIR/requirements.txt" --break-system-packages -q ``` ### Technical Analysis The dependency specifications set only minimum versions and have no upper bounds, exact pins, or package hashes. A setup run can therefore install a future release that was never reviewed with this Skill. The use of `--break-system-packages` bypasses protections intended to prevent `pip` from modifying an externally managed Python installation. Dependencies are installed into the host interpreter rather than a Skill-specific virtual environment. This increases both supply-chain exposure and the blast radius of dependency conflicts. No typosquatted package was identified in the current requirements. The risk arises from mutable dependency resolution and unsafe installation scope, rather than evidence that the named packages are presently malicious. ### Attack Path 1. A dependency account, package release process, or configured package index is compromised, or an unsafe future release is published. 2. A user runs `setup.sh`. 3. `pip` resolves the newest versions satisfying the open-ended `>=` constraints. 4. Installation-time package code or subsequently imported malicious code executes with the privileges of the user running setup or the Skill. 5. Because installation targets the system interpreter, the compromised or incompatible package may also affect unrelated Python applications on the host. ### Impact Assessment Malicious dependency code can access files, environment variables, the configured Gitea token, network resources, and any other resources available to the setup or Skill process. If setup is run with elevated privileges, the impact may extend to s ...[truncated 243 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
main.js:19
Finding

Predictable shared temporary state enables cross-session interference and symlink attacks

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
setup.sh:51
Finding

Personal Access Token is collected with terminal echo enabled

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
main.js:125
Finding

Unvalidated usernames are interpolated into API and repository paths

Content
View full analysis
s.trim()) .filter(Boolean); state.data.members = members.filter( m => m !== state.data.creator ); } else { state.data.members = []; } } ``` The values are then inserted directly into URL and repository path components: ```python def get_user_email(username: str) -> str | None: resp = api_get(f'/users/{username}') if resp.status_code == 200: return resp.json().get('email') return None def add_collaborator(repo_name: str, username: str, permission: str): resp = api_put( f'/repos/{GITEA_ORG}/{repo_name}/collaborators/{username}', {'permission': permission} ) for username in all_members: profile_content = make_profile(username, now) files_to_write.append(( f'profiles/{username}.md', profile_content, f'docs: add {username} member profile', )) ``` ### Technical Analysis Repository names receive a restrictive validation check, but creator and member usernames do not. Arbitrary non-empty creator input is accepted, while member input is only split on commas or whitespace. The values are used as: - Gitea API URL path segments; - repository content path components; - Markdown content and mentions; - generated filenames; - issue assignees; - email lookup identifiers. Shell command injecti ...[truncated 1859 chars]
Remediation
View remediation
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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (37)

Tainted flow: 'GITEA_URL' from os.environ.get (line 49, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
96% confidence
Finding

GITEA_URL is loaded from environment or .env and used directly as the destination for authenticated HTTP requests. Because the Authorization token is sent in headers, a malicious or misconfigured GITEA_URL can exfiltrate the Gitea token and all repository metadata to an attacker-controlled server; the default also uses plain HTTP, making interception easier.

Content

Scanner excerpt · scripts/init_repo.py (reported line 66)May include surrounding context.

python
}

def api_get(path):
    return requests.get(f'{GITEA_URL}/api/v1{path}', headers=_headers(), timeout=15)

def api_post(path, data):
    return requests.post(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

Tainted flow: 'GITEA_URL' from os.environ.get (line 49, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
96% confidence
Finding

The script posts repository creation, file contents, and issue data to a base URL fully controlled by environment configuration. If GITEA_URL is altered, sensitive data including the Gitea token, repository names, descriptions, usernames, and generated file contents can be transmitted to an attacker-controlled endpoint.

Content

Scanner excerpt · scripts/init_repo.py (reported line 69)May include surrounding context.

python
return requests.get(f'{GITEA_URL}/api/v1{path}', headers=_headers(), timeout=15)

def api_post(path, data):
    return requests.post(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

def api_put(path, data):
    return requests.put(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

Tainted flow: 'GITEA_URL' from os.environ.get (line 49, credential/environment) → requests.put (network output)

Critical
Category
Data Flow
Confidence
96% confidence
Finding

PUT requests for collaborator management are sent to a URL built from untrusted environment configuration while carrying the same Authorization token. This can leak credentials and enable unauthorized privilege-management requests against unintended services if the endpoint is malicious or compromised.

Content

Scanner excerpt · scripts/init_repo.py (reported line 72)May include surrounding context.

python
return requests.post(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

def api_put(path, data):
    return requests.put(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

# ── 邮件发送(调用 imap-smtp-email Skill)────────────────────

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

A second, broader description-behavior mismatch exists: the skill promises a full interactive workflow and multiple external side effects, but the available file does not implement or prove any of them, while static analysis indicates other setup or dependency actions may occur instead. This creates a supply-chain style trust problem where the manifest can socially engineer approval for behavior that is absent, incomplete, or materially different in the real code path.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A second, broader description-behavior mismatch exists: the skill promises a full interactive workflow and multiple external side effects, but the available file does not implement or prove any of them, while static analysis indicates other setup or dependency actions may occur instead. This creates a supply-chain style trust problem where the manifest can socially engineer approval for behavior that is absent, incomplete, or materially different in the real code path.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill description does not prominently warn that it will create repositories, modify access control, generate files, create issues, and send emails. Lack of clear disclosure undermines informed consent and increases the risk that a user triggers irreversible or organization-wide changes without realizing the consequences.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 54)May include surrounding context.

md
| 变量 | 说明 |
|------|------|
| `GITEA_URL` | Gitea 服务器地址 |
| `GITEA_TOKEN` | AIFusionBot 的 Personal Access Token |
| `GITEA_ORG` | 操作的 Gitea 组织名 |
| `EMAIL_SKILL_PATH` | imap-smtp-email Skill 的绝对路径 |
| `EMAIL_ACCOUNT` | 发件邮箱账号名称(留空使用默认账号) |

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 · env-example.txt (reported line 3)May include surrounding context.

text
# =============================================
# project-init Skill 环境变量配置示例
# 复制本文件内容到 ~/.config/project-init/.env
# =============================================

# Gitea 服务器地址

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 · env-example.txt (reported line 20)May include surrounding context.

text
# =============================================
# project-init Skill 环境变量配置示例
# 复制本文件内容到 ~/.config/project-init/.env
# =============================================

# Gitea 服务器地址

Credential Access

High
Category
Privilege Escalation
Confidence
75% confidence
Finding

The example explicitly instructs operators to provision a long-lived Gitea Personal Access Token for automation, which creates a sensitive credential dependency for a repository-management skill. In this context, the skill can create repositories, assign admin/read roles, open issues, and trigger notifications, so compromise of the token could enable broad unauthorized actions across the organization.

Content

Scanner excerpt · env-example.txt (reported line 9)May include surrounding context.

text
# Gitea 服务器地址
GITEA_URL=http://43.156.243.152:3000

# AIFusionBot 的 Personal Access Token
# 获取方式:登录 Gitea → 用户设置 → 应用 → 生成令牌
GITEA_TOKEN=your_token_here

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/init_repo.py (reported line 41)May include surrounding context.

python
# ── 加载配置 ──────────────────────────────────────────────────
SKILL_DIR = Path(__file__).parent.parent
CONFIG_PATH = Path.home() / '.config' / 'project-init' / '.env'
FALLBACK_ENV = SKILL_DIR / '.env'

if CONFIG_PATH.exists():

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

Falling back to a .env file inside the skill directory increases the chance that secrets are bundled with the skill, exposed to other users, or accidentally committed to source control. In the context of an agent skill distributed as files, this makes credential exposure materially more dangerous than a private per-user config path.

Content

Scanner excerpt · scripts/init_repo.py (reported line 42)May include surrounding context.

python
# ── 加载配置 ──────────────────────────────────────────────────
SKILL_DIR = Path(__file__).parent.parent
CONFIG_PATH = Path.home() / '.config' / 'project-init' / '.env'
FALLBACK_ENV = SKILL_DIR / '.env'

if CONFIG_PATH.exists():
    load_dotenv(CONFIG_PATH)

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 · setup.sh (reported line 10)May include surrounding context.

sh
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_DIR="$HOME/.config/project-init"
ENV_FILE="$CONFIG_DIR/.env"

echo "========================================"
echo "  project-init Skill 初始化配置"

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The script requests a Gitea Personal Access Token directly from the user without masking input, so the token may be visible on-screen or captured in terminal recordings and shoulder-surfing scenarios. Because the token can grant repository and organization access, disclosure could enable unauthorized repo creation, modification, or data access within the configured Gitea environment.

Content

Scanner excerpt · setup.sh (reported line 53)May include surrounding context.

sh
read -p "Gitea 服务器地址 (默认: http://43.156.243.152:3000): " GITEA_URL
GITEA_URL="${GITEA_URL:-http://43.156.243.152:3000}"

read -p "AIFusionBot Personal Access Token: " GITEA_TOKEN
if [ -z "$GITEA_TOKEN" ]; then
    echo "❌ Token 不能为空"
    exit 1

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill advertises actions that inherently require powerful capabilities (reading environment variables, filesystem access, network access, and likely shell execution) but does not declare any explicit tool scope or permission boundaries. This increases the chance of over-privileged execution and makes it harder to audit what the skill is allowed to do, especially because it can create repositories, assign roles, and send notifications.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrase is broad enough to match ordinary conversation, which can cause accidental activation of a skill that performs high-impact actions like creating repositories and assigning permissions. In this context, unintended invocation is more dangerous than usual because the skill affects shared infrastructure and may send notifications to other users.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The natural-language description is entirely in Chinese and presents the skill as operating in that language context without any indication that users can choose another language or locale. The audit rule flags language or locale policy violations when a skill appears to force a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The comments and setup instructions are written entirely in Chinese, which imposes a specific language on users. Under the policy, language constraints should either be optional for the user or clearly justified as region-specific; this file provides neither.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill's user-facing prompts, confirmations, and status messages are written exclusively in Chinese, and the debug interface also expects Chinese interaction. There is no indication that users can opt into another language or locale, which is a natural-language policy concern when no language constraint is documented.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Line L226 tells the user that an error-details email has been sent, but in this file the failure path only returns a formatted error message after the Python script exits unsuccessfully. There is no code here that sends an email or checks script output for successful error-notification delivery, so the user-facing text actively overstates what the code can substantiate.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This Python file's top-level docstring, CLI description, status/error messages, and email content are written exclusively in Chinese, which imposes a language choice on users without opt-in. Under the policy, language constraints should either be optional or clearly justified as region-specific; neither is stated here.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/init_repo.py (reported line 69)May include surrounding context.

python
return requests.get(f'{GITEA_URL}/api/v1{path}', headers=_headers(), timeout=15)

def api_post(path, data):
    return requests.post(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

def api_put(path, data):
    return requests.put(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

External Transmission

Medium
Category
Data Exfiltration
Confidence
80% 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/init_repo.py (reported line 72)May include surrounding context.

python
return requests.post(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

def api_put(path, data):
    return requests.put(f'{GITEA_URL}/api/v1{path}', json=data, headers=_headers(), timeout=15)

# ── 邮件发送(调用 imap-smtp-email Skill)────────────────────

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
87% confidence
Finding

The script executes an external Node.js program whose path and optional account argument are derived from environment-controlled configuration. Although subprocess.run is used without shell=True, this still trusts EMAIL_SKILL_PATH and EMAIL_ACCOUNT from .env files, so a tampered configuration can redirect execution to attacker-controlled code and cause arbitrary code execution in the context of the skill.

Content

Scanner excerpt · scripts/init_repo.py (reported line 92)May include surrounding context.

python
cmd = ['node', str(smtp_script), '--account', EMAIL_ACCOUNT,
               'send', '--to', to, '--subject', subject, '--body', body]

    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    if result.returncode != 0:
        print(f'[WARN] 邮件发送失败: {result.stderr}', file=sys.stderr)
    return result.returncode == 0

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

Medium
Category
Data Flow
Confidence
85% confidence
Finding

The command arguments passed to subprocess.run include EMAIL_ACCOUNT from environment-controlled configuration and the script path derived from EMAIL_SKILL_PATH. Even without shell expansion, this still creates a code-execution trust boundary: an attacker who can modify configuration can influence which program runs or how the helper script behaves, which is significant in an automation skill that may run with service credentials.

Content

Scanner excerpt · scripts/init_repo.py (reported line 92)May include surrounding context.

python
cmd = ['node', str(smtp_script), '--account', EMAIL_ACCOUNT,
               'send', '--to', to, '--subject', subject, '--body', body]

    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    if result.returncode != 0:
        print(f'[WARN] 邮件发送失败: {result.stderr}', file=sys.stderr)
    return result.returncode == 0

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
main.js:64