What SkillTotal catches, and what it does not
Static analysis has known blind spots, and researchers have published them. This page goes through the published techniques one by one and says what the engine does with each, so you can decide what to put on top. A clean scan from any scanner is not proof of safety. Here is what this one covers and what it does not.
The published bypasses
In June 2026 Trail of Bits showed four ways to get a malicious agent skill past marketplace scanners (Trail of Bits, 3 June 2026), and the Cloud Security Alliance summarized them with a community study (CSA research note, 10 June 2026). In October 2026 VirusTotal published a study of 35,878 agent skills, 18.5 % of them malicious under its own definition, and a benchmark of scanners (VirusTotal, October 2026).
| Technique (as published) | What it defeats | What SkillTotal does |
|---|---|---|
| Whitespace inflation: ~100,000 blank lines push the payload past a scanner's truncation window | Scanners that read only the first part of a file | Every text file up to 2 MiB is read to the end, so the padded payload stays in scope. A file over 2 MiB is not read; the report lists it under "Files too large to analyze", file by file, and --fail-on-unanalyzed fails the build. |
Precompiled bytecode: the payload ships only as .pyc, with no .py | Scanners that read source | The engine does not read bytecode, so it cannot see what the file does. Since 0.79.0 a .pyc, .pyo or .class with no source beside it is reported as "Compiled code shipped without source": the verdict reads "Partially analyzed", the CI log names the file, and --fail-on-unanalyzed fails the build. Bytecode next to its source is treated as a build artifact; the source is what gets analyzed. |
| Document-archive indirection: instructions and scripts hidden inside a DOCX (a ZIP) | Pattern matching on the skill definition | Not covered. The engine does not unpack documents; a DOCX is skipped as a binary. It opens the archives a component is installed from: .zip, .mcpb, .dxt, .whl, .vsix and tarballs. |
| Prompt injection against the scanner's LLM: a "compliance policy" that talks the model's judgement down | Scanners with an LLM review layer | Does not apply. There is no model in the pipeline, so there is nothing for the component's text to persuade. |
Four more shapes, tested
Each built as a sanitized sample and run through the engine (0.79.1, ruleset 79; the samples ship in the engine's test corpus):
| Shape | Result |
|---|---|
Instructions hidden in invisible Unicode (tag characters, zero-width) inside SKILL.md | Malicious indicator: the hidden text is decoded into the evidence |
| A clean SKILL.md with the payload moved to a referenced file and a helper script | High risk: the whole component is scanned, not only the skill file; the script's credential read plus network send is the exfiltration combination |
A base64 blob decoded and executed from setup.py | Malicious indicator (decode-and-execute), install-time dropper |
An npm postinstall that downloads and runs a script, then posts credentials | Critical, malicious indicator |
What a result does not mean
- A low score is not a safety certificate. It means no malicious indicator and no risky construct were found in the files that were read. The report lists what was read and what was not.
- The engine looks at the component, never at how you deploy it. What a capability means in your environment is your call.
- It does not execute anything and does not watch runtime behavior. Runtime monitoring, least privilege for the agent and version pinning are the layers the CSA note recommends on top of any static scan, and we agree. How the approaches compare: static analysis vs LLM review.
How to use this
- In CI, set
fail-on-unanalyzed: 'true'for the third-party components you scan: anything the engine could not read fails the build. Leave it off for your own repository, which has bundles and large files for good reasons. Details on the GitHub Action page. - In Claude Code, the plugin's CI strict mode denies what it could not check instead of asking.
- Marketplaces that scan every upload with a model (for example) and a deterministic check at install time see different things. Use both.
FAQ
- Does a clean SkillTotal scan mean the component is safe?
- No. It means no malicious indicator and no risky construct were found in the files the engine read. The report lists what it could not read, and --fail-on-unanalyzed turns that into a failed build.
- Can a component hide a payload in a .pyc file?
- The engine does not read bytecode, so it cannot see inside the file. Since 0.79.0 a .pyc, .pyo or .class with no source beside it is reported as compiled code shipped without source, the verdict reads Partially analyzed, and --fail-on-unanalyzed fails the build.
- Can text inside a component change the verdict?
- No. There is no language model in the pipeline. Detection is deterministic static analysis, so text aimed at a reviewer has no reviewer to persuade.
- Does it unpack DOCX or other documents?
- No. It unpacks the archives a component is installed from (.zip, .mcpb, .dxt, .whl, .vsix and tarballs). A document inside a component is skipped as a binary and is not analyzed.