Back to skill

Security audit

mumu-ai-novel

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real MuMu novel automation skill, but it needs review because it can publish or overwrite chapters and has under-protected API authentication/session handling.

Install only if you trust the MuMu API endpoint and are comfortable giving this skill authority to generate, rewrite, and publish chapters. Configure explicit credentials, use HTTPS for any non-local endpoint, avoid MUMU_SESSION_FILE in shared directories, and manually review target chapter IDs and content before running approve or rewrite commands.

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/client.py:6
Finding

Credentials and authenticated traffic can be transmitted over plaintext HTTP

Content
View full analysis

Vulnerability Details

File Location: scripts/client.py, lines 6-9 and 74-79
Vulnerability Type: Plaintext transmission of credentials and insecure default credentials
Risk Level: High

Vulnerable Code

python
MUMU_API_URL = os.getenv("MUMU_API_URL", "http://localhost:8000").rstrip("/")
MUMU_USERNAME = os.getenv("MUMU_USERNAME", "admin")
MUMU_PASSWORD = os.getenv("MUMU_PASSWORD", "admin123")
DEFAULT_TIMEOUT = float(os.getenv("MUMU_HTTP_TIMEOUT", "60"))
python
def login(self):
    url = f"{MUMU_API_URL}/api/auth/local/login"
    data = {
        "username": MUMU_USERNAME,
        "password": MUMU_PASSWORD
    }
    resp = self.session.post(url, json=data, timeout=DEFAULT_TIMEOUT)

Technical Analysis

The API URL is fully controlled through MUMU_API_URL, but the client does not validate its scheme or restrict plaintext HTTP to loopback addresses. The login function sends the configured username and password directly to that destination as JSON.

Although the default URL points to localhost, an operator may configure a remote HTTP endpoint. In that configuration, credentials, session cookies, project content, chapter rewrites, lore, and other API traffic lack transport confidentiality and integrity. A network-positioned attacker can observe or alter the traffic.

The hardcoded fallback credentials (admin / admin123) are an additional insecure default. If the corresponding server retains these credentials, an attacker may authenticate without learning an operator-defined secret.

This network communication is necessary for the declared MuMu API integration, but permitting unencrypted remote authentication and supplying predictable fallback credentials exceed safe minimum requirements.

Attack Path

  1. The Skill is deployed with a remote plaintext URL such as MUMU_API_URL=http://api.example.test:8000.
  2. The operator invokes any script that constructs MumuClient.
  3. The client first checks `/api/users/m ...[truncated 1151 chars]
Remediation
View remediation

Remediation Suggestions

  1. Require https:// for every non-loopback API endpoint.
  2. Permit http:// only for explicit loopback destinations such as localhost, 127.0.0.1, and ::1.
  3. Reject unsupported schemes, embedded URL credentials, and malformed destinations before creating a client.
  4. Remove the admin and admin123 fallbacks. Fail closed when credentials are not explicitly configured.
  5. Prefer short-lived API tokens or scoped service credentials over reusable account passwords.
  6. Preserve TLS certificate verification and do not add a configuration option that silently disables it.
  7. Document that the Skill transmits novel content and authentication information to the configured MuMu API.
  8. Rotate any credentials that may already have been used over plaintext HTTP.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/client.py:57
Finding

Authentication cookies are persisted without restrictive file protections

Content
View full analysis

Vulnerability Details

File Location: scripts/client.py, lines 57-64
Vulnerability Type: Insecure storage of authentication material
Risk Level: Medium

Vulnerable Code

python
def _save_cookies(self):
    session_file = get_session_file()
    if not session_file:
        return
    cookies_dict = self.session.cookies.get_dict()
    session_file.parent.mkdir(parents=True, exist_ok=True)
    session_file.write_text(json.dumps(cookies_dict))

Technical Analysis

When MUMU_SESSION_FILE is configured, the client serializes all session cookies to the selected path using Path.write_text(). The implementation does not explicitly enforce owner-only permissions, validate the ownership or permissions of an existing file, prevent symbolic-link traversal, or use secure atomic replacement.

For a newly created file, effective permissions depend on the process umask and may allow other local users to read the cookie data. If the destination already exists, its previous permissions remain relevant. Because the code follows symbolic links, an attacker who can prepare the configured path or its parent directory may redirect the write to another file accessible to the Skill process.

Session persistence is optional and supports legitimate repeated API use, but retaining authorization cookies requires stronger controls than ordinary project-state storage.

Attack Path

  1. MUMU_SESSION_FILE is configured to point into a shared or insufficiently protected directory.
  2. The client successfully authenticates to the MuMu API.
  3. _save_cookies() writes the authorization cookies without setting mode 0600.
  4. Another local user reads the file and obtains the session cookies.
  5. That user supplies the cookies to the MuMu API and acts as the authenticated account.

For a write-redirection variant:

  1. An attacker with access to the session file's parent directory creates a symbolic link at the configured path.
  2. The Skill logs in and ...[truncated 668 chars]
Remediation
View remediation

Remediation Suggestions

  1. Store session data in a private directory with mode 0700.
  2. Create the session file with owner-only mode 0600, independent of the process umask.
  3. Reject symbolic links and non-regular files. On supported platforms, use O_NOFOLLOW.
  4. Write to a securely created temporary file in the same private directory, flush it, set mode 0600, and atomically replace the destination.
  5. Verify that an existing session file and its parent directory are owned by the expected user.
  6. Avoid persisting cookies unless explicitly requested.
  7. Consider using the operating system's credential store instead of a plaintext JSON file.
  8. Invalidate exposed sessions and rotate associated credentials after fixing the storage mechanism.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/runtime_state.py:16
Finding

Unvalidated project identifiers can escape the runtime-state directory

Content
View full analysis

Vulnerability Details

File Location: scripts/runtime_state.py, lines 16-17, 38-53, and 57-61
Vulnerability Type: Path traversal leading to file overwrite or deletion
Risk Level: High

Vulnerable Code

python
def get_state_path(project_id):
    return get_runtime_dir() / f"{project_id}.json"
python
def save_state(project_id, payload):
    path = get_state_path(project_id)
    path.parent.mkdir(parents=True, exist_ok=True)
    data = dict(payload)
    data.setdefault("project_id", project_id)
    data.setdefault("owner_id", get_owner_id())
    data.setdefault("runner_id", new_runner_id())
    data.setdefault("updated_at", time.time())
    fd, tmp_path = tempfile.mkstemp(prefix=path.name, dir=str(path.parent))
    try:
        with os.fdopen(fd, "w") as handle:
            json.dump(data, handle, ensure_ascii=False)
        os.replace(tmp_path, path)
    finally:
        if os.path.exists(tmp_path):
            os.unlink(tmp_path)
    return data
python
def clear_state(project_id):
    path = get_state_path(project_id)
    try:
        path.unlink()
    except FileNotFoundError:
        pass

Technical Analysis

project_id is incorporated directly into a filesystem path without validating its format. A value containing ../ components can traverse outside .mumu_runtime. Under pathlib, an absolute right-hand operand can also replace the intended base directory entirely.

save_state() creates parent directories and atomically replaces the resulting path, while clear_state() unlinks it. Consequently, a crafted identifier can target an unintended .json file anywhere writable by the process.

The normal CLI flow performs API requests before many state operations, which limits straightforward exploitation against a trusted server because the server must accept or return the crafted project reference. The issue remains exploitable when the configured API is malicious or compromised, when it accepts non ...[truncated 1574 chars]

Remediation
View remediation

Remediation Suggestions

  1. Validate project_id against the service's exact identifier format, such as a canonical UUID or a strict alphanumeric pattern.
  2. Reject absolute paths, path separators, . and .. components, null bytes, and identifiers outside an established length limit.
  3. Resolve both the runtime directory and destination path, then verify that the destination remains a direct child of the runtime directory.
  4. Avoid using external identifiers as filenames. A safer option is a fixed-length cryptographic hash of the project identifier.
  5. Configure the runtime directory with mode 0700 and state files with mode 0600.
  6. Apply the same validation before load, save, and delete operations.
  7. Do not create arbitrary parent directories derived from a project identifier.
  8. Add tests covering absolute paths, traversal sequences, alternate separators, malformed Unicode, and excessively long identifiers.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
96% confidence
Finding

The description claims a broader showrunner/editor role after project binding or initialization: batch generation, RAG-based plot consistency auditing, and scheduled chapter correction. The supplied code only manages project setup and binding-related operations. It creates a new project through a staged wizard, resumes or advances initialization stages, checks readiness/status, lists existing projects, and binds a writing style. These are materially narrower and different from the declared ongoing editorial/showrunner functions. While 'initialize your connection by creating or binding a novel' is partially represented, the main declared capabilities after that are absent, and several actual capabilities (project/style listing and binding) are undeclared. Therefore this is a clear description-behavior mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broad orchestration/editor workflow for a novel project, including project binding, generation management, RAG auditing, and correction. The supplied code chunk only fetches and displays status information for a batch generation job through chapters/batch-generate/{batch_id}/status. While status checking could be a minor supporting feature of batch generation management, this chunk by itself does not implement the core declared functions and has a materially narrower primary purpose than advertised.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description presents a multi-function showrunner/editor skill for managing a novel project end-to-end: binding a novel, generating content in batches, auditing plot consistency via RAG, and correcting chapters on a schedule. The supplied code chunk is much narrower. It is a single CLI utility focused on one read-oriented action: querying foreshadows/projects/{project_id}/pending-resolve with current_chapter=1 and printing unresolved foreshadow items. While unresolved foreshadow retrieval may be loosely related to plot consistency review, it is only a small subset of the declared functionality and not an accurate representation of the primary purpose described. Therefore, the description materially overstates and mischaracterizes what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The declared description promises a broader editorial orchestration tool: initialize/bind a novel, generate batches, audit plot consistency using RAG, and correct chapters on a schedule. The supplied code only reads chapters from a project endpoint, selects likely review candidates based on status and word count, and prints chapter metadata plus short content previews. There is no generation, retrieval-augmented analysis, correction/editing, scheduling, or deep world-building logic. While it does operate on novel project chapters, its actual purpose is a simple fetch/report utility, which is materially narrower and different from the declared skill behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The declared description presents a broader end-to-end novel management/editor workflow: bind a novel, run batch generation, audit consistency via RAG, and correct chapters on a schedule. The supplied code only performs one narrower function: it calls an outline-generation endpoint for an already identified project and streams status/results. While outline generation is related to novel production, the primary behavior here is materially narrower than the declared purpose, and several major claimed capabilities are absent.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The declared description presents a broad orchestration/editor skill for a novel project, including initialization/binding, batch generation, RAG-based plot auditing, and scheduled chapter correction. The supplied code chunk does something much narrower: it parses CLI arguments and, for the sole supported action add_foreshadow, posts a foreshadow record to a project backend. This is related to novel memory/RAG support, but it does not realize the primary capabilities described. The code's actual purpose is limited memory/foreshadow management, so the description materially overstates and misrepresents what this code chunk actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code’s behavior is focused on one operational task: taking existing outlines in a project that lack chapters, expanding them through a streaming API, and creating chapter placeholders from the resulting plans. While this loosely relates to 'drive batch generation,' it does not cover several central parts of the declared description: binding/initializing a novel, auditing plot consistency via RAG, or correcting chapters on a scheduled basis. The declared purpose presents a broader orchestration/editor capability, whereas the code is a specific batch materialization utility. Therefore the description does not accurately represent the actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The description presents a broad orchestration skill for a novel project: initialize/bind a novel, drive batch generation, perform RAG-based plot consistency audits, and correct chapters on a schedule. The supplied code does something much narrower: it parses CLI arguments, reads replacement chapter text from content/file/stdin, and uses MumuClient to update a single chapter's status to published or overwrite its content and publish it. While this is loosely related to chapter editing/review in a novel workflow, it does not implement the major advertised capabilities such as batch generation, RAG auditing, scheduling, or broader project/showrunner functions. Therefore the declared description materially overstates and misrepresents the actual behavior.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a high-level fiction showrunner/editor capability for managing a novel project and performing generation, auditing, and correction tasks. The provided code does none of that directly. Instead, it implements generic runtime state persistence: computing a runtime directory, reading/writing project JSON files, assigning owner/runner IDs, clearing state, and checking whether saved state is stale. While state management could be a supporting detail for a larger novel tool, this chunk’s actual purpose is materially different from the declared end-user behavior, and it introduces undeclared filesystem access and environment-based configuration. Therefore this code chunk does not accurately represent the declared skill behavior on its own.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The description promises a broader novel-management skill that can initialize/bind a novel, run batch generation, audit plot consistency via RAG, and correct chapters on a schedule. The supplied code only covers one slice of that workflow: triggering batch generation for existing empty draft chapters and optionally polling the batch job status. It reads project and chapter metadata and posts to a batch-generate endpoint, but there is no code for binding/initializing projects, no RAG or consistency auditing logic, no chapter correction/editing, and no scheduler or trigger behavior. This is therefore a material description-to-behavior mismatch, with the actual code being a much narrower batch-generation utility.

Content

No source excerpt is available for this finding.

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/bind_project.py (reported line 376)May include surrounding context.

python
stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
        start_new_session=True,
        env=os.environ.copy(),
    )
    return proc.pid

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
args = parser.parse_args()
    client = MumuClient(project_id=args.project_id, style_id=getattr(args, 'style_id', None))
    if not client.project_id:
        print("Error: --project_id argument is required or must be set in .env")
        return
    
    if args.action == "list-pending":

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

python
def set_project_id(self, project_id: str):
        self.project_id = project_id
        # Removed writing to .env to allow multi-agent concurrency in the same workspace.
        # Agents will must remember this ID and pass it via --project_id <ID> to scripts.
        print(f"[System] MUMU_PROJECT_ID 绑定成功,当前 Agent 需记住此 ID -> {project_id}")

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

python
def set_project_id(self, project_id: str):
        self.project_id = project_id
        # Removed writing to .env to allow multi-agent concurrency in the same workspace.
        # Agents will must remember this ID and pass it via --project_id <ID> to scripts.
        print(f"[System] MUMU_PROJECT_ID 绑定成功,当前 Agent 需记住此 ID -> {project_id}")

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill declares broad operational behavior involving shell, environment variables, filesystem interaction, and likely network-backed scripts, but it does not define any explicit tool scope such as permissions or allowed-tools. In a shared agent runtime, this increases the chance the skill is invoked with more capability than users expect, enabling unintended command execution, data access, or outbound requests.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill instructs the agent to perform a rewrite operation that 'officially overwrites the chapter and publishes it' without a strong confirmation or safety warning. In an autonomous or semi-autonomous agent context, this can cause irreversible content loss or unauthorized publication through a single command, especially if the agent misidentifies the target chapter or is prompt-manipulated.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The code sets the default narrative_perspective to "第三人称", which forces a Chinese-language value when none is provided. This is a natural-language locale choice embedded in behavior, and the file does not offer a user language/locale option or explain why the constraint is required.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The create flow always sends "第三人称" for narrative_perspective, which imposes a specific language/locale choice regardless of user preference. Under the policy, locale-specific behavior should be optional or explicitly justified.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.