Back to skill

Security audit

上线体检

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent local release-check tool, but it has under-disclosed filesystem boundary risks around symlinks and report writing that users should review before installing.

Install only if you are comfortable running it on trusted repositories or in a sandbox. Avoid scanning untrusted repos with preserved symlinks, avoid writing reports to paths inside untrusted worktrees, and review generated reports before sharing them because they may contain source snippets or configuration findings.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/release_check.py:503
Finding

Attacker-Controlled Output Symlink Can Overwrite Files Outside the Project

Content
View full analysis

Vulnerability Details

File Location: scripts/release_check.py:503-505
Vulnerability Type: Symbolic-link-following arbitrary file overwrite
Risk Level: Medium

Vulnerable Code

python
out_path = os.path.abspath(a.out or default_out(root))
os.makedirs(os.path.dirname(out_path) or ".", exist_ok=True)
with open(out_path, "w", encoding="utf-8") as fh:
    fh.write(render(root, items, generated))

Technical Analysis

The documented workflow permits writing the report to a relative path inside the scanned repository, such as:

bash
python3 scripts/release_check.py . --out ./release-report.md

The implementation converts that path to an absolute lexical path but does not:

  • Check whether the destination is a symbolic link.
  • Resolve the destination and enforce containment within an authorized output directory.
  • Use no-follow file-opening semantics.
  • Create a new output file atomically.

Python's open(..., "w") follows symbolic links and truncates the resolved destination. Consequently, a repository contributor can supply release-report.md as a symbolic link to another file writable by the user running the Skill.

This crosses the trust boundary between repository-controlled filesystem metadata and the user's filesystem. The user authorizes creation of a report at the selected repository path, but the repository can redirect that write to a different path.

There is no evidence that the project intentionally creates malicious links or targets user files; this is an exploitable coding flaw rather than evidence of a backdoor.

Attack Path

  1. An attacker controls or contributes content to a repository that the victim will scan.
  2. The attacker adds a symbolic link such as:
    text
    release-report.md -> /home/victim/.config/example/config
    
  3. The victim clones or otherwise obtains the repository with the symbolic link preserved.
  4. Following the documented usage, the victim runs:
    bash
    python3 scripts/rel
    

...[truncated 947 chars]

Remediation
View remediation

Remediation Suggestions

  • Reject an existing output path when os.lstat() shows that it is a symbolic link.
  • Resolve the destination with os.path.realpath() and verify that it remains within an explicitly authorized output directory.
  • Open the destination with no-follow semantics, such as os.open() with O_NOFOLLOW, where supported.
  • Use exclusive or atomic creation to reduce race conditions:
    1. Create a new temporary file in the authorized destination directory.
    2. Write and flush the report.
    3. Atomically rename it to the final destination after validating the destination.
  • Refuse non-regular output files, including device nodes, FIFOs, and sockets.
  • If overwriting an existing regular file is required, require an explicit overwrite option and validate the file again immediately before replacement.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/release_check.py:76
Finding

Symlinked Project Inputs Can Read and Disclose Files Outside the Scan Root

Content
View full analysis

Vulnerability Details

File Location: scripts/release_check.py:76-97
Related Locations: scripts/checks/sql_migration_check.py:119, scripts/release_check.py:245-247, scripts/release_check.py:470-473
Vulnerability Type: Symbolic-link path escape and local file disclosure
Risk Level: Medium

Vulnerable Code

Discovery records files by their apparent pathname without rejecting symbolic links or validating their resolved location:

python
for dirpath, dirnames, filenames in os.walk(root):
    dirnames[:] = sorted(d for d in dirnames if d not in SKIP_DIRS and not d.startswith(".git"))
    for fn in sorted(filenames):
        full = os.path.join(dirpath, fn)
        rel = os.path.relpath(full, root)
        low = fn.lower()
        if fn == "Dockerfile" or fn.startswith("Dockerfile.") or low.endswith(".dockerfile"):
            found["dockerfile"].append(rel)
            continue
        if low.endswith(".sql"):
            found["sql"].append(rel)
            continue

The SQL checker then follows the discovered pathname:

python
def scan_file(path, dialect):
    text = sys.stdin.read() if path == "-" else open(path, encoding="utf-8", errors="replace").read()
    clean = strip_comments(text)

Matching SQL text is propagated into a finding:

python
msg = f.get("message", "")
stmt = (f.get("statement") or "").strip()
if stmt:
    msg = f"{msg}(语句 `{stmt[:90]}`)"
out.append(finding(f.get("severity"), f.get("rule"), where, msg, f.get("fix")))

The finding is subsequently written to the generated report:

python
for f in i["findings"][:TOP_N]:
    head = f"- **[{f['severity'].upper()}]** `{f['code']}`"
    if f["where"]:
        head += f" · `{f['where']}`"
    lines.append(f"{head} — {f['message']}")

Technical Analysis

The scanner is intended to inspect files under a user-selected project root. However, file discovery uses the apparent path returned by os.walk() and checks only the filename extension. It ...[truncated 2928 chars]

