Back to skill

Security audit

Github Novel Serialization

Security checks for vulnerabilities and agentic risk

Overview

This novel-writing skill needs review because its release automation has a command-execution flaw and can publish chapters without enforcing their approval.

Fix the release workflow before enabling it: validate tag names, pass tag text through a quoted environment variable, and reduce token permissions. Review the exact chapter attachments and actual editorial approvals before pushing a release tag. Only paste unpublished manuscripts into AI services you have chosen to trust.

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
.github/workflows/novel-release.yml:130
Finding

Git tag name is interpolated directly into shell source

Content
View full analysis

Impact

Arbitrary commands execute on the release runner. The workflow grants contents: write and packages: write at lines 9–11, and checkout at lines 17–18 retains credentials by default, exposing repository write credentials to injected commands.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (38)

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 · Makefile (reported line 41)May include surrounding context.

text
$(DEV) scaffold --name "$(NAME)" --root "$(ROOT_DIR)"

clean:
	rm -rf .workbuddy/.pytest_cache
	find . -name __pycache__ -type d -prune -exec rm -rf {} +

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

md
.claude/
.copilot/
.agents/
.env
.env.local

# Logs

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

md
.copilot/
.agents/
.env
.env.local

# Logs
*.log

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The supplied chunk implements repository hygiene tooling rather than novel-writing orchestration, narrative continuity verification, or GitHub publishing. Although hygiene checks could support a publishing workflow, this script independently audits a broad local directory tree and optionally modifies matching files, capabilities not represented in the declared description. It contains no AI integration, narrative analysis, or GitHub interaction. This assessment is limited to the supplied chunk.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The supplied code primarily launches developer checks through subprocesses. It does not implement AI-assisted writing, character or world creation, chapter continuity verification, or GitHub publishing. Its scaffold command is related to novel-project setup, but the dominant functionality is development tooling, making this a material primary-purpose mismatch. No malicious behavior or external data transmission is evident; the delegated scripts' internal behavior is not shown.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The supplied chunk primarily tests a repository hygiene utility and contains no writing, character development, world-building, narrative continuity, or GitHub publishing functionality. Such checks could support a publishing workflow, but this chunk establishes no integration with that workflow; its demonstrated purpose is materially different. File changes shown are limited to test fixtures, and the scanner implementation itself is not supplied.

Content

No source excerpt is available for this finding.

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
both forms are supported), and keeps lexical sort equal to numeric sort. See `references/subproject-playbook.md` Section 2.

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
> `references/subproject-playbook.md` Section 3 (timeline inside `worldbuilding/`, character state

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **Subproject Playbook**: `references/subproject-playbook.md` — field-tested layout, decision ledger, report indexing, layered memory, hygiene. **Where it disa

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
d files are exempt **but must be declared** via `scan_hygiene.py --allow`. See `references/subproject-playbook.md` Section 10.

Incomplete referenced artifact analysis

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- **Shared Scripts**: `scripts/README.md` — catalog and invocation conventions for `humanizer_check.py` (de-AI-tone gate), `_list_hits.py`, `_promote_draft.py`

Tool Parameter Abuse

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

md
- 改动一律**先进子项目草稿**(`notes-personal/`),草稿 `humanizer_check.py` 通过且审核通过后,才允许用 `_promote_draft.py` 同步进 `chapters/` 定稿。
- 送审走**三审制度**:`review_all.py --stage first`(初审·责任编辑)→ `--stage second`(复审·编辑部主任)→ `--stage final`(终审·主编签发),每审次各出一份带独立签字栏的报告,全部归档到 `.workbuddy/reports/`。审次单向流转,任一 `FAIL` 退回上一环节;**终审未签发(或 FAIL 未清零)不得 promote**。
- `_promote_draft.py` 默认执行 humanizer 自检,FAIL 拒绝同步;`--force` 为例外通道,`--no-check` 不推荐。
- 纯勘误(错别字、标点、繁简、断行)可直改定稿并用 `_sync_draft.py` 回写草稿。

## 新增子项目脚本

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

md
|---|---|---|
| `humanizer_check.py` | 去 AI 痕迹自检:AI 腔词密度、结构套话与抽象评价、模糊副词、情绪标签、套路句式、章末升华、成语连用、破折号/省略号/感叹号密度、段长变异系数;按 PASS / WARN / FAIL 分级 | `<文件或目录>`、`--out <报告.md>` |
| `_list_hits.py` | 列出待改写的命中句(人工改写前取句) | `--kind banned/pattern/vague/emotion/idiom/dash`、`--target <路径>`、`--limit N` |
| `_promote_draft.py` | 草稿 → 定稿(release)同步:按章号整块写入、写前快照 `_trash/定稿同步前_<日期>/`、字数前后对比、章标题零差异校验、humanizer 门禁(FAIL 拒绝同步) | `<章号...>`、`--root`、`--draft`、`--dry-run`、`--report`、`--no-check`、`--force` |
| `_sync_draft.py` | 定稿 → 草稿回写(**仅勘误**,不得作常规改动通道) | `<章号...>` |
| `review_all.py` | **综合审稿**:跑门禁并输出审核报告(对象/结论表/问题明细/规模概览/待办清单/签字栏);`--stage` 按三审制度分阶段(`first` 初审=humanizer+scale+punctuation/`second` 复审=continuity+rationality/`final` 终审=全维回归+签发),各审次出独立签字栏;不带 `--stage` 为一次跑全部(旧行为) | `--batch`、`--stage`、`--chapters`、`--draft`、`--target`、`--skip`、`--out` |
| `review_scale.py` | **规模审查**:每章字数、达标率、缺口、分布区间与缺口 TOP(供分批扩写排序) | `--target`、`--max`、`--chapters`、`--draft`、`--out` |

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 · scripts/_promote_draft.py (reported line 10)May include surrounding context.

python
python "../GitHub Novel Serialization Skill/scripts/_promote_draft.py" 031 --dry-run   # 只看差异,不落盘
  python "../GitHub Novel Serialization Skill/scripts/_promote_draft.py" 031 --report .workbuddy/reports/xxx.md
  python "../GitHub Novel Serialization Skill/scripts/_promote_draft.py" 031 --root "C:/Users/Admin/-1928"
  python "../GitHub Novel Serialization Skill/scripts/_promote_draft.py" 031 --no-check  # 跳过 humanizer 自检(不推荐)
  python "../GitHub Novel Serialization Skill/scripts/_promote_draft.py" 031 --force     # humanizer 非 PASS 也强制同步

前提:草稿改动已通过审核(§9.1 第 1—4 步)。未过审的改动不得进定稿。

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 · scripts/_promote_draft.py (reported line 69)May include surrounding context.

python
ap.add_argument('--draft', default=DRAFT_DEFAULT)
    ap.add_argument('--dry-run', action='store_true')
    ap.add_argument('--report', default='', help='审核报告路径(记入同步日志)')
    ap.add_argument('--no-check', action='store_true')
    ap.add_argument('--force', action='store_true')
    ap.add_argument('--root', default='', help='子项目根目录(默认当前工作目录,须含 chapters/ 与 notes-personal/)')
    a = ap.parse_args()

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · scripts/init_subproject.py (reported line 471)May include surrounding context.

python
ap.add_argument("--scripts", default="../GitHub Novel Serialization Skill/scripts",
                    help="relative path to the shared scripts directory")
    ap.add_argument("--owner", default="OWNER", help="GitHub owner, used in generated links")
    ap.add_argument("--force", action="store_true", help="overwrite existing files")
    ap.add_argument("--dry-run", action="store_true", help="print the plan, write nothing")
    args = ap.parse_args(argv)

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · README.md (reported line 301)May include surrounding context.

Create a symlink in your Claude Code skills directory

mkdir -p ~/.claude/skills ln -s $(pwd) ~/.claude/skills/github-novel-serialization-skill

text

### For Cursor / Other Agents

The release workflow claims to run continuity verification but only checks whether a module documentation file exists, then publishes regardless.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

The purported continuity check only tests whether a documentation file exists; it never validates chapter content and does not fail when the module is missing. This creates a fail-open publication gate that can release unchecked content despite the skill's explicit requirement that every chapter pass verification.

Content

No source excerpt is available for this finding.

The mandatory release workflow uploads every chapter file without warning users about the full publication scope.

Medium
Category
Output Handling
Confidence
90% confidence
Finding

The release action attaches every matching chapter rather than only the chapter approved for a particular release. In a serialization workflow this can distribute future or unapproved chapters unintentionally; the exposure depends on repository visibility and existing access, and does not bypass private-repository permissions.

Content

No source excerpt is available for this finding.

Skill declares no tool scope ('permissions' or 'allowed-tools') but code capabilities were detected: file_read, file_write, network, shell.

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

The publishing workflow instructs the agent to push to a repository without warning about external data transmission or publication visibility.

Medium
Category
Output Handling
Confidence
94% confidence
Finding

The Quick Start explicitly instructs the agent to push to a repository, rather than merely listing a tool capability. The skill does not warn that this sends local release data to a remote host and may expose it to others depending on repository visibility.

Content

No source excerpt is available for this finding.

The copy-paste workflow sends manuscript content to external AI services without a privacy warning.

Medium
Category
Output Handling
Confidence
90% confidence
Finding

The template instructs users to paste it into third-party AI chat services, with the full draft and continuity notes supplied as inputs (L040–L064). It provides no warning that unpublished manuscripts or confidential notes will be shared with the selected provider and handled under that provider's data policies.

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

python
def humanizer_pass(path):
    r = subprocess.run([sys.executable, HUMANIZER, path],
                       capture_output=True, text=True, encoding='utf-8')
    out = r.stdout or ''
    m = re.search(re.escape(os.path.basename(path)) + r'.*?\*\*(PASS|WARN|FAIL)\*\*', out, re.S)

Backtick paths documented as “listed, not judged” can instead become release-blocking findings.

Medium
Category
Excessive Agency
Confidence
98% confidence
Finding

L032–L034 explicitly state that backtick paths are documentation rather than links and are listed without judgment. However, L313–L316 convert only existing targets to BARE, retaining MISSING and NONRELEASE classifications for other backtick paths; these can fail the check through --fail-on (L405–L411), including the documented invocation at L059.

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

python
def run(cmd: list, label: str) -> int:
    print(f"\n--- {label} ---")
    print("$ " + " ".join(f'"{c}"' if " " in c else c for c in cmd))
    proc = subprocess.run(cmd, cwd=str(ROOT))
    if proc.returncode == 0:
        print(f"[ok] {label}")
    else: