Back to skill

Security audit

github-skill-publisher

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real GitHub publishing helper, but it can publicly upload broad local directories with weak review boundaries and asks for powerful GitHub token handling.

Install only if you are comfortable giving the workflow GitHub repository write authority and manually reviewing exactly what will be uploaded. Use a least-privilege, short-lived token through a secure secret mechanism, prefer private repo creation first, inspect the complete file list yourself, and do not rely on this scanner as proof that no secrets or private files will be published.

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

Error
Location
scripts/publish.py:91
Finding

Incomplete privacy scanning can publish unreviewed sensitive files to a public repository

Content
View full analysis

Vulnerability Details

File Location: scripts/publish.py:91-102, scripts/publish.py:166-197, and scripts/publish.py:221-236
Vulnerability Type: Incomplete security validation followed by automatic public disclosure
Risk Level: High

Vulnerable Code

The upload routine recursively collects every file under the supplied directory:

python
def upload_dir(token, owner, repo, local_dir, file_order=None):
    """递归上传整个目录。

    file_order: 优先上传的文件列表(先根目录 README,再子目录)
    """
    all_files = []
    for root, dirs, files in os.walk(local_dir):
        for f in files:
            full = os.path.join(root, f)
            rel = os.path.relpath(full, local_dir)
            all_files.append(rel)

The privacy scanner excludes selected filenames and silently skips files that cannot be decoded as UTF-8:

python
ignore_files = ignore_files or []
issues = []
for root, dirs, files in os.walk(local_dir):
    for f in files:
        full = os.path.join(root, f)
        # 跳过规则定义自身(脚本和 SKILL.md)
        if f in ignore_files:
            continue
        try:
            with open(full, 'r', encoding='utf-8') as fp:
                content = fp.read()
        except (UnicodeDecodeError, IOError):
            continue
        for pat, desc in patterns:
            m = re.search(pat, content)
            if m:
                issues.append((full, desc, m.group()[:60]))
return issues

Publication explicitly excludes all files named publish.py or SKILL.md from review, creates a public repository, and then uploads the complete directory:

python
issues = privacy_scan(local_dir, ignore_files=['publish.py', 'SKILL.md'])
if issues:
    print(f'❌ 发现 {len(issues)} 个潜在问题:')
    for path, desc, snippet in issues:
        print(f'   {path}: {desc} -> {snippet}')
    print('请先修复再发布。')
    sys.exit(1)
print('  ✅ 干净')