Remediation
View remediation

Remediation Suggestions

  • Reject symbolic-link files during discovery:
    python
    if os.path.islink(full):
        continue
    
  • Resolve every candidate with os.path.realpath() and verify containment using os.path.commonpath():
    python
    root_real = os.path.realpath(root)
    candidate_real = os.path.realpath(full)
    if os.path.commonpath([root_real, candidate_real]) != root_real:
        continue
    
  • Apply the same validation in each standalone checker so that direct invocation cannot bypass the orchestrator's checks.
  • Use no-follow file-opening semantics where supported.
  • After opening a file, use descriptor metadata to verify that it is a regular file and mitigate path-replacement races.
  • Do not include source statement text in reports by default. Prefer rule identifiers, filenames, and line numbers.
  • If excerpts are necessary, add an explicit option and clearly warn that report artifacts may contain source data.
  • Add regression tests covering:
    • Symlinked files pointing outside the project.
    • Symlink chains.
    • Broken links.
    • Links to special files.
    • Replacement of a validated file between validation and opening.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The documentation promises a comprehensive five-check release gate with strict 'unknown means fail' behavior, but the analyzed implementation reportedly lacks most of that functionality and has different gating semantics. This is dangerous because operators may rely on the tool as a release control and incorrectly approve deployments based on incomplete or weaker checks than advertised.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · scripts/checks/dockerfile_check.py (reported line 87)May include surrounding context.

python
add("DF011", "warn", line, "RUN 中使用 sudo", "构建时默认就是 root,无需 sudo;需要降权时用 USER 指令")
            if re.search(r"(curl|wget)[^|]*\|\s*(sudo\s+)?(ba|z|da)?sh\b", low):
                add("DF012", "warn", line, "远程脚本直接管道进 shell 执行", "先下载、校验(sha256 / 签名)再执行,或固定脚本版本")
            if "chmod 777" in low or "chmod -r 777" in low:
                add("DF016", "warn", line, "chmod 777", "按需给最小权限,如 755 / 644")
            if "apt-get upgrade" in low or "apt upgrade" in low:
                add("DF002", "warn", line, "apt-get upgrade 会让镜像不可复现且膨胀", "改为固定基础镜像版本;需要安全更新就换更新的基础镜像标签")

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/checks/env_sync_check.py (reported line 6)May include surrounding context.

python
用法:
  python3 env_sync_check.py                      # 当前目录:.env.example 对比 .env* 并扫描代码
  python3 env_sync_check.py --example .env.example --env .env.production --src src/
  python3 env_sync_check.py --json --strict      # 有缺失必填变量则退出码 1
检查项:示例里有、环境文件缺(缺配置);环境文件有、示例没有(未登记);代码读取但示例没有(漏文档);示例定义但代码从未读取(僵尸变量);环境文件里的疑似真实密钥;重复定义。
"""

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/checks/env_sync_check.py (reported line 77)May include surrounding context.

python
URL_LIKE = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://")
URL_CRED = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://[^:@/\s]*:(?P<pw>[^@/\s]*)@")
NUMERIC = re.compile(r"^[\d.,:_+\-]+$")
SRC_EXT = {".py", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".go", ".java", ".kt", ".rb", ".php", ".rs", ".sh", ".bash", ".yml", ".yaml", ".toml", ".cfg", ".ini", ".env"}


def parse_env(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 · scripts/checks/env_sync_check.py (reported line 105)May include surrounding context.

python
URL_LIKE = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://")
URL_CRED = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://[^:@/\s]*:(?P<pw>[^@/\s]*)@")
NUMERIC = re.compile(r"^[\d.,:_+\-]+$")
SRC_EXT = {".py", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".go", ".java", ".kt", ".rb", ".php", ".rs", ".sh", ".bash", ".yml", ".yaml", ".toml", ".cfg", ".ini", ".env"}


def parse_env(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 · scripts/checks/env_sync_check.py (reported line 170)May include surrounding context.

python
URL_LIKE = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://")
URL_CRED = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://[^:@/\s]*:(?P<pw>[^@/\s]*)@")
NUMERIC = re.compile(r"^[\d.,:_+\-]+$")
SRC_EXT = {".py", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".go", ".java", ".kt", ".rb", ".php", ".rs", ".sh", ".bash", ".yml", ".yaml", ".toml", ".cfg", ".ini", ".env"}


def parse_env(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 · scripts/release_check.py (reported line 96)May include surrounding context.

python
URL_LIKE = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://")
URL_CRED = re.compile(r"^[A-Za-z][A-Za-z0-9+.\-]*://[^:@/\s]*:(?P<pw>[^@/\s]*)@")
NUMERIC = re.compile(r"^[\d.,:_+\-]+$")
SRC_EXT = {".py", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".go", ".java", ".kt", ".rb", ".php", ".rs", ".sh", ".bash", ".yml", ".yaml", ".toml", ".cfg", ".ini", ".env"}


def parse_env(path):

Privileged Kubernetes Workload

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Code deploys a privileged Kubernetes workload (privileged container, hostPath mount, or host namespaces). This grants root on the node and is a node/cluster takeover vector.

Content

Scanner excerpt · scripts/checks/k8s_check.py (reported line 222)May include surrounding context.

python
add("K003", "info", f"容器 {cn} 没有 livenessProbe", "为长期运行的服务加存活探针(注意别与就绪探针指向同一个重依赖检查)")
        csc = c.get("securityContext") or {}
        if csc.get("privileged") is True:
            add("K004", "high", f"容器 {cn} privileged: true", "几乎等于 root 节点权限;改用具体 capabilities")
        if csc.get("runAsNonRoot") is not True and psc.get("runAsNonRoot") is not True:
            add("K004", "warn", f"容器 {cn} 未声明 runAsNonRoot: true", "在 securityContext 设置 runAsNonRoot: true 与 runAsUser(非 0)")
        if csc.get("allowPrivilegeEscalation") is not False:

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

md
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

md
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

md
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

md
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

md
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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/checks/env_sync_check.py (reported line 161)May include surrounding context.

python
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

python
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

python
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

python
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

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

python
#!/usr/bin/env python3
"""上线前五分钟体检:把 Dockerfile / K8s 清单 / SQL 迁移 / OpenAPI / .env 五项检查串起来,汇总成一份报告。

