# Qu1cksc0pe installs a dependency from an unpinned GitHub archive

> Qu1cksc0pe analyses suspicious files across seventeen formats and exposes its static analysis to agents over a Model Context Protocol server. Its dependency file ends with a raw archive URL pointing at another project's master branch, which means the code that runs inside your analysis tool changes whenever that author pushes.

**CYB3RMX/Qu1cksc0pe** — All-in-One malware analysis tool.

- Repository: https://github.com/CYB3RMX/Qu1cksc0pe
- Stars: 2,064 · Forks: 259
- Language: YARA
- License: GPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/cyb3rmx-qu1cksc0pe

## The last requirement line is a URL to someone's master branch

The dependency file is thirty lines long and almost all of them are package names. The last one is not:

```
https://github.com/DissectMalware/pyOneNote/archive/master.zip
```

That is an archive download of a different project's repository, taken from its default branch. Nothing in the file pins a tag, a commit or a version.

The effect is that every fresh install, every rebuild of the container, and every re-run of the setup script downloads whatever that repository's master branch contains at that moment. If the upstream author pushes a change, the code inside your analysis tool changes without you, without a version bump, and without anything in your own lockfile recording it.

For most consumer software that would be a supply chain weakness worth noting. For a malware analysis tool it is more pointed than that, because the tool's entire purpose is running code against hostile input, and a package that silently updates is exactly the shape of thing an attacker would want to compromise the tool with.

The archive belongs to a OneNote parsing project, which is a legitimate dependency for a tool that reads office documents. The fix is a commit hash in that line. It is not there.

## One dependency is pinned to an alpha and five are pinned exactly

The rest of the file mixes every policy you can think of in thirty lines.

Five entries carry an exact version: the pattern matching engine, a terminal toolkit, the Android package analyser, a Windows binary parser and the CPU emulator used for code emulation. One carries a lower bound, the protocol package the new server needs.

And one carries an exact version that is an alpha: the Android analysis library is pinned to a release whose own version string ends in an alpha suffix. So the package that parses Android packages, one of the formats the tool advertises dynamic analysis for, is locked to a pre-release build.

Everything else, roughly two dozen entries including the HTTP client, the office document parser, the cryptographic library, the instrumentation toolkit and the process memory library, carries no version at all.

There is also no lockfile in the repository. There is a manifest-style requirements file, a shell setup script, a PowerShell setup script and a Debian package build script, but no resolved dependency set, so two installs of the same commit on the same day can produce different trees.

## The agent-facing tool list includes writing your API keys

The protocol server exposes fourteen tools. Most of them are the obvious analysis verbs, and three are worth pulling out of the list.

There is a tool that configures a VirusTotal key and a tool that configures an AI provider key. And there is a tool that updates the hash database.

So a client attached to that server is not read-only with respect to your configuration. It can set the credentials the tool uses to query a third-party reputation service, set the credentials it uses to call a model provider, and trigger a fetch of the known-hash data the tool compares samples against.

The boundary is drawn deliberately elsewhere, and that is to the project's credit. Three features are explicitly withheld: the watch mode for dynamic analysis, the web interface, and the install command. Those are the three that would let an agent start an interactive session, open a browser, or change the machine.

The reasoning is stated rather than implied, and it is a sensible line. Reading analysis is one thing, editing credentials and pulling remote data into the detection path is another.

## The 50MB size cap exists so the command does not stop and wait

Every tool validates its input locally before invoking the command line, and the validation rule has a stated reason:

files of 50MB or more are rejected, because the command line would otherwise prompt interactively.

So the size limit is not a resource cap and not a security boundary. It is a hang guard. The command line tool, when handed a large file, asks a question on the terminal, and a client attached to the protocol server has no terminal to answer it on. The request would sit there until something timed it out.

That is a real consideration and worth having handled explicitly rather than leaving each client to discover it. It also means the size limit is inherited from the older command line interface rather than chosen on its own terms, which is why the explanation reads like an apology for a legacy prompt.

The same interface returns the generated report as JSON plus the captured console output, and it logs every invocation, its duration, its exit code and the reports it collected.

## Two transport models and a config file that picks the right one

The protocol server defaults to an HTTP transport rather than the traditional one:

```bash
python3 qu1cksc0pe.py --mcp
```

With the default, that binds a loopback address on port 8765 at a single path, and it runs as a persistent process. Any number of clients attach to it and detach from it independently. You start it once in a terminal and point clients at the address.

That is the opposite of the traditional model, where each client spawns and owns a process of its own, and the documentation is explicit about when to want which. So a project-level configuration file is included, which pins the traditional transport explicitly, with the reason given: that particular client spawns a fresh process per session rather than attaching to one you started.

Four environment variables control the server, each with a documented default: the transport, the bind address, the bind port, and the URL path. The transport accepts three values.

The documentation also warns that if the interpreter on your path is not the one holding the tool's dependencies, which it says is common on Windows and with multiple Python installs, the server will fail at startup, and tells you to test the import first.

## The container build makes three unpinned network fetches

The image starts from a long-term Ubuntu release, installs a Java runtime alongside curl, git, sudo, unzip and file, copies the whole build context in, runs the shell setup script, and then downloads a data file:

```
RUN wget https://raw.githubusercontent.com/CYB3RMX/MalwareHashDB/main/HashDB -O /home/root/sc0pe_Base/HashDB
```

A raw file from a branch on the same account, fetched at build time, with no checksum verified and no version referenced.

Two smaller things in the same file are worth noticing. The image sets the timezone to a single European city, which bakes the author's locale into every container. And it creates a symbolic link from a home directory back to root, because the tool expects to find its data under the home path of the user running it, which inside a root container is not where it looks.

Together with the archive requirement, that is three network fetches during a build, two of them from moving branches and one of them an archive with no version at all.

## The format table uses three different words for its sandboxes

The file type table is seventeen rows, and the analysis column is where the careful wording lives.

Office documents with macros get sandboxed behaviour emulation. HTML documents, JavaScript files and HTML applications get isolated behaviour emulation. PowerShell scripts get bounded in-memory behaviour emulation.

Three different qualifiers for three engines that all execute untrusted code. Sandbox means a boundary, isolated means separated from the host, bounded means capped in resource use. The project is telling you these are three different containment mechanisms rather than one sandbox applied uniformly, and it is doing so in a table that is mostly about file extensions.

Two other rows carry admissions. Android dynamic analysis is marked as working for the package format only, for now. macOS executables are static only.

And three rows describe extension mismatches rather than formats: AppleScript and Windows batch scripts are both described as detected when they arrive wearing a Visual Basic family extension. That is a real malware behaviour and worth having on the list, since it is exactly the sort of thing a static filter keyed on extension would miss.

## Conclusion

Worth using, and the MCP documentation is unusually careful about what it withholds from agents, which is more than most projects bother with. Two things to weigh before you wire it into an agent. One requirement is an archive from a moving branch, so pin it yourself before this tool has anything to do with a real sample. And note that the agent-facing tool list includes key configuration and hash database updates, so treat any client attached to that server as having your API keys.

## FAQ

### What file types can Qu1cksc0pe analyze?

Seventeen categories, including Windows and Linux executables, macOS binaries, Android packages and archives, Go binaries on Linux, office documents, the Visual Basic family, AppleScript, HTML, JavaScript, HTML applications, Windows batch scripts, Windows shortcuts, zip, rar and ace archives, packet captures, PowerShell and email files. macOS binaries are static only, and Android dynamic analysis is limited to the package format.

### Does Qu1cksc0pe need an API key or a language model to run?

No. Static analysis runs without either. The optional AI summary defaults to a local Ollama model and falls back to a heuristic summary when that is unavailable, and the five cloud providers are strictly opt-in through an environment variable or the interactive key manager.

### How do I run the Qu1cksc0pe protocol server?

Run the main script with the mcp flag after installing the protocol package. The transport defaults to an HTTP transport bound to loopback port 8765 at a single path, running as a persistent process; setting the transport environment variable to stdio switches to the traditional model where each client owns its own process.

### What does the Qu1cksc0pe container download while building?

It installs a shell setup script and then downloads a known-hash database from a raw file URL on a project branch, with no checksum and no version reference. The dependency list separately installs an archive downloaded from another project's default branch, also unversioned.

## Sources

- [CYB3RMX/Qu1cksc0pe on GitHub](https://github.com/CYB3RMX/Qu1cksc0pe)
- [Issues](https://github.com/CYB3RMX/Qu1cksc0pe/issues)
- [License: GPL-3.0](https://github.com/CYB3RMX/Qu1cksc0pe/blob/master/LICENSE)
- [README](https://github.com/CYB3RMX/Qu1cksc0pe/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cyb3rmx-qu1cksc0pe
