Back to skill

Security audit

agent-project-structure

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a straightforward project-structure helper, but its creation script can overwrite existing files and follow symlinks outside the chosen project path.

Review before installing if you work in existing projects or shared directories. Use the create script only on a new empty directory or after checking for existing files and symlinks, because accepting the prompt on an existing path may overwrite configuration placeholders such as config/settings.json.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/create_structure.py:61
Finding

Unsafe Overwrite and Symlink Following During Project Structure Creation

Content
View full analysis

Vulnerability Details

File Location: scripts/create_structure.py, lines 61-65
Vulnerability Type: Unsafe file overwrite and symlink traversal
Risk Level: Medium

Vulnerable Code

python
for file_path, content in example_files.items():
    full_path = project_path / file_path
    full_path.parent.mkdir(parents=True, exist_ok=True)
    with open(full_path, 'w') as f:
        f.write(content)

The relevant generic confirmation logic is at lines 84-89:

python
if project_path.exists():
    print(f"警告: 路径已存在: {project_path}")
    response = input("是否继续? (y/N): ")
    if response.lower() != 'y':
        print("已取消")
        sys.exit(0)

Technical Analysis

The script opens every placeholder file with mode w, which truncates an existing file before writing the new content. It does not check whether individual files already exist or disclose which files will be replaced. For example, an existing config/settings.json is unconditionally replaced with {} after the user accepts only a generic project-level confirmation.

The script also does not reject symbolic links or verify resolved-path containment. If a target file such as config/settings.json, or one of its parent directories, is a symbolic link, Python follows that link when opening the destination. A crafted project directory can therefore redirect a write outside the selected project root.

This is a fixed-content arbitrary file-write primitive rather than arbitrary-content code execution: the attacker can choose a writable target through a symlink, while the content written is determined by the script's example_files mapping.

Attack Path

  1. An attacker prepares a directory that appears to be an existing project.
  2. The attacker creates a symbolic link at a generated path, such as config/settings.json, pointing to a file writable by the victim. Alternatively, the directory already contains legitimate files at the placeholder paths.
  3. The victim or an Agent ...[truncated 1305 chars]
Remediation
View remediation

Remediation Suggestions

  1. Do not overwrite existing files by default. Use exclusive creation mode and handle FileExistsError:

    python
    with open(full_path, "x", encoding="utf-8") as f:
        f.write(content)
    

    Alternatively, explicitly skip every destination that already exists.

  2. Require granular overwrite consent. If replacement is supported, enumerate the exact files that would be changed and require explicit confirmation before modifying them.

  3. Reject symbolic links. Check every existing destination and parent path component with is_symlink() or os.lstat() and abort if a symbolic link is encountered.

  4. Enforce path containment. Resolve the project root and each destination, then verify that every destination remains beneath the resolved root before writing:

    python
    root = project_path.resolve()
    destination = full_path.resolve(strict=False)
    destination.relative_to(root)
    

    Abort when relative_to raises ValueError.

  5. Reduce race-condition exposure. Path checks alone can be bypassed if an attacker can modify directories concurrently. On supported platforms, use directory-relative file operations with no-follow semantics, such as openat-style operations and O_NOFOLLOW.

  6. Use atomic replacement only when intentional. Write to a safely and exclusively created temporary file within the verified destination directory, set appropriate permissions, and atomically rename it after explicit authorization.

  7. Add regression tests covering existing files, symlinked target files, symlinked parent directories, paths outside the project root, and cancellation without filesystem changes.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (13)

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 · references/GITIGNORE.md (reported line 31)May include surrounding context.

md
Thumbs.db

# 环境变量文件
.env
.env.local
.env.*.local

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 · references/GITIGNORE.md (reported line 32)May include surrounding context.

md
# 环境变量文件
.env
.env.local
.env.*.local

# 构建和依赖

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/GITIGNORE.md (reported line 45)May include surrounding context.

md
│   └── cache/
├── config/            # 配置文件目录
│   ├── settings.json
│   └── secrets.json
├── data/              # 数据文件目录
│   ├── input/
│   └── output/

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/GITIGNORE.md (reported line 46)May include surrounding context.

md
│   └── cache/
├── config/            # 配置文件目录
│   ├── settings.json
│   └── secrets.json
├── data/              # 数据文件目录
│   ├── input/
│   └── output/

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/PROJECT_STRUCTURE.md (reported line 23)May include surrounding context.

md
│   └── cache/
├── config/            # 配置文件目录
│   ├── settings.json
│   └── secrets.json
├── data/              # 数据文件目录
│   ├── input/
│   └── output/

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/PROJECT_STRUCTURE.md (reported line 111)May include surrounding context.

md
│   └── cache/
├── config/            # 配置文件目录
│   ├── settings.json
│   └── secrets.json
├── data/              # 数据文件目录
│   ├── input/
│   └── output/

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The markdown content is entirely in Chinese, including headings and usage instructions, with no indication that users may choose another language or that the skill is intentionally limited to a Chinese-speaking audience. This can violate a language/locale policy when a skill mandates one language without opt-in or justification.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding

The skill instructs the agent to create or adjust project directory structures and explicitly references scripts that would write files, but the skill metadata does not declare any tool scope such as permissions or allowed-tools. This creates an authorization gap where a broadly triggered skill could cause filesystem modifications without clear least-privilege boundaries or reviewer visibility.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The trigger phrases are generic terms like 'create a project', 'new project', and 'project structure', and the skill says it should default-trigger unless the user specifies otherwise. That makes unintended activation likely during ordinary conversations, increasing the chance the agent applies this skill and performs directory creation or reorganization when the user did not explicitly request filesystem changes.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This markdown file uses Chinese section headings throughout, such as the labels for logs, temporary files, screenshots, and other categories. Under the stated policy, forcing a specific language without opt-in or justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The title and the document content are written in Chinese, and there is no indication that other languages are supported or that Chinese is required for a region-specific purpose. Under the language/locale policy rule, forcing a specific language without user opt-in can be a policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file's docstrings and all user-facing CLI messages are written only in Chinese, including usage, errors, and success output. This imposes a language choice on users without offering an alternative or documenting that the tool is intended only for a Chinese-speaking audience.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

The docstrings, usage text, warnings, prompts, and status messages are all hard-coded in Chinese throughout the script. This creates a language/locale policy concern because the skill does not offer any user-selectable language option or document a justified locale restriction.

Content

No source excerpt is available for this finding.