Back to skill

Security audit

story-engine-for-creator

Security checks for vulnerabilities and agentic risk

Overview

Review is warranted because accepting one edit can change rejected dialogue, and the audit hashes can overlook content changes.

Keep manuscript backups and inspect the complete diff before adopting repairs, because rejected dialogue can still change. Do not rely on these hashes as proof that report content is unchanged. Choose unused output filenames. Enable an external provider only when you approve sending story content and settings to its endpoint. The Review verdict rests on reproduced editing and integrity defects, not the scanner's score.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (13)

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Most visible functionality aligns with the declared narrative-tool purpose. However, OpenAIProvider.generate performs authenticated HTTP POST requests to /chat/completions, defaulting to api.openai.com. Configuring a provider enables generation and repair workflows and can also introduce network calls into audit_text through deep diagnosis and prose checking. These are conditional capabilities, not automatic import-time transmissions, but they materially expand both data access and determinism beyond the description. Local configuration reads and report writes are supporting implementation details and are not independently flagged. The supplied chunk is truncated, so the presence of every other advertised feature cannot be established.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The explicit call to self.llm_provider.generate(prompt, temperature=0.2, max_tokens=800) makes an audit result depend on a generative provider rather than exclusively deterministic validators. Its response directly controls the reported pass status, violations, and score; deterministic checking is only the exception fallback. The provider implementation is not supplied, so remote transmission cannot be confirmed. The remaining visible functionality generally supports the declared narrative-tool purpose, and features absent from this partial chunk are not treated as mismatches.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
MCP Tool Poisoning
Confidence
84% confidence
Finding

Most visible operations match the declared narrative-generation and auditing purpose. However, attaching a real external LLM introduces an undisclosed external-service capability and potentially nondeterministic processing beyond the stated deterministic functionality. The snippet proves provider configuration, not that a network request occurs or that chapter text is transmitted; those details depend on the unavailable implementation.

Content

No source excerpt is available for this finding.

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

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 manifest promises deterministic operation, but audit hashes vary across repeated audits of identical text.

Medium
Category
Excessive Agency
Confidence
97% confidence
Finding

L55 explicitly documents that UUID-derived report fields enter the hash payload, causing identical text to produce different audit hashes on repeated runs. L77 confirms this behavior experimentally. This conflicts with the manifest's deterministic-tool claim, although nondeterminism alone does not establish that the hash chain lacks integrity.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
# v2.3: attach a real LLM (any OpenAI-compatible API, zero external deps)
from scripts.story_engine import OpenAIProvider
engine.set_llm_provider(OpenAIProvider(api_key="sk-...", model="gpt-4o",
                                       base_url="https://api.openai.com/v1"))
# v2.3: single-chapter real-time gatekeeping (skips global recomputation)
quick = engine.audit_text("Chapter content", diff_only=True)
# v2.3: foreshadow + spacetime + hash-chain fields

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/story_engine.py (reported line 96)May include surrounding context.

python
Args:
        api_key:   API 密钥。
        model:     模型名称,如 "gpt-4o"、"deepseek-chat"。
        base_url:  API 基础地址,默认 "https://api.openai.com/v1"。
        timeout:   请求超时(秒)。
    """

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/story_engine.py (reported line 104)May include surrounding context.

python
self,
        api_key: str,
        model: str = "gpt-4o",
        base_url: str = "https://api.openai.com/v1",
        timeout: int = 120,
    ):
        self.api_key = api_key

Hash normalization removes substantive content despite documentation promising to preserve content fields.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

_strip_nondeterminism replaces every dictionary value matching eight lowercase hexadecimal characters, regardless of whether the field contains a generated identifier or substantive story content. Consequently, different substantive values such as 'deadbeef' and 'cafebabe' can produce identical normalized payloads and audit hashes, undermining the advertised tamper-evidence without breaking SHA-256.

Content

No source excerpt is available for this finding.

The advertised deterministic tool includes optional remote, probabilistic LLM processing of story content.

Medium
Category
Excessive Agency
Confidence
96% confidence
Finding

The manifest describes a deterministic plot architecture tool but does not disclose external LLM processing. Configuring a provider propagates it to causal, worldbuilding, and prose auditors; these send story content and world rules for probabilistic analysis (L2537–L2554, L3276–L3288), and OpenAIProvider transmits prompts over HTTP (L0120–L0139). This behavior is opt-in, but materially changes both the stated determinism and the data-processing boundary.

Content

No source excerpt is available for this finding.

generate_novel silently creates or overwrites an HTML report file without disclosing the filesystem write.

Medium
Category
Output Handling
Confidence
90% confidence
Finding

The novel-generation method opens output_path in write mode, truncating any existing file at that location. Unlike the explicitly documented export helpers, this method has no confirmation, log, docstring, or comment explaining that generating a novel also writes an audit report to disk.

Content

No source excerpt is available for this finding.

Selective review acceptance can modify dialogue belonging to rejected or unrelated issues.

Medium
Category
Excessive Agency
Confidence
99% confidence
Finding

For every accepted issue, apply_review can mask all dialogues containing forbidden words whenever characters are provided, even when the accepted issue is unrelated to dialogue. Global replacement also affects multiple occurrences, so accepting one edit can modify content associated with rejected issues, violating the author's selective-approval boundary and potentially destroying manuscript information in the returned text.

Content

No source excerpt is available for this finding.

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/story_engine.py (reported line 1819)May include surrounding context.

python
obj: Any = self.global_state
        for part in parts[:-1]:
            if hasattr(obj, part):
                obj = getattr(obj, part)
            elif isinstance(obj, dict):
                obj = obj.setdefault(part, {})
            elif isinstance(obj, list) and part.lstrip("-").isdigit():