Back to skill

Security audit

Deep modules for agent-native codebases

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent codebase-refactoring aid, but its bundled optional scaffolding script has unsafe path and input handling that could write files outside a repository or generate injectable source code if misused.

Install only if you are comfortable treating this as a planning/refactoring aid and avoid running the bundled scaffold script on untrusted names or automated metadata. If you use the script, pass simple lowercase kebab-case module names, keep paths repository-relative, and review generated files before running tests or builds.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scaffold_deep_module.py:28
Finding

Repository Root Escape Through Unvalidated Scaffold Paths

Content
View full analysis
None: path.parent.mkdir(parents=True, exist_ok=True) if path.exists(): # Don't clobber existing work. return path.write_text(content, encoding="utf-8") ``` ```python def main(argv: list[str]) -> int: parser = argparse.ArgumentParser() parser.add_argument("--name", required=True, help="Module name (kebab-case recommended).") parser.add_argument("--lang", choices=["ts", "py"], required=True, help="Language template to use.") parser.add_argument("--base-dir", default="src", help="Base directory inside repo (default: src).") parser.add_argument("--root", default=".", help="Repo root (default: current directory).") args = parser.parse_args(argv) root = Path(args.root).resolve() base_dir = root / args.base_dir if args.lang == "py": # Python packages must be valid identifiers; normalise kebab-case to snake_case. package_name = args.name.replace("-", "_") module_dir = base_dir / package_name created = scaffold_py(module_dir, package_name=package_name, display_name=args.name) else: module_dir = base_dir / args.name created = scaffold_ts(module_dir, args.name) ``` ### Technical Analysis The user-controlled `--base-dir` and `--name` arguments are combined with the repository root without validating that the resulting path remains inside that root. `Path` accepts traversal components such as `..`; additionally, joining an absolute path can discard the preceding base path. The resulting destinations are passed to `_write()`, which recursively creates parent directories and writes generated source files. No resolved-path containment check is performed before these filesystem oper ...[truncated 1387 chars]
Remediation
View remediation
Path: root = root.resolve() destination = destination.resolve() if not destination.is_relative_to(root): raise ValueError(f"Destination escapes repository root: {destination}") return destination ``` 5. Apply the containment check to `base_dir`, `module_dir`, and every path passed to `_write()`. 6. Consider requiring `--base-dir` to be selected from known repository-relative locations such as `src` or `packages`. 7. Preserve the existing no-overwrite behavior and report skipped files separately from newly created files. 8. Add regression tests covering absolute paths, nested `../` traversal, traversal through `--name`, and valid repository-relative destinations. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scaffold_deep_module.py:37
Finding

Generated Source-Code Injection Through Unsanitized Module Names

Content
View full analysis
list[Path]: created: list[Path] = [] index_ts = module_dir / "index.ts" types_ts = module_dir / "types.ts" public_api_ts = module_dir / "internal" / "public-api.ts" test_ts = module_dir / "__tests__" / f"{name}.contract.test.ts" _write( types_ts, f"""// Public types for the `{name}` module. export type {to_pascal(name)}Error = | {{ type: "not-implemented" }}; """, ) ``` The Python templates place attacker-controlled values into a module docstring and executable import statement: ```python def scaffold_py(module_dir: Path, package_name: str, display_name: str) -> list[Path]: created: list[Path] = [] init_py = module_dir / "__init__.py" types_py = module_dir / "types.py" public_api_py = module_dir / "internal" / "public_api.py" test_py = module_dir / "tests" / f"test_{package_name}_contract.py" type_name = to_pascal(display_name) + "Error" _write( types_py, f"""\"\"\"Public types for the `{display_name}` module.\"\"\" from __future__ import annotations from typing import Literal, TypedDict, Union class NotImplementedErrorType(TypedDict): type: Literal["not-implemented"] {type_name} = Union[NotImplementedErrorType] """, ) ``` ```python _write( test_py, f"""from {package_name} import not_implemented_yet def test_not_implemented_yet_returns_structured_error(): result = not_implemented_yet() assert result["ok"] is False assert result["error"]["type"] == "not-implemented" """, ) ``` The input is only partially transformed before interpolation: ```python if arg ...[truncated 2788 chars]
Remediation
View remediation
str: if not MODULE_NAME.fullmatch(name): raise ValueError( "Module name must contain only lowercase letters, digits, and single hyphens" ) return name ``` 2. Derive language-specific identifiers only after validation: - Python: convert hyphens to underscores, then require `package_name.isidentifier()` and reject Python keywords. - TypeScript: derive a valid identifier separately and verify that it is nonempty. 3. Explicitly reject line breaks, carriage returns, control characters, quotes, backticks, path separators, and comment delimiters. 4. Avoid placing raw user-controlled display text in executable source templates. If descriptive text is necessary, escape it using a language-aware string encoder. 5. Generate Python string literals with a safe serializer such as `repr()` rather than direct interpolation. 6. Keep filesystem names, source identifiers, and human-readable display names as separate validated values. 7. Add tests using malformed names containing newlines, quotes, triple quotes, backticks, comment delimiters, slashes, dots, spaces, and language keywords. 8. Document that scaffold arguments must not be sourced from untrusted metadata unless validation has already occurred. ]]>
Vulnerability Patterns
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (1)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill clearly instructs the agent to inspect repositories and produce move plans, refactor steps, and optional skeletons, which implies file write capability may be used during execution. Because the skill does not declare any explicit tool scope or allowed tools, an integrating assistant may grant broader-than-necessary access, increasing the chance of unintended repository modification or misuse if the skill is invoked in an unsafe context.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.