Back to skill

Security audit

ZipCracker

Security checks for vulnerabilities and agentic risk

Overview

This ZIP recovery skill has a coherent authorized-use purpose, but its extraction and optional dependency-install paths create high-impact filesystem and supply-chain risks.

Review before installing. Use this only for CTFs, owned archives, or explicitly authorized recovery, preferably in a disposable workspace or container. Avoid --allow-install-prompts unless you accept mutable dependency downloads, preinstall pinned dependencies where possible, and do not point --out at an existing important directory until the extraction cleanup and path traversal issues are fixed.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/zipcracker_core.py:2790
Finding
User-Controlled Output Path Enables Recursive Deletion of Arbitrary Directories## Vulnerability Details **File Location**: `scripts/zipcracker_core.py`, lines 2790-2796; user-controlled value assigned at lines 4320-4331 **Vulnerability Type**: Unrestricted recursive filesystem deletion **Risk Level**: High ### Vulnerable Code ```python def _clean_and_create_outdir(out_dir: str) -> None: if os.path.exists(out_dir): try: shutil.rmtree(out_dir) except Exception: pass os.makedirs(out_dir, exist_ok=True) ``` The deleted path comes directly from the command-line argument: ```python if arg in ("-o", "--out"): if index + 1 >= len(sys.argv): print( loc( locale, "[!] Error: No directory name provided after -o.", "[!] Error: No directory name provided after -o.", ) ) return 1 out_dir = sys.argv[index + 1] index += 2 ``` ### Technical Analysis The `-o` or `--out` option accepts an unrestricted path. Before extraction, `_clean_and_create_outdir()` recursively deletes that path with `shutil.rmtree()`. The code does not: - Canonicalize the destination before deletion. - Require the destination to be a dedicated ZipCracker directory. - Reject filesystem roots, home directories, the current working directory, or project directories. - Check for a tool-created ownership marker. - Request confirmation before deleting an existing directory. - Prevent paths containing symbolic-link-based redirections in parent components. This behavior is not required for ZIP recovery. Creating a new output directory or refusing to overwrite an existing directory would provide the declared functionality with substantially lower privileges. ### Attack Path 1. An attacker influences a natural-language request or generated command so that it includes a sensitive destination, such as `-o .`, `-o /home/user`, or another writable directory. ...[truncated 835 chars]
Remediation
## Remediation Suggestions - Resolve the requested destination with `Path.resolve()` before performing any filesystem operation. - Reject filesystem roots, drive roots, user home directories, the current working directory, the archive's parent directory, and the Skill installation directory. - Default to a newly created, unique directory rather than deleting an existing one. - Refuse to overwrite a non-empty existing directory unless the user provides a separate explicit destructive flag. - Place a ZipCracker ownership marker inside directories created by the tool and only permit automatic cleanup when that marker is present and valid. - Check every parent component for symbolic links before recursive deletion. - Do not suppress deletion exceptions; report the failure and stop extraction. - Consider using `tempfile.mkdtemp()` followed by an atomic rename into a previously nonexistent destination.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/zipcracker_core.py:2675
Finding
ZIP Member Path Traversal in Per-Entry bkcrack Extraction## Vulnerability Details **File Location**: `scripts/zipcracker_core.py`, lines 2675-2745 **Vulnerability Type**: Directory traversal and arbitrary file overwrite **Risk Level**: High ### Vulnerable Code ```python def extract_with_bkcrack_keys( bk: str, keys: tuple[str, str, str], zip_path: str, out_dir: str, locale: str, ) -> tuple[bool, list[str] | str]: k0, k1, k2 = keys _clean_and_create_outdir(out_dir) extracted_names: list[str] = [] try: with zipfile.ZipFile(zip_path, "r") as zf: infos = [info for info in zf.infolist() if is_regular_member(info)] for info in infos: dest_path = os.path.join(out_dir, info.filename) parent_dir = os.path.dirname(dest_path) if parent_dir: os.makedirs(parent_dir, exist_ok=True) if info.flag_bits & 0x1: with tempfile.NamedTemporaryFile( prefix="zipcracker_bkcrack_entry_", suffix=".bin", delete=False, ) as tmp: tmp_path = tmp.name try: proc = subprocess.run( [ bk, "-k", k0, k1, k2, "-C", zip_path, "-c", info.filename, "-d", tmp_path, ], capture_output=True, text=True, timeout=None, ) ...[truncated 3212 chars]
Remediation
## Remediation Suggestions - Reject absolute member paths, drive-qualified paths, NUL characters, and any path containing a `..` component. - Normalize path separators for both POSIX and Windows semantics before validation. - Resolve the output root and candidate destination, then verify the destination is a strict descendant of the output root using `Path.is_relative_to()` or an equivalent safe check. - Reject symbolic-link, device, FIFO, and other non-regular archive entries. - Open destination files using no-follow semantics where the platform supports them. - Perform validation before creating any parent directory or invoking bkcrack for the entry. - Apply one shared safe extraction function to every extraction path in the project. - Add tests for `../file`, absolute paths, Windows drive paths, mixed separators, nested traversal, and symlink-based escapes.

T08 · Insecure Dependencies

Warning
Location
scripts/zipcracker_core.py:887
Finding
Unpinned Runtime Installation of pyzipper## Vulnerability Details **File Location**: `scripts/zipcracker_core.py`, lines 887-895 and 966-1013 **Vulnerability Type**: Mutable third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```python def build_pyzipper_pip_install_commands(locale: str) -> list[tuple[str, list[str]]]: command = [sys.executable, "-m", "pip", "install", "--disable-pip-version-check"] if pip_should_use_user_flag(): command.append("--user") official = command + ["pyzipper"] if locale != "en": tsinghua = command + ["-i", PYPI_TUNA_SIMPLE_URL, "pyzipper"] return [("tsinghua", tsinghua), ("official", official)] return [("official", official)] ``` The generated mutable installation command is subsequently executed: ```python for source_name, cmd in build_pyzipper_pip_install_commands(locale): proc = subprocess.run( cmd, capture_output=True, text=True, timeout=1800, ) if proc.returncode == 0: break last_error = proc.stderr or proc.stdout or "" if source_name == "tsinghua": print( loc( locale, "[!] Installing pyzipper through the Tsinghua PyPI mirror failed. Falling back to the official PyPI index...", "[!] Installing pyzipper through the Tsinghua PyPI mirror failed. Falling back to the official PyPI index...", ) ) ``` ### Technical Analysis The Skill installs `pyzipper` by package name without pinning an exact version or requiring an artifact hash. The effective code installed during a future run can therefore differ from the dependency that existed when the Skill was audited. In non-English mode, the code first uses a third-party package mirror and then automatically falls back to the official package index. Neither source is constrained by a lock file or hash allowlist. Installation is cons ...[truncated 1274 chars]
Remediation
## Remediation Suggestions - Pin `pyzipper` and every transitive dependency to reviewed versions. - Use a lock file with hashes and install with pip's hash-verification mode. - Prefer provisioning dependencies before Skill execution rather than installing them at runtime. - Install into an isolated virtual environment dedicated to the Skill. - Remove automatic mirror fallback unless every accepted artifact is independently hash-verified. - Display the exact version, source, and expected hash before requesting user approval. - Fail closed if the reviewed artifact is unavailable instead of resolving a newer release.

T03 · Remote Payload Retrieval and Execution

Warning
Location
scripts/zipcracker_core.py:1399
Finding
Mutable Remote bkcrack Source or Binary Is Downloaded and Executed## Vulnerability Details **File Location**: `scripts/zipcracker_core.py`, lines 1399-1583 **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Medium ### Vulnerable Code The source-install path dynamically resolves the latest release, downloads its source archive, builds it, and then locates the resulting executable: ```python release = _http_get_json(BKCRACK_RELEASES_API) tarball_url = release.get("tarball_url") if not tarball_url: return False, loc(locale, "Could not resolve the bkcrack source download URL.", "Could not resolve the bkcrack source download URL.") managed_root = get_managed_bkcrack_root() current_dir = os.path.join(managed_root, "current") temp_dir = tempfile.mkdtemp(prefix="zipcracker_bkcrack_src_") try: archive_path = os.path.join(temp_dir, "bkcrack-source.tar.gz") print( loc( locale, "[*] Downloading bkcrack source and preparing a local build...", "[*] Downloading bkcrack source and preparing a local build...", ) ) _http_download_file(tarball_url, archive_path) source_extract_dir = os.path.join(temp_dir, "src") _extract_archive(archive_path, source_extract_dir) source_root = _find_source_root(source_extract_dir) if not source_root: return False, loc(locale, "CMakeLists.txt was not found in the downloaded source tree.", "CMakeLists.txt was not found in the downloaded source tree.") build_dir = os.path.join(temp_dir, "build") if os.path.isdir(current_dir): shutil.rmtree(current_dir, ignore_errors=True) os.makedirs(managed_root, exist_ok=True) for command in ( ["cmake", "-S", source_root, "-B", build_dir, f"-DCMAKE_INSTALL_PREFIX={current_dir}"], ["cmake", "--build", build_dir, "--config", "Release"], ["cmake", "--build", build_dir, "--config", "Release", "--target", "install"], ): proc ...[truncated 3506 chars]
Remediation
## Remediation Suggestions - Pin `bkcrack` to a reviewed release tag or immutable commit. - Bundle trusted SHA-256 values with the Skill and reject any artifact that does not match exactly. - Do not treat a digest obtained from the same mutable release response as an independent trust anchor. - Disable runtime download and compilation by default; prefer documented, administrator-managed installation. - If automatic installation is retained, isolate compilation and execution in a sandbox with minimal filesystem and network access. - Validate archive members before extraction and reject path traversal or link entries in downloaded packages. - Store reviewed binaries in a versioned location rather than replacing a mutable `current` directory. - Show the exact URL, version, expected digest, installation destination, and execution implications before requesting approval. - Fail closed when an allowlisted artifact is unavailable rather than falling back to an unverified latest release.
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (49)

Env Variable Harvesting

High
Category
Data Exfiltration
Content
def build_env(args: argparse.Namespace) -> dict[str, str]:
    env = os.environ.copy()
    if not args.allow_install_prompts:
        env.setdefault("ZIPCRACKER_AUTO_INSTALL_PYZIPPER", "0")
        env.setdefault("ZIPCRACKER_AUTO_INSTALL_BKCRACK", "0")
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.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if package_manager == "yum":
        return f"{prefix}yum install -y {package_list}"
    if package_manager == "pacman":
        return f"{prefix}pacman -Sy --noconfirm {package_list}"
    if package_manager == "zypper":
        return f"{prefix}zypper install -y {package_list}"
    if package_manager == "apk":
Confidence
93% confidence
Finding
Using `pacman -Sy --noconfirm` promotes unattended system package installation with reduced operator review, which is especially risky when surfaced from a task-oriented skill. Combined with this skill's auto-install behavior, it can facilitate broad system changes from a benign-looking ZIP request and increases supply-chain and privilege-abuse risk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill instructs the agent to invoke shell commands against local ZIP files, potentially install dependencies, and consult multiple local reference files, but it declares no explicit tool scope or permission boundaries. That mismatch means an orchestration layer may expose broader capabilities than necessary, increasing the risk of unintended command execution, file access, environment disclosure, or network use if the skill is triggered in a permissive runtime.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The default prompt is framed as a broad, high-authority instruction to act as a 'top-tier ZIP CTF solver' and to 'choose the strongest clue-driven path' without embedding explicit boundaries such as authorized-use checks, safe-trigger constraints, or refusal conditions. In a security-sensitive cracking skill, this increases the chance of inappropriate implicit invocation or use on unauthorized password-protected archives, making misuse easier even if the surrounding metadata describes authorized contexts.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
The wrapper maps OpenClaw-friendly flags to the bundled engine:

- `--auto-crc` -> auto-confirm short-plaintext CRC32 enumeration.
- `--auto-large-mask` -> auto-confirm huge mask warnings.
- `--auto-template-kpa` -> auto-confirm suggested built-in KPA templates.
- `--skip-dict-count` -> skip upfront dictionary line counting.
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
The wrapper maps OpenClaw-friendly flags to the bundled engine:

- `--auto-crc` -> auto-confirm short-plaintext CRC32 enumeration.
- `--auto-large-mask` -> auto-confirm huge mask warnings.
- `--auto-template-kpa` -> auto-confirm suggested built-in KPA templates.
- `--skip-dict-count` -> skip upfront dictionary line counting.
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
The wrapper maps OpenClaw-friendly flags to the bundled engine:

- `--auto-crc` -> auto-confirm short-plaintext CRC32 enumeration.
- `--auto-large-mask` -> auto-confirm huge mask warnings.
- `--auto-template-kpa` -> auto-confirm suggested built-in KPA templates.
- `--skip-dict-count` -> skip upfront dictionary line counting.
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The copy explicitly promises automatic extraction after success, but provides no warning that the skill may write files or modify the working directory. In an agent setting, implicit extraction can create unintended filesystem side effects, including overwriting files or materializing unsafe archive contents without clear user consent.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The English promotional section markets password recovery, brute force, KPA, and archive attack workflows without a prominent authorization-only warning in the same copy block. Even though the broader skill metadata mentions authorized contexts, this file itself reduces friction for misuse by advertising offensive recovery capability as a general-purpose feature.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill documentation promises automatic extraction after cracking, but it does not warn users that running the workflow may write files to disk. In a security tooling context, extracting attacker-controlled archive contents can create unintended filesystem changes, overwrite files, or expose the environment to path traversal and unsafe file material if extraction behavior is not clearly constrained.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The publishing copy explicitly markets password-cracking, known-plaintext attacks, CRC32 recovery, and automatic extraction, but it does not include a clear abuse-risk warning or an explicit restriction to authorized use in the main description area. That omission can normalize offensive archive-cracking behavior, reduce informed consent for users, and make the skill easier to invoke for unauthorized access despite the surrounding CTF framing.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The trigger phrase “这个压缩包打不开” (“this archive won't open”) is broad enough to match many ordinary support requests unrelated to authorized CTF or recovery contexts. In a skill explicitly designed for ZIP cracking and password recovery, overbroad routing can cause the agent to invoke offensive or high-risk functionality when the user only wants benign troubleshooting, increasing the chance of misuse or policy bypass through ambiguous phrasing.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| 密码应该是四位数字。 | `python3 <skill-dir>/scripts/openclaw_zipcracker.py <zip> -m '?d?d?d?d'` | Natural-language structure maps cleanly to a mask. |
| The password starts with `flag` and ends with two digits. | `python3 <skill-dir>/scripts/openclaw_zipcracker.py <zip> -m 'flag?d?d'` | Strong structure clue, tighter than a generic wordlist. |
| 形态像一位大写、三位小写、三位数字。 | `python3 <skill-dir>/scripts/openclaw_zipcracker.py <zip> -m '?u?l?l?l?d?d?d'` | Exact password shape is better than brute-force dictionaries. |
| 这个掩码很大,但我确认要跑。 | `python3 <skill-dir>/scripts/openclaw_zipcracker.py --auto-large-mask <zip> -m '<mask>'` | Auto-confirms the large-mask safety prompt. |

## Known-plaintext requests
Confidence
89% confidence
Finding
The example explicitly recommends `--auto-large-mask`, which bypasses a safety confirmation for computationally expensive mask attacks. In an agent setting, this can enable autonomous initiation of high-cost cracking jobs without an explicit fresh user confirmation at execution time, increasing the risk of resource exhaustion, unintended long-running tasks, or misuse against unauthorized targets.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The entrypoint hard-codes the language parameter as "zh" when invoking the CLI. This creates a natural-language policy issue because the skill enforces a specific language/locale without offering user opt-in or documenting a justified region-specific constraint.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This code selects a language from environment variables and defaults to "zh" when no English or Chinese locale is detected. That imposes a specific language choice on users without an explicit opt-in or neutral default, which matches the locale-policy violation criteria.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
parser.add_argument(
        "--auto-crc",
        action="store_true",
        help="Auto-confirm short-plaintext CRC32 enumeration prompts.",
    )
    parser.add_argument(
        "--auto-large-mask",
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
parser.add_argument(
        "--auto-crc",
        action="store_true",
        help="Auto-confirm short-plaintext CRC32 enumeration prompts.",
    )
    parser.add_argument(
        "--auto-large-mask",
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
parser.add_argument(
        "--auto-crc",
        action="store_true",
        help="Auto-confirm short-plaintext CRC32 enumeration prompts.",
    )
    parser.add_argument(
        "--auto-large-mask",
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if args.profile_json:
            inspect_args.append("--json")
        inspect_args.extend(inner_args)
        completed = subprocess.run([sys.executable, *inspect_args], check=False)
        return completed.returncode

    cli_path = CLI_BY_LANG[args.lang]
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
cli_path = CLI_BY_LANG[args.lang]
    env = build_env(args)
    command = [sys.executable, str(cli_path), *inner_args]
    completed = subprocess.run(command, env=env, check=False)
    return completed.returncode
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

External Transmission

Medium
Category
Data Exfiltration
Content
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DEFAULT_PASSWORD_LIST_PATH = os.path.join(SCRIPT_DIR, "password_list.txt")
BKCRACK_REPO_URL = "https://github.com/kimci86/bkcrack"
BKCRACK_RELEASES_API = "https://api.github.com/repos/kimci86/bkcrack/releases/latest"
MSVC_REDIST_URL = "https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist"
MSVC_REDIST_X86_URL = "https://aka.ms/vc14/vc_redist.x86.exe"
MSVC_REDIST_X64_URL = "https://aka.ms/vc14/vc_redist.x64.exe"
Confidence
90% confidence
Finding
The code is designed to contact external services such as GitHub and package indexes during operation, transmitting metadata requests and downloading binaries/source. In a ZIP-cracking skill, outbound network behavior is more dangerous because it is beyond the minimal scope of local archive analysis and may violate containment or supply-chain expectations.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The skill performs network downloads and local installation/build of external dependencies unrelated to merely parsing ZIPs, including GitHub release retrieval, package installation, and source builds. This greatly enlarges the attack surface and lets a user request cause code ingestion from the network and execution on the host.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if accept_header:
            cmd.extend(["-H", f"Accept: {accept_header}"])
        cmd.append(url)
        proc = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Tainted flow: 'cmd' from os.environ.get (line 3171, credential/environment) → subprocess.run (code execution)

Medium
Category
Data Flow
Content
if accept_header:
            cmd.extend(["-H", f"Accept: {accept_header}"])
        cmd.append(url)
        proc = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if accept_header:
        ps_script.append("$headers['Accept']='%s'" % accept_header)
    ps_script.append("(Invoke-WebRequest -UseBasicParsing -Headers $headers -Uri '%s').Content" % url.replace("'", "''"))
    proc = subprocess.run(
        [powershell, "-NoProfile", "-Command", "; ".join(ps_script)],
        capture_output=True,
        text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.