---
title: "README ZIP Malware: Review the Actual Install"
canonical: https://wavect.io/blog/readme-zip-malware-install-review/
language: en
description: "README ZIP malware can hide behind a clean SKILL.md. Compare changed files, archive hashes and install scope with a reproducible offline review exercise."
image: "https://wavect.io/img/blog/headers/header_readme-zip-malware-install-review.png"
author: ["Kevin Riedl"]
published: "2026-11-05"
updated: "2026-11-05"
reviewed: "2026-11-05"
---

# README ZIP malware: review the actual AI tool install

[**Back**](/blog/overview/)

[![Kevin Riedl](/img/team/kevin.webp)](/team/kevin-riedl/)

[Kevin Riedl](/team/kevin-riedl/) https://linkedin.com/in/wsdt

13 min read · 5 Nov 2026 Last reviewed November 5, 2026

[**Next**](/blog/ai-agent-eval-sandbox-security-checklist/)

TL;DR

A clean SKILL.md does not cover an entire AI-tool installation. Our harmless offline exercise compares README changes, archive bytes and copied files against an earlier review record. Recheck changed inputs and execution scope; a matching commit or hash establishes consistency with that record, not safety.

You approved an AI skill. Later, its README points at an archive you never reviewed, while `SKILL.md` stays unchanged. The old file check still passes. Your installation decision now depends on something that check never covered.

**A README ZIP malware lure can leave the skill instructions unchanged while redirecting installation.** Review the repository identity, exact commit, README destination, archive contents and requested privileges together. Keep a trusted record of those inputs, then reopen the review when the source, downloaded bytes, copied files or execution scope changes.

An installation review is a decision about particular software inputs under defined permissions. Our offline exercise below makes the limits of that decision visible, including a harmless packaging change that deserves investigation without a malware verdict.

**Research checked: 5 November 2026.** The campaign account uses published researcher evidence. The executed comparison uses generated text files, ZIPs and local Git commits. It makes no network requests and runs no candidate installer.

**Independence and trademarks:** Wavect publishes this page and is itself a provider, so we have a commercial interest in it. We are not affiliated with, endorsed by or partnered with the other companies named here, and all third-party company names, brands and trademarks are the property of their respective owners. Statements about other providers are taken from publicly available sources, primarily their own published pages, as of the review date shown on this page, and may have changed since. Please verify them directly before you decide. This page was written to the best of our knowledge and with the intent to remain objective. If you believe anything here is inaccurate or unfair, write to us and we will correct it: [office@wavect.io](mailto:office@wavect.io)

## What does the 73-repository report establish?

On November 4, 2026, Thomas Roccia of SecurityBreak published an [IOC list covering 73 GitHub repositories](https://gist.github.com/fr0gger/3d0288bf0fee3b8df7b618e7c10334d7) posing as AI agent tools. His list recorded 51 as reachable and 22 returning 404 during that day's recheck. Those figures describe repository observations, not infections or current availability.

Roccia described copies of projects such as `mcp-superset`, `hermes-agent` and `ContinuousClaude`. The inspected skill and settings files appeared clean, while [README instructions led readers to committed ZIP files](https://x.com/fr0gger_/status/2118075957240348931). The directions also asked Windows users to override a security warning. One archive sat under `.claude/hooks/config/`. The reported Windows packages combined a batch launcher, a LuaJIT runtime and obfuscated Lua disguised as text.

The [announcement identifies SmartLoader](https://x.com/fr0gger_/status/2118075954740547684), commonly associated with StealC. The evidence does not establish that every repository delivered that payload. The IOC list distinguishes confirmed sample indicators from broader indicators unconfirmed for these builds. Victim counts and every account operator's identity remain unresolved. This evidence does not establish a compromise of the legitimate upstream projects.

## Why can a clean SKILL.md miss a README ZIP malware lure?

A clean `SKILL.md` result describes the inspected file. Installation can involve other instructions, bundled scripts, downloaded archives and startup configuration. If your review stops at the skill file, it cannot justify running those additional components. The missing question is which files and actions the approval covers.

The [Agent Skills specification](https://agentskills.io/specification) defines a skill as a directory, with `SKILL.md` as its required entry point. Scripts, references, assets and other files may accompany it. That layout gives you a useful review boundary: inventory the directory and follow the installation dependencies it introduces, rather than treating its entry point as the whole package.

Consider a reviewer who reads instructions for formatting documents, sees no suspicious commands, and approves them. A separate README tells the installer to obtain a runtime. That new dependency needs its own explanation: why this runtime, from this publisher, at this revision, with this access? Familiar wording in the first file cannot answer those questions.

The execution context also matters. In [Netskope's analysis of related SmartLoader samples](https://www.netskope.com/blog/developers-in-the-crosshairs-fake-ai-tools-deliver-infostealer), a batch launcher passes a text file containing Lua to an interpreter. Looking at the extension alone misses what the command does with the contents. A text file can supply code; a legitimate interpreter can execute it.

Keep the review's conclusion specific: “these instructions were reviewed” is useful evidence. Expanding that conclusion to every later download or command creates the gap. The same scope question applies when [shared skill instructions change over time](/blog/wikiskill-self-evolving-agent-skills/), although that separate workflow needs its own evaluation controls.

## What should an installation review cover?

An installation review should connect the publisher and source snapshot to the files, startup action and permissions you intend to enable. We recommend keeping a record outside the candidate's writable directory. Each entry should explain what was checked and which later change would require another decision from its owner.

| Review input | Evidence to retain | Question it answers |
| --- | --- | --- |
| Publisher and repository | Exact owner/repository and the independent reference used to identify it. | Are we reviewing the intended project? |
| Source snapshot | Full commit ID and the source files included in the review. | Which revision did the reviewer inspect? |
| README destination | The resolved archive path or final download URL, including relevant redirects. | What does the installation instruction select? |
| Archive | Archive SHA-256, member paths and the contents reviewed. | Are these the reviewed bytes and files? |
| Installed copy | A manifest of expected installed paths and file hashes. | Did copying or packaging change what will be loaded? |
| Startup action | Exact command, arguments, working directory and configuration. | What will execute when the tool is enabled? |
| Authority | Required filesystem access, network destinations and credentials. | What can that execution reach? |
| Decision owner | Reviewer, date, permitted use and reasons for any exception. | Who can approve a changed input? |

Start with the actual installation path. A ZIP committed inside a repository belongs to that source snapshot. A README that directs you elsewhere introduces a separately retrieved object. A release label, download button or archive filename is insufficient evidence that the selected bytes were covered.

Keep the expected values under your team's control. Comparing a candidate archive against a checksum shipped beside it by the same unknown publisher can establish internal consistency, but it does not establish that your reviewer approved either item. Record the expected digest after the review and protect that record from the candidate and its installer.

Our [MCP install risk scanner](/tools/mcp-install-risk-scanner/) can help triage pasted command or configuration patterns. It does not fetch a repository or inspect archive bytes. Use its output for the part it examines, then retain the missing evidence separately.

## Which changes invalidated the review in our offline test?

Comparing all recorded inputs matched only the unchanged case in our six-case offline test. A check of `SKILL.md` alone matched every case. Comparing the Git commit caught the two committed repository changes, but left changes outside that snapshot unnoticed. These results measure consistency with an earlier record, not whether files are malicious.

The lab completed **24 recorded checks using Python 3.12.14 and Git 2.51.1**. It creates harmless repositories containing a skill file, a README and two identical text-only ZIPs. It also models an external download with a local file and copies one known text member into a separate installation directory.

Each scenario starts from the same baseline and changes one input. The record contains the commit, source-file hashes, archive and member hashes, and installed-file hashes. Publisher identity and execution permissions are outside this lab. “Match” means equality with the baseline record. “Different” means that comparison would require the change to be explained before reusing the earlier review.

| Independent scenario | SKILL.md hash | Git commit | All lab inputs | What changed |
| --- | --- | --- | --- | --- |
| Unchanged baseline | Match | Match | Match | None. |
| README points to the other committed ZIP | Match | Different | Different | Only README content and its new commit; both ZIPs already contain identical harmless text. |
| Committed ZIP contents change | Match | Different | Different | Archive bytes and member contents, committed as a new revision. |
| External URL label stays the same; modeled download changes | Match | Match | Different | External archive bytes and member contents. |
| Copied installation file changes | Match | Match | Different | The installed text file. |
| Harmless external ZIP repack | Match | Match | Different | Only the archive comment; member contents remain identical. |

The README case is deliberately modest. It redirects a real relative Markdown link between two already committed archives. Neither archive contains malware. A file-only check misses the changed instruction, while a commit comparison notices it. This prevents the exercise from suggesting that a proper commit pin cannot bind a committed archive.

The external-download and repack cases are hypothetical extensions of the review problem. They do not describe additional findings about Roccia's repositories. No URL is requested: a local file stands in for the downloaded bytes.

The repack is the useful negative control. Its archive digest changes even though the contained text does not. A procedure that immediately calls this “malware” makes a stronger claim than its evidence supports. Reopen the review, compare the packaging change and decide whether to issue a new record.

Four checks run per scenario: the exact changed fields, the comparison outcomes, an unchanged baseline record, and a clean Git working tree. Six scenarios multiplied by four checks gives 24. The commit-only gaps therefore do not come from quietly editing uncommitted source files.

## How can you reproduce the comparison without running an installer?

Reproduce the comparison by reading the standalone lab source, then running its generated-data exercise with Python and Git. The script creates its own harmless candidates and writes a JSON result under your chosen working directory. It accepts no target repository or download URL and never launches the generated files.

Download the [readable Python lab source](/downloads/readme-zip-review-lab.py) and the [recorded result JSON](/downloads/readme-zip-review-results.json). The source requires Python 3.10 or later and Git, with no third-party Python packages. After inspecting it, run these commands from the directory where you saved it:

```
python3 readme-zip-review-lab.py \
  --work-dir .agent-cache/readme-zip-review-lab

python3 -m json.tool \
  .agent-cache/readme-zip-review-lab/results.json
```

Inspect `observed_controls` beside `expected_controls` in each scenario. The result also includes the actual changed fields, inventories, tool versions and the lab source's SHA-256. A failed check stops the run; an old success file is removed before the next run starts.

The baseline record is stored outside the candidate and installed-copy directories. In a deployed system, you would also need to enforce that separation against writes. This lab only verifies that its own record stays unchanged during the exercise.

Its file inventories cover regular paths and contents. They do not evaluate permissions, symlinks, arbitrary archive extraction, signatures, agent behavior or changes between checking and execution. The installed-file case follows a safe copy of known text. It is not a reason to run an unknown installer first and inspect the damage afterwards.

## What does a commit pin or matching checksum prove?

A commit pin identifies the selected source snapshot, while a matching checksum establishes byte consistency with a trusted reference. Their value depends on what you reviewed and what the installation uses. A correct match can preserve a bad decision; a harmless packaging change can produce a mismatch that needs explanation.

Separate three objects: a ZIP stored as a repository file, GitHub's generated archive of source code, and a download obtained from another location. The first is part of the selected commit. The second is a package generated around source contents. The third needs its own artifact evidence.

[GitHub's archive stability documentation](https://docs.github.com/en/repositories/working-with-files/using-files/downloading-source-code-archives) says commit-based archives preserve file contents while the commit remains available and the repository name is unchanged. Branches and tags can move. GitHub also distinguishes stable extracted contents from compressed archive bytes, which may change when compression settings change.

That distinction explains why the lab stores both the archive digest and member inventories. Do not silently replace a mismatched digest with the newly downloaded value. Retain the old record, establish what changed, and have the responsible reviewer accept or reject the replacement. Otherwise, the comparison records whatever arrived last.

Provenance helps answer a different part of the review. [GitHub's artifact-attestation guidance](https://docs.github.com/en/actions/concepts/security/artifact-attestations) explains how verified attestations connect an artifact to its source and build instructions. It also states that an attestation does not guarantee security. You still decide whether that publisher, build process and software behavior meet your requirements.

Finally, bind verification to the object you start. If the launcher resolves a moving reference again after the review, the earlier comparison no longer describes that retrieval. We recommend staging reviewed artifacts under host control and preventing replacement before launch. The offline lab does not test that enforcement.

## How do you enforce the review outside the agent's instructions?

Enforce the review with controls that govern retrieval, file changes and execution outside the candidate's instructions. Let discovery produce a proposal; let a protected decision determine which inputs and permissions may be enabled. Keep the verifier and expected record beyond the candidate's write access, and test refusal paths on the actual host.

Writing “only install reviewed tools” into an instruction file can explain your policy. Enforcement needs the client or operating environment to stop an action that violates it. [Claude Code's permissions documentation](https://code.claude.com/docs/en/permissions) explicitly distinguishes host-enforced permission rules from prompts and `CLAUDE.md`, which shape model behavior without changing the access the host grants.

One field deserves care: Claude Code's [`allowed-tools` skill setting](https://code.claude.com/docs/en/skills) preapproves the listed tools during the invoking turn. It does not make them the only callable tools; ordinary permissions still govern the others. Reading that field as a restrictive allowlist would leave your review based on the wrong control.

Check the process boundary too. The [Claude Code Bash sandbox documentation](https://code.claude.com/docs/en/sandboxing) covers shell commands and their children, but identifies hooks, local MCP servers and other helpers that run outside it. A whole-process boundary is a separate deployment choice. Our [Claude mods and function-hooks review](/blog/claude-mods-function-hooks/) covers those extension capabilities in more detail.

For Codex, [approval policy and sandbox mode](https://learn.chatgpt.com/docs/agent-approvals-security) are separate settings. Removing prompts does not itself remove an active sandbox, and an approval is not evidence of artifact safety. Review the effective configuration of the environment that will run the tool.

Codex's [MCP configuration reference](https://learn.chatgpt.com/docs/extend/mcp?surface=cli) likewise separates tool filters and per-tool approval behavior from a local server's command, arguments, environment and working directory. Restricting callable MCP tool names does not evaluate or sandbox the server's startup process. Approve that process before asking which methods the agent may call.

The [MCP security guidance for one-click local-server configuration](https://modelcontextprotocol.io/docs/2026-07-28/tutorials/security/security_best_practices) requires showing the exact command and arguments and obtaining explicit consent. It recommends least-privilege sandboxing too. Those are requirements for implementing clients, not evidence that every installation path already satisfies them.

These are documented control boundaries, not vendor features exercised by our Python lab. Use the [agent sandbox security checklist](/blog/ai-agent-eval-sandbox-security-checklist/) for the separate runtime containment review. A pre-installation file comparison cannot substitute for it.

## What evidence should your team keep before enabling the tool?

Keep an installation decision that names its inputs, execution scope, reviewer and conditions for re-review. Attach the comparison evidence and the host's refusal tests to that decision. Another engineer should be able to establish why the installed version is covered without relying on the agent's account of what it approved.

A small proposed record is enough to start. The following fields describe evidence you supply; they are not a production configuration or values generated by the lab:

```
decision: reviewed-for-local-test
source: <owner/repository and full commit>
artifact: <reviewed relative path or final URL>
archive_sha256: <digest of reviewed archive bytes>
installed_inventory: <protected file-manifest reference>
launch: <exact command, arguments and working directory>
scope: <filesystem, network and credential policy>
reviewer: <responsible person and review date>
recheck_on: [source, artifact, installed-files, launch, scope]
```

Then test the decision where installation will happen. We recommend the following acceptance evidence; these are proposed deployment checks, separate from the observed offline results.

| Proposed check | Evidence to retain |
| --- | --- |
| The reviewed baseline can perform its intended task. | A positive result using only the agreed access. |
| A changed input reaches the installation gate. | The host refuses reuse of the old decision before launch and identifies the changed field. |
| The candidate attempts to replace the expected record. | An independently enforced write denial, with the record intact. |
| A launcher requests a new destination, credential or filesystem path. | A refusal or separate authorized decision, plus the effective policy that caused it. |
| Files change after verification but before execution. | Evidence that the staged object cannot be replaced, or that another comparison stops launch. |

Assign an owner to each failure. A byte mismatch may need an engineer to inspect a repack. A new credential request may need the system owner to decide whether the use is acceptable. Neither should disappear behind a generic “continue” action.

For a team implementing this in its development workflow, our [DevSecOps service](/services/devsecops/) owns repository, build and release controls. The acceptance criterion stays concrete: enable the reviewed installation under its agreed scope, and require another decision when either changes.

## README ZIP installation review FAQ

### Does cloning one of these repositories automatically infect a machine?

The reported archive chain needs an execution step; a clone alone does not establish infection. Apiiro's [broader FakeGit research](https://apiiro.com/blog/never-deleted-only-re-pointed) distinguishes an archive arriving on disk from launching its contents. Still review what your surrounding tools automatically load or run. Investigate cloning, extension activation and installer execution as separate events.

### Is every ZIP committed to GitHub malicious?

No. A ZIP is a packaging format, and this exercise deliberately uses harmless archives. Investigate why the project needs the archive, who supplied it, what it contains and which command will use it. A changed digest calls for an explanation and another review decision; it does not identify malicious intent by itself.

### Can a repository's stars and normal history establish who controls it?

Treat those as background signals. They cannot replace verification of the intended publisher and current installation inputs. Roccia's [account observations](https://x.com/fr0gger_/status/2118075959291330709) were tentative about possible takeovers. Avoid diagnosing an account from appearance alone; retain the independent publisher reference and exact revision you reviewed.

### Does a .txt extension mean a file cannot execute?

No. An interpreter can read a text file as program input. The related Netskope analysis describes Lua supplied this way. Inspect how the launcher uses the file and which runtime receives it. Treating every text file as safe, or every interpreter as malicious, discards the context needed to assess the installation.

### Should I block every domain in the IOC list?

Review each indicator's role, confidence and scope before creating a rule. The published list includes legitimate shared services and indicators unconfirmed for the sampled builds. A broad domain block can interrupt unrelated work. Have your security owner select an appropriately narrow rule and validate its effect against your own telemetry.

### What should I do if I already ran an unfamiliar installer?

Stop using that device for sensitive work and contact your incident-response owner. Preserve the installer identity, timestamps and available logs. Island's [response guidance](https://www.island.io/blog/agentbaiting-how-800-fake-ai-skills-and-mcp-servers-delivered-malware) recommends isolating a suspected endpoint and revoking relevant sessions and credentials. Coordinate those actions from a clean device as warranted; deleting the download alone does not establish recovery.

### Can I apply this review to macOS, Linux or an OpenClaw extension?

Yes, the proposed comparison concerns installation inputs and permissions rather than a particular operating system. Adapt it to the files, startup mechanisms and host controls your extension uses. The reported launcher chain is Windows-specific; our harmless fixture is not evidence of the same payload on another platform or of any OpenClaw-specific enforcement.

QA and production readiness

## Read next

Testing, audits, maintenance and hardening practices for reliable production software.

[Start here**QA for AI-Generated Code**](/blog/qa-for-ai-generated-code/)

- [Lovable Data Exposure: How to Prove a Permissions Fix](/blog/lovable-supabase-data-exposure/)
- [Google's Elephant-Goldfish Model: Review the Plan Before Code](/blog/elephant-goldfish-model-design-review/)
- [LangSmith Trace Retention: Sampling, Evals and Cost](/blog/langsmith-trace-retention-sampling-cost/)
- [4 Software Agencies in Austria for Development and QA (2026)](/blog/software-agencies-austria-development-qa/)
- [Ultramarine 1 Flash for document agents: pricing, API limits and a migration test](/blog/ultramarine-1-flash-api-document-workflows/)

[Next article**Lovable Data Exposure: How to Prove a Permissions Fix**](/blog/lovable-supabase-data-exposure/)

[**Back**](/blog/overview/)

[![Kevin Riedl](/img/team/kevin.webp)](/team/kevin-riedl/)

[Kevin Riedl](/team/kevin-riedl/) https://linkedin.com/in/wsdt

13 min read · 5 Nov 2026 Last reviewed November 5, 2026

[**Next**](/blog/ai-agent-eval-sandbox-security-checklist/)