create_repo(token, repo, description, priv
...[truncated 3917 chars]
Remediation
View remediation

Remediation Suggestions

  1. Use one immutable, validated manifest

    • Enumerate candidate files once.
    • Scan the exact bytes that will be uploaded.
    • Store approved paths, hashes, and file sizes in a manifest.
    • Upload only entries whose hashes still match the reviewed manifest.
  2. Fail closed

    • Treat decoding failures, unreadable files, broken links, and unsupported file types as blocking findings.
    • Never interpret an unscannable file as clean.
    • Require explicit, per-file approval if binary publication is necessary.
  3. Remove broad filename exclusions

    • Do not exclude every file named publish.py or SKILL.md.
    • If scanner rule definitions cause self-matches, suppress only the exact known lines or findings rather than the entire file.
    • Ensure every uploaded file receives equivalent validation.
  4. Constrain directory traversal

    • Exclude .git, environment files, editor metadata, caches, temporary files, build outputs, and credential stores by default.
    • Add an explicit allowlist of intended publication paths or file types.
    • Detect symbolic links and reject links that resolve outside the canonical source directory.
  5. Improve secret detection

    • Add generic credential assignment checks for terms such as api_key, secret, password, and token.
    • Detect common cloud, package registry, database, SSH, and private-key formats.
    • Use entropy-based checks or an established secret-scanning tool.
    • Report every finding rather than only the first match for each pattern and file.
  6. Require explicit approval

    • Display the complete upload manifest, repository owner, repository name, visibility, and all scan findings.
    • Require a deliberate confirmation before the first network request.
    • Do not rely solely on the absence of regex matches as consent to publish.
  7. Default to private visibility

    • Create the repository ...[truncated 506 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (29)

Tainted flow: 'req' from os.environ.get (line 67, 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/publish.py (reported line 45)May include surrounding context.

python
headers=auth_headers(token),
        method='POST',
    )
    with urllib.request.urlopen(req) as r:
        repo_data = json.loads(r.read())
    print(f'  ✅ 仓库已建: {repo_data["html_url"]}')

Tainted flow: 'req' from os.environ.get (line 67, 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/publish.py (reported line 68)May include surrounding context.

python
headers=auth_headers(token),
        method='POST',
    )
    with urllib.request.urlopen(req) as r:
        repo_data = json.loads(r.read())
    print(f'  ✅ 仓库已建: {repo_data["html_url"]}')

Tainted flow: 'req' from os.environ.get (line 67, 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/publish.py (reported line 86)May include surrounding context.

python
headers=auth_headers(token),
        method='POST',
    )
    with urllib.request.urlopen(req) as r:
        repo_data = json.loads(r.read())
    print(f'  ✅ 仓库已建: {repo_data["html_url"]}')

Tainted flow: 'req' from os.environ.get (line 67, 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/publish.py (reported line 127)May include surrounding context.

python
headers=auth_headers(token),
        method='POST',
    )
    with urllib.request.urlopen(req) as r:
        repo_data = json.loads(r.read())
    print(f'  ✅ 仓库已建: {repo_data["html_url"]}')

Tainted flow: 'req' from os.environ.get (line 67, 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/publish.py (reported line 141)May include surrounding context.

python
headers=auth_headers(token),
        method='POST',
    )
    with urllib.request.urlopen(req) as r:
        repo_data = json.loads(r.read())
    print(f'  ✅ 仓库已建: {repo_data["html_url"]}')

Tainted flow: 'req' from os.environ.get (line 67, 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/publish.py (reported line 161)May include surrounding context.

python
headers=auth_headers(token),
        method='POST',
    )
    with urllib.request.urlopen(req) as r:
        repo_data = json.loads(r.read())
    print(f'  ✅ 仓库已建: {repo_data["html_url"]}')

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

md
4. **补 topics** → 6 个,按"技术领域 + 内容领域 + 工具类型"配
5. **发 release** → v1.0.0 + 脱敏保证说明
6. **WebFetch 验证** → 看 GitHub 主页 README 渲染正常
7. **凭据清理** → `unset GH_TOKEN` + `rm -rf /tmp/*-review`

## 踩过的坑(已封装,不用再踩)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% 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 · README.md (reported line 71)May include surrounding context.

md
4. **补 topics** → 6 个,按"技术领域 + 内容领域 + 工具类型"配
5. **发 release** → v1.0.0 + 脱敏保证说明
6. **WebFetch 验证** → 看 GitHub 主页 README 渲染正常
7. **凭据清理** → `unset GH_TOKEN` + `rm -rf /tmp/*-review`

## 踩过的坑(已封装,不用再踩)

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

md
4. **补 topics** → 6 个,按"技术领域 + 内容领域 + 工具类型"配
5. **发 release** → v1.0.0 + 脱敏保证说明
6. **WebFetch 验证** → 看 GitHub 主页 README 渲染正常
7. **凭据清理** → `unset GH_TOKEN` + `rm -rf /tmp/*-review`

## 踩过的坑(已封装,不用再踩)

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

声明描述的是一个“完整工作流”发布器,包含脱敏检查、结构标准化、建仓、逐文件推送、补 topics/description/release,以及处理公开可见性等坑点。实际代码确实实现并执行了脱敏检查、创建仓库、上传文件,且创建仓库时会设置 description,因此这部分是匹配的。但关键差异在于:1) 没有任何代码对本地项目结构进行 github-project-radar 标准化或重排;2) set_topics、set_visibility、create_release 虽被定义,但 main() 中没有调用,因此实际运行不会补 topics、release 或可见性步骤;3) 声明给人的预期是“一次完成完整公开发布”,但代码主流程只覆盖其中一部分。因此属于描述高于实际行为的明显不匹配,而不是支持性实现细节差异。

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

md
| 文件结构 | `SKILL.md` + `README.md` + `LICENSE`(MIT)+ `.gitignore` + `references/` + `assets/` |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 61)May include surrounding context.

md
| 文件结构 | `SKILL.md` + `README.md` + `LICENSE`(MIT)+ `.gitignore` + `references/` + `assets/` |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

The separate match on rm -rf /tmp/xxx-review is a real hazardous pattern even though the specific target is a temp path. In an automation skill that may be adapted or copied, normalizing forceful recursive deletion encourages unsafe command reuse and can cause accidental file destruction if the path is malformed or broadened.

Content

Scanner excerpt · SKILL.md (reported line 242)May include surrounding context.

md
发布完一个项目后,必须:
1. `unset GH_TOKEN` —— 凭据立即从环境清空
2. 临时文件 `rm -rf /tmp/xxx-review` —— 不留痕
3. 写 memory:今天推了几个仓、commit hash、踩了什么坑
4. 主动挑刺 + 报告,让用户决定是否继续

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

The separate match on rm -rf /tmp/xxx-review is a real hazardous pattern even though the specific target is a temp path. In an automation skill that may be adapted or copied, normalizing forceful recursive deletion encourages unsafe command reuse and can cause accidental file destruction if the path is malformed or broadened.

Content

Scanner excerpt · SKILL.md (reported line 242)May include surrounding context.

md
发布完一个项目后,必须:
1. `unset GH_TOKEN` —— 凭据立即从环境清空
2. 临时文件 `rm -rf /tmp/xxx-review` —— 不留痕
3. 写 memory:今天推了几个仓、commit hash、踩了什么坑
4. 主动挑刺 + 报告,让用户决定是否继续

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

The separate match on rm -rf /tmp/xxx-review is a real hazardous pattern even though the specific target is a temp path. In an automation skill that may be adapted or copied, normalizing forceful recursive deletion encourages unsafe command reuse and can cause accidental file destruction if the path is malformed or broadened.

Content

Scanner excerpt · SKILL.md (reported line 242)May include surrounding context.

md
发布完一个项目后,必须:
1. `unset GH_TOKEN` —— 凭据立即从环境清空
2. 临时文件 `rm -rf /tmp/xxx-review` —— 不留痕
3. 写 memory:今天推了几个仓、commit hash、踩了什么坑
4. 主动挑刺 + 报告,让用户决定是否继续

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

Line L66 recommends create_repo(auto_init=True), but elsewhere the README repeatedly emphasizes creating an empty repository and describes auto_init as a pitfall because the generated README can overwrite uploaded content unless special handling is used. This is an active contradiction in the documentation about the intended repository creation mode.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The line states that mixed Chinese-English descriptions are undesirable and that descriptions 'must be pure Chinese'. This is a natural-language policy concern because it imposes a language requirement without offering user choice or documenting a region-specific need.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill describes capabilities that read local files, access environment variables, and make network requests to GitHub, but it does not declare an explicit tool scope such as allowed tools or permissions. That creates an authorization gap: an agent may invoke broader capabilities than the user expects when a common GitHub-related request triggers this skill.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The trigger phrases are broad enough to match many ordinary requests about GitHub, including ambiguous requests that do not imply consent to publish local content publicly. In this skill's context, overbroad activation is more dangerous because the described workflow includes scanning local files, handling credentials, and creating public repositories.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The standard output requires “中文优先,” and later repository structure guidance also mandates a Chinese README, which is a language policy constraint expressed in natural language. The file does not indicate that the user can choose another language or opt into this locale preference.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill explicitly instructs the agent to ask the user to paste a GitHub PAT into chat. That creates a direct natural-language exfiltration path for sensitive credentials into conversation logs, model context, and any downstream storage, which is especially risky because the PAT can grant repository creation and modification privileges.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The instruction to write persistent memory containing repository counts, commit hashes, and publishing history stores user activity beyond what is necessary to complete the publication task. Persistent retention of this metadata can leak project history, private workflow details, or future correlation signals if memory is later exposed or reused in unrelated contexts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The cheatsheet includes a workflow for changing a repository from private to public, but it does not explicitly warn that this action permanently broadens access and can expose sensitive code, history, metadata, and previously overlooked secrets. In a publishing skill whose purpose is to push local content to public GitHub, omission of a strong visibility warning increases the chance of accidental disclosure even if a privacy scan is mentioned.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language instructions, usage examples, and operational messages only in Chinese. That forces a specific language on users without opt-in, which matches the policy's language/locale violation criterion.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The function signature and docstring imply repository creation can also apply topics when provided. However, set_topics expects (token, owner, repo, topics) and create_repo calls set_topics(token, name, topics), omitting owner and misplacing arguments, which contradicts the documented intent that topics are handled as part of repo creation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.