用法:
  python3 scripts/release_check.py [目标目录] [--out 报告路径] [--json] [--strict]

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares broad operational behavior—walking project directories, invoking subprocesses, and writing reports—but does not declare any explicit tool scope or permissions boundary. In an agent environment, that omission can result in overbroad file, shell, environment, or network access being granted implicitly, increasing the blast radius if the skill is misused or compromised.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The primary description and invocation examples are written to trigger on Chinese phrases such as "当用户说『能不能上线』『上线前检查一下』...时使用", which establishes a language-specific activation pattern. There is English metadata elsewhere, but this line itself frames usage around Chinese-only phrasing without stating that users may choose their preferred language.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest text says the tool is '只读文件' and the boundary section says it only does static checking, which implies read-only operation. However, later documentation explicitly states it writes a Markdown report to a temp directory or a user-specified path via --out, so the behavior is not purely read-only.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This is an active contradiction within the documentation: '只读文件' suggests no filesystem writes, yet the usage and process sections describe writing a Markdown report and printing its path. That makes the comment materially inconsistent with the described implementation behavior.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

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

python
elif name == "RUN":
            cmd = arg
            low = cmd.lower()
            if "sudo " in low:
                add("DF011", "warn", line, "RUN 中使用 sudo", "构建时默认就是 root,无需 sudo;需要降权时用 USER 指令")
            if re.search(r"(curl|wget)[^|]*\|\s*(sudo\s+)?(ba|z|da)?sh\b", low):
                add("DF012", "warn", line, "远程脚本直接管道进 shell 执行", "先下载、校验(sha256 / 签名)再执行,或固定脚本版本")

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/checks/dockerfile_check.py (reported line 87)May include surrounding context.

python
add("DF011", "warn", line, "RUN 中使用 sudo", "构建时默认就是 root,无需 sudo;需要降权时用 USER 指令")
            if re.search(r"(curl|wget)[^|]*\|\s*(sudo\s+)?(ba|z|da)?sh\b", low):
                add("DF012", "warn", line, "远程脚本直接管道进 shell 执行", "先下载、校验(sha256 / 签名)再执行,或固定脚本版本")
            if "chmod 777" in low or "chmod -r 777" in low:
                add("DF016", "warn", line, "chmod 777", "按需给最小权限,如 755 / 644")
            if "apt-get upgrade" in low or "apt upgrade" in low:
                add("DF002", "warn", line, "apt-get upgrade 会让镜像不可复现且膨胀", "改为固定基础镜像版本;需要安全更新就换更新的基础镜像标签")

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · scripts/checks/dockerfile_check.py (reported line 88)May include surrounding context.

python
add("DF011", "warn", line, "RUN 中使用 sudo", "构建时默认就是 root,无需 sudo;需要降权时用 USER 指令")
            if re.search(r"(curl|wget)[^|]*\|\s*(sudo\s+)?(ba|z|da)?sh\b", low):
                add("DF012", "warn", line, "远程脚本直接管道进 shell 执行", "先下载、校验(sha256 / 签名)再执行,或固定脚本版本")
            if "chmod 777" in low or "chmod -r 777" in low:
                add("DF016", "warn", line, "chmod 777", "按需给最小权限,如 755 / 644")
            if "apt-get upgrade" in low or "apt upgrade" in low:
                add("DF002", "warn", line, "apt-get upgrade 会让镜像不可复现且膨胀", "改为固定基础镜像版本;需要安全更新就换更新的基础镜像标签")

Static analysis

No suspicious patterns detected.