Security scanning
Every upload is scanned before anyone decides on it, with SkillSpector, an open-source scanner for agent skills.
What it looks for
| Category | Example |
|---|---|
| Prompt injection | "Ignore all previous instructions…" in a skill |
| Credential access | Reading ~/.ssh, ~/.aws or token files |
| Data exfiltration | Sending data to an outside URL |
| Remote code execution | Downloading a script and running it |
| Code that runs on its own | Hooks that fire on Claude Code events |
| Supply chain | Risky dependencies |
Hooks
A plugin's hooks run automatically — before or after a tool call, at session
start, and so on. The scanner reads the hook configuration and follows it into
the scripts the hooks call: a harmless-looking hooks.json that runs a
malicious hooks/run.sh is reported against hooks/run.sh. Any plugin with
hooks is flagged for review, whatever its contents.
Waxell's own checks
SkillSpector reads what's in the upload. Two risks live outside it, so Waxell checks them itself and adds the findings to the same result. They can raise the verdict, never lower it.
MCP servers
For every MCP server a plugin declares, Waxell checks how it's launched:
| Finding | Severity |
|---|---|
| Downloads a script and pipes it to a shell | Critical |
Launches through a shell (sh -c …) | High; Critical if it also downloads |
Runs a package at whatever version is newest (npx -y pkg) | High |
| Runs a pinned third-party package | Medium |
| Package name resembles a well-known one | Medium |
| Container image not pinned; privileged or host-sharing container | High / Critical |
| Connects over plain HTTP | High |
| Connects to a server not in the MCP catalog | Medium (Low if catalogued but not verified) |
| A credential written into the configuration | High |
| Pointed at a home folder, the filesystem root, or credential folders | Medium / High |
A remote server always gets a finding naming where it connects, even a verified one. Every query the model sends through it goes to that service, so you see who that is before you approve.
What a skill tells Claude to install
A skill is instructions, and Claude follows them. If a SKILL.md says
"run npm install some-package", that package installs on the user's machine
when the skill runs, even though it was never part of the upload.
| Finding | Severity |
|---|---|
| Tells Claude to download a script and pipe it to a shell | Critical |
| Tells Claude to install packages without pinning a version | High |
| Tells Claude to install pinned packages | Medium |
Covers npm, pnpm, yarn, bun, pip, uv, gem, cargo and go. Restoring a project's
own dependencies (npm install with no package, pip install -r requirements.txt) isn't flagged.
Binary files
The scanner reads text, so Waxell inspects every other file itself — by what its bytes are, not its name — and the file ships with the package as uploaded.
| Finding | Severity |
|---|---|
| An Office file with macros | Critical |
| An Office file that loads remote content when opened (an attached template, a linked object or image, a data connection), or embeds other files | High |
| A PDF with scripts, embedded files or an open action | High |
| An executable, library or Java archive | High |
| An archive inside the package (its contents aren't scanned) | High |
A legacy .doc / .xls / .ppt, or a file type Waxell can't inspect | Medium |
| Inspected, nothing found — a clean Office file, image, font or PDF | Info |
Every binary file gets a finding, so you can see each one was looked at. Ordinary hyperlinks in a document aren't findings.
Reading a result
| Part | Meaning |
|---|---|
| Verdict | Safe, Caution, or Do not install. The scanner can rate a package as a whole with no individual finding; the drawer says so. |
| Risk score | 0–100. |
| Worst finding | The most severe finding, shown beside the verdict. |
| Findings | Each with severity, the file and line, the matched text, and how to fix it. |
The scanner can call a skill Safe while reporting a high finding. Waxell always shows the worst finding beside the verdict, and the auto-approval severity rule acts on the finding — so a "Safe" skill with a high finding still goes to a person.
What isn't scanned
- Inside a binary file beyond the checks above — an image's pixels, a compiled program's behaviour. Executables and archives are flagged for that reason.
- Code fetched when a plugin runs — the package an MCP server downloads at start-up, or one a skill tells Claude to install. Waxell flags that it happens (above) but can't scan code that isn't in the upload. Plugins with MCP servers, hooks or scripts go to a person by default for this reason.
Scanning is static analysis. Tenant content is not sent to a language model.
Rescanning
Rescan in the drawer runs the scan again. A submission still waiting for a decision is re-checked against your policy when the new result arrives.