Back to skill

Security audit

Novel Studio

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent novel-writing workflow, but its helper scripts include under-scoped file deletion/write behavior and an optional Feishu sync that uploads manuscripts to a hard-coded, undisclosed wiki space.

Review before installing. The writing workflow itself is coherent, but do not use the Feishu sync unless you verify and change the destination space. Treat the helper scripts as project-local tools only, and avoid passing untrusted stage, branch, artifact, or file-path values until path containment and deletion safeguards are fixed.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/stage_persistence_utils.py:62
Finding

Path Traversal Enables Arbitrary File Writes Outside the Project

Content
View full analysis
bool: return stage == 'character-system' and relpath.startswith('characters/') and relpath.endswith('.md') def validate_artifact_updates(stage: str, artifact_updates: dict[str, str], substage: str | None = None) -> dict[str, str]: if not isinstance(artifact_updates, dict): raise ValueError('artifactUpdates must be an object') allowed = document_stage_targets(stage, substage) normalized = {} for relpath, text in artifact_updates.items(): if not isinstance(relpath, str) or not relpath.strip(): raise ValueError('artifact path must be a non-empty string') if relpath not in allowed and not allow_character_file(stage, relpath): raise ValueError(f'out-of-scope artifact for {stage}: {relpath}') if not isinstance(text, str) or not text.strip(): raise ValueError(f'artifact content cannot be empty: {relpath}') normalized[relpath] = text return normalized ``` The validated value is subsequently used as a filesystem path without containment verification: ```python validated = validate_artifact_updates(args.stage, payload.get('artifactUpdates', {}), substage) for relpath, text in validated.items(): path = project / relpath path.parent.mkdir(parents=True, exist_ok=True) path.write_text(text, encoding='utf-8') ``` ### Technical Analysis Character artifact paths are approved using only textual prefix and suffix checks. A value such as `characters/../../outside.md` starts with `characters/` and ends with `.md`, so it passes validation. When the path is joined to the project directory, the operating system resolves the `. ...[truncated 1584 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/manage_stage_branches.py:45
Finding

Unvalidated Stage and Branch Identifiers Enable Arbitrary Recursive Directory Deletion

Content
View full analysis
Path: return project / 'staging' / stage / branch_id ``` The unvalidated path is used during branch promotion and deletion: ```python def promote_branch(project: Path, stage: str, branch_id: str, copy_files: list[str]) -> dict: data = load_state(project) workflow = data.setdefault('workflow', {}) review = data.setdefault('review', {}) style_risk = data.setdefault('narrativeIntelligence', {}).setdefault('styleRisk', {}) substage = workflow.get('currentSubstage') selected_branch = branch_dir(project, stage, branch_id) if not selected_branch.exists(): raise ValueError(f'branch not found: staging/{stage}/{branch_id}') artifact_updates = {} for relpath in copy_files: source = selected_branch / relpath if not source.exists(): raise ValueError(f'branch artifact not found: staging/{stage}/{branch_id}/{relpath}') artifact_updates[relpath] = source.read_text(encoding='utf-8') validated = validate_artifact_updates(stage, artifact_updates, substage) novelty_axes = parse_novelty_axes(selected_branch) for relpath, text in validated.items(): target = project / relpath target.parent.mkdir(parents=True, exist_ok=True) target.write_text(text, encoding='utf-8') shutil.rmtree(project / 'staging' / stage, ignore_errors=True) ``` The prune operation uses the same unvalidated stage value: ```python def prune_stage(project: Path, stage: str) -> dict: data = load_state(project) review = data.setdefault('review', {}) stage_root = project / 'staging' / stage active = { entry ...[truncated 2729 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/sync_to_feishu_wiki.py:5
Finding

Project Manuscripts Are Uploaded to an Undisclosed Hard-Coded Feishu Wiki Space

Content
View full analysis
[root_title]') sys.exit(1) project_dir = Path(sys.argv[1]).expanduser() root_title = sys.argv[2] if len(sys.argv) >= 3 else project_dir.name root_node, _ = get_or_create(SPACE_ID, root_title) root_token = root_node['node_token'] top_count = 0 for p in sorted(project_dir.glob('*.md')): sync_file(p, root_token) top_count += 1 time.sleep(0.2) for dirname in ['characters', 'manuscript']: d = project_dir / dirname if not d.is_dir(): continue dir_node, _ = get_or_create(SPACE_ID, dirname, root_token) dir_token = dir_node['node_token'] subcount = 0 for p in sorted(d.glob('*.md')): sync_file(p, dir_token) subcount += 1 time.sleep(0.15) print(f'{dirname}: {subcount}') ``` ### Technical Analysis The synchronization function reads complete Markdown content from: - The project root. - The `characters` directory. - The `m ...[truncated 2214 chars]
Remediation
View remediation
Vulnerability Patterns
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (96)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Validating subagent results via CLI, reading JSON bundles from disk, and outputting machine-readable validation results exposes a tooling interface that is not conveyed by the high-level description. That matters because command-line and file-driven interfaces can be abused or misused if users think they are invoking only a conversational writing helper.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

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

md
Do not pretend balance just to sound polite.
If the material is weak, say it is weak and explain why.

## Default concise-output rule

Across the entire workflow, default to concise, high-density answers.
Unless the user explicitly asks for expansion, explanation, or detail, respond in the shortest form that still contains real value.

Memory Manipulation

High
Category
Memory Poisoning
Confidence
85% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · references/subagent-drafting.md (reported line 16)May include surrounding context.

md
- `must-not-modify list` must exactly equal the baseline snapshot minus `target files`
- no planning, recap, review, or state writes

## Overwrite Rule
- existing target files stay read-only unless parent sets `overwrite=true`
- fail closed when overwrite permission is missing or ambiguous
- this template assumes `overwrite=true` reflects an explicit parent-approved dispatch decision for the current target files

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

The script passes dynamically constructed commands into a shell, creating a tool-parameter abuse pathway where attacker-controlled or user-supplied values can alter the executed command. This is especially risky because the skill optionally syncs project content to Feishu and accepts command-line input for project paths and titles, increasing the chance that untrusted data reaches the shell boundary.

Content

Scanner excerpt · scripts/sync_to_feishu_wiki.py (reported line 9)May include surrounding context.

python
def run(cmd):
    p = subprocess.run(cmd, shell=True, text=True, capture_output=True)
    if p.returncode != 0:
        raise RuntimeError(f'cmd failed: {cmd}\nstdout={p.stdout}\nstderr={p.stderr}')
    lines = [ln for ln in p.stdout.splitlines() if not ln.startswith('[lark-claw]')]

Static analysis

No suspicious patterns detected.