Back to skill

Security audit

Nika Skill Creator

Security checks for vulnerabilities and agentic risk

Overview

This is mostly a straightforward Nika skill generator and validator, but it needs review because its helper script can write or overwrite files in user-selected filesystem locations.

Review before installing if you expect strict containment. Use it only in a workspace where creating Nika skill Markdown files is intended, avoid --force unless you have checked the exact destination, and do not pass absolute or parent-traversal output directories. No evidence of network access, credential theft, hidden execution, or backdoor persistence was found.

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
scripts/init_nika_skill.py:34
Finding
Unrestricted Filesystem Writes and Symbolic-Link Following## Vulnerability Details **File Location**: `scripts/init_nika_skill.py`, lines 34-37 and 157-184 **Vulnerability Type**: Unrestricted filesystem write and symbolic-link traversal **Risk Level**: Medium ### Vulnerable Code ```python def _write_text(path: Path, content: str, *, force: bool) -> None: if path.exists() and not force: _die(f"refusing to overwrite existing file: {path}") path.parent.mkdir(parents=True, exist_ok=True) path.write_text(content, encoding="utf-8") ``` ```python parser.add_argument("--out-dir", default="skills", help="Output base directory (default: skills).") parser.add_argument( "--subdocs", default=None, help="Comma-separated list of sub doc names (default: 步骤,模板,示例).", ) parser.add_argument( "--force", action="store_true", help="Overwrite existing files if they already exist.", ) args = parser.parse_args(argv) skill_name_cn = args.skill_name_cn _validate_name(skill_name_cn) out_dir = Path(args.out_dir) subdocs = _parse_subdocs(args.subdocs) for s in subdocs: _validate_name(s) skill_dir = out_dir / skill_name_cn main_doc = skill_dir / "SKILL.md" refs_dir = skill_dir / "references" refs_dir.mkdir(parents=True, exist_ok=True) _write_text(main_doc, _main_doc_content(skill_name_cn, subdocs), force=args.force) created: list[Path] = [main_doc] for s in subdocs: p = refs_dir / f"{s}.md" _write_text(p, _subdoc_content(s), force=args.force) created.append(p) ``` ### Technical Analysis The `--out-dir` argument is converted directly into a `Path` without canonicalization or verification that the resulting destination remains inside the repository or another approved output root. It can therefore contain an absolute path or traversal components such as `../`. The write operation uses `Path.write_text()`, which follows symbolic links. The code checks whether the destination exists but does no ...[truncated 2482 chars]
Remediation
## Remediation Suggestions 1. Establish an explicit trusted output root, preferably derived from the repository location rather than the current working directory. 2. Resolve both the trusted root and proposed destination with `Path.resolve()` and reject any destination that is not contained within the trusted root. 3. Reject absolute `--out-dir` values and traversal outside the approved root unless external output is an explicitly documented feature protected by a separate opt-in. 4. Inspect every existing destination component with `lstat()` and reject symbolic links, including the destination file and all parent directories. 5. Use exclusive file creation for normal operation, such as mode `x`, so an existing path cannot be replaced accidentally. 6. For intentional overwrite behavior, open files using platform-appropriate no-follow protections such as `O_NOFOLLOW`, verify the opened object's type with `fstat()`, and write through the validated file descriptor. 7. Avoid check-then-write logic because it is vulnerable to time-of-check/time-of-use races. Perform validation and secure opening atomically wherever the operating system permits. 8. Add automated tests covering absolute output paths, `../` traversal, symlinked output directories, symlinked destination files, dangling symlinks, and `--force` behavior.
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims to create, update, refactor, and validate Nika skills, but the documented behavior appears more limited and specialized, especially around local directory validation and repository-specific constraints. This inconsistency is dangerous because users may trust it to safely perform broader transformations while it actually enforces opaque repo rules or fails to deliver the promised behavior, creating integrity and workflow risks.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims to create, update, refactor, and validate Nika skills, but the documented behavior appears more limited and specialized, especially around local directory validation and repository-specific constraints. This inconsistency is dangerous because users may trust it to safely perform broader transformations while it actually enforces opaque repo rules or fails to deliver the promised behavior, creating integrity and workflow risks.

Self-Modification

High
Category
Rogue Agent
Content
def _write_text(path: Path, content: str, *, force: bool) -> None:
    if path.exists() and not force:
        _die(f"refusing to overwrite existing file: {path}")
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content, encoding="utf-8")
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.

Self-Modification

High
Category
Rogue Agent
Content
parser.add_argument(
        "--force",
        action="store_true",
        help="Overwrite existing files if they already exist.",
    )

    args = parser.parse_args(argv)
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.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill instructs use of local file read/write operations via repository scripts, but it does not declare any explicit tool scope or permission boundaries. This is dangerous because an agent may perform filesystem actions without clear user-visible authorization constraints, increasing the chance of unintended file modification or overbroad access.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The manifest description says to use the skill when a user asks to 'make a Nika skill, refactor an existing one to Nika format, or validate a Nika skill draft,' but it does not define explicit trigger phrases, exclusions, or boundaries for when this skill should not activate. This creates ambiguity because several common documentation or refactoring requests could plausibly match the description.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill states that the default behavior is to generate or update repository content, but it does not require an explicit warning or confirmation before writing files. This is dangerous because users may intend to get draft text only, yet the skill's default behavior can cause unintended persistent modifications to the local repository.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The template explicitly requires Chinese in the skill name and description fields, as shown by '中文' and the surrounding Chinese-only instructional text. This is a natural-language policy concern because it imposes a specific language/locale without any opt-in, alternative, or justification that the template is region-specific.

Natural-Language Policy Violations

Medium
Confidence
82% confidence
Finding
The entire specification is written as mandatory constraints for target skills and consistently requires compliance in Chinese, but it does not state that language choice is optional or that the constraint is limited to a justified Chinese-only environment. Under the policy, forcing a specific language without user opt-in can be a natural-language policy violation.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This markdown file is natural-language guidance and it fixes the operating language to Chinese throughout the document. Under the language/locale policy, forcing a specific language without an explicit user choice or documented justification is a policy concern.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The comment at L052 states a concrete constraint for generated content, yet the template includes text such as "不要出现文件路径或文件扩展名的引用形式" and table columns referring to recommended file names and naming patterns. More importantly, the CLI advertises `references/*.md`, showing the produced skeleton is not consistently enforcing the documented constraint.

Intent-Code Divergence

Medium
Confidence
94% confidence
Finding
The argparse description says the script initializes a "Nika-compliant" skill skeleton, while the generated template later instructs users with examples like `references/*.md`, "文件路径", and "文件扩展名" handling. This is not merely incomplete documentation: the code's own output violates the stated no path/extension reference constraint described both in the manifest and in `_main_doc_content` comments.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
This code hard-codes Chinese as the required skill name language and defaults generated subdocument names and template text to Chinese. The generated SKILL.md content also contains only Chinese instructions, which imposes a specific language/locale rather than offering a choice.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This Python file enforces the presence of Chinese-only section keywords ("必要输入" and "交付物") and elsewhere uses Chinese-only allowed reference names, which creates a language constraint in the skill validation logic. The file does not indicate that this skill is intentionally region- or locale-specific, nor does it provide any user opt-in or alternative language handling.

Natural-Language Policy Violations

Low
Confidence
82% confidence
Finding
The instructional content from line 8 onward is presented entirely in Chinese, but the skill does not indicate that language selection is optional or limited to a Chinese-speaking context. This can violate language/locale policy expectations when users have not opted into a specific language.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The line '中文优先' directs authors to prefer Chinese for subdocument names, which is a natural-language locale policy constraint. The file does not offer a language choice or explain a region-specific reason for this requirement, so it appears to impose a language preference by default.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The script writes multiple files and can overwrite existing files when --force is used. Although it logs written paths after completion and refuses overwrite by default, there is no explicit warning or confirmation at the point where destructive overwrite may occur.

Static analysis

No suspicious patterns detected.