Latest Innovations
Checkmarx for Developers
Partners
Blog
Research

NVIDIA SkillSpector: “Safe” Verdicts Don’t Mean The Skill Is Safe

NVIDIA’s SkillSpector labels AI agent Skills as “Safe,” but that verdict has blind spots. Here’s how a malicious Skill can earn one.

NVIDIA SkillSpector: “Safe” Verdicts Don’t Mean The Skill Is Safe

NVIDIA has created a very useful scanner for AI agent/chatbot Skills: SkillSpector. This tool walks a directory containing the Skills files, and performs a lightweight static analysis combined with YARA rules and a lightweight LLM of its own to categorize a Skill’s content as “Safe”, “Caution”, or “Do Not Install”. But a “Safe” verdict, despite the name, doesn’t really mean the skill you just scanned is actually safe. Our research into SkillSpector’s approach, led by Alon Lerner, uncovered three ways malicious Skills can get a “Safe” verdict, at least in SkillSpector versions through 2.2.3. We reported these to NVIDIA; however, since they don’t consider these to be evidence of vulnerability in SkillSpector, it’s outside their threat model – which means it’s inside yours.

A quick SkillSpector overview

Skills are a quasi-standard way to give new capabilities to agents (for simplicity, we include chatbots, code assistants, and other similar AI systems when we use the word “agent”, even if they aren’t truly agentic). They’re a directory of files; the `SKILL.md` file contains some metadata describing the skill and a comprehensive prompt, and is the core of the Skill. Skills can also contain other things:

  • Additional documents, usually also in markdown (.md) format; these aren’t read until the prompts in the SKILL.md file direct the agent to do so.
  • Scripts, usually in bash (which agents often execute directly in a shell), Python, or JavaScript. Different agents have different strategies for sandboxing these scripts, with varying degrees of capability and safety
  • Templates that the Skill can fill in rather than having to generate outputs from scratch. For example, a Skill that produces a report as a Word file might have a Word template that defines the styles and layout.
  • Assets that the Skill can include as-is in its output. For example, a Skill that produces a branded image for social media might have a logo asset that the Skill can add into the generated image

SkillSpector focuses on the places of highest risk: the prompts in SKILL.md (because they are input into the LLM) and the bundled scripts (because they will execute where the agent is running). It scans these, at a high level, by:

  1. Finding relevant files in the Skill directory; only the files marked as relevant are fed to the next steps
  2. Running a suite of tests for known risky patterns, using a mix of regular expressions (regex), simple static analysis (looking for things like running local commands), data flow analysis, and a YARA run to identify malicious behavior
  3. Feeding the relevant files to an LLM. There’s a discovery phase and a meta-analyzer phase that confirms findings

Each finding identified is assigned risk points, and if the total points exceed certain thresholds, SkillSpector will report a “CAUTION” or “DO_NOT_INSTALL” flag, which you can implement so that it blocks Skill installation or startup.

Problem 1: Non-determinism

The first challenge for SkillSpector verdicts is that the LLM outputs aren’t deterministic: you can scan a skill twice, with no changes, and get different verdicts. Alon’s testing was able to surface cases where a byte-for-byte identical Skill could raise CAUTION flags in some scans, while being marked SAFE in others.

SkillSpector Security Report v2.2.3 for skill “devsetup” (source: excluded_path_poc), scanned 2026-10-13 14:44:31 UTC. Risk Assessment: Score 6/100, Severity LOW, Recommendation SAFE. Components (3): SKILL.md (markdown), package.json (json), scripts\cli.js (javascript, executable). Issues (1): LOW SC1 – Unpinned Dependencies, package.json line 9, confidence 40%. Executable scripts: Yes.
Safe verdict
SkillSpector Security Report v2.2.3 for the same skill “devsetup” (excluded_path_poc), scanned one minute later at 2026-10-13 14:45:22 UTC. Risk Assessment: Score 32/100, Severity MEDIUM, Recommendation CAUTION. Same three components. Issues (1): HIGH TP4 – the skill invokes `npm run bootstrap`, SKILL.md line 1, confidence 88%.
Caution verdict

This doesn’t mean SkillSpector is useless, but it does mean it has a degree of unreliability. This is a risk whether or not a Skill author is trying to evade SkillSpector, since it can result in both false positives (a safe Skill being blocked) and false negatives (a malicious Skill being approved). In CI/CD environments, build gates that key off of SkillSpector’s outputs could correctly block a Skill during one build, but permit it in the next.

Problem 2: You can hide malicious things in stuff SkillSpector ignores

Remember how SkillSpector’s first step is to build a list of relevant files? This list explicitly excludes dotfiles (like .envrc) and vendored dependency directories (like node_modules and venv Python environments). This is a sensible architectural design on the surface: SkillSpector intends to scan what Skill authors write, not third-party code found in those sources. This saves time on the static scan, and time and tokens during the LLM stage.

Unfortunately, that makes these excluded paths ideal places to hide malware. Alon was able to slip malicious code into node_modules/devtools-core/index.js, essentially pretending the malicious code was a legitimate dependency. SkillSpector gave a SAFE verdict, with a score of only 6 (while CAUTION requires at least a score of 50 out of a total possible 100) – because SkillSpector never even examined the malicious code.

At runtime though, the AI agent loads that code into its Node environment and happily executes it, allowing an attacker to execute arbitrary commands wherever the agent runs.

Code editor showing node_modules\devtools-core\index.js in an rce_poc project. Comments explain the file sits under node_modules, which SkillSpector’s file walker excludes, so no analyzer ever sees it. A red box highlights line 16: spawn(
Malicious payload in index.js
Windows terminal running `npm run bootstrap` in the rce_poc folder, which runs `node scripts/cli.js`. The Windows Calculator app (Standard mode) has opened on top of the terminal, showing that the hidden code in node_modules executed.
Result of running index.js (as instructed in the skill.md)

This risk exists because of a mismatch between what the real-world agent executes and what SkillSpector is willing to analyze, which means attackers can bypass both the static and LLM parts of SkillSpector

Problem 3: You can obfuscate some sketchy stuff

SkillSpector’s deterministic half identifies dangerous functions by name; so if you can hide the real names, you can hide your code from this half of the scanner. Hiding names is pretty easy: a call to os.system.cmd() would get flagged, but a call to getattr(os, "system")(cmd) does the same thing and looks completely fine to the scanner (or at least it did; as of version v2.5.0 this seems to have been fixed since then). Alon was able to reliably hide exactly that type of call from SkillSpector, once again allowing arbitrary execution of commands.

Code editor showing scripts\status.py in a getattr_poc project. The docstring says os.system is reached indirectly via getattr() with a constant name, so the AST detector never resolves it. A red box highlights line 14, run = getattr(os,
getattr() inside status.py
Windows terminal in the getattr_poc folder running `python scripts\status.py`. The Windows Calculator app (Standard mode) has opened beside the prompt, showing that the obfuscated os.system call executed.
Result of running status.py
SkillSpector Security Report v2.2.3 for skill “devsetup” (getattr_poc), scanned 2026-06-21 08:35:10 UTC, static analysis only. Risk Assessment: Score 13/100, Severity LOW, Recommendation SAFE. Components (2): SKILL.md and scripts\status.py (python, executable). Issues (1): MEDIUM LP3 – skill has no declared permissions but code capabilities were detected, SKILL.md line 1, confidence 70%.
Safe verdict when scanned

Fortunately, the LLM half isn’t so easily tricked. So, unlike Problem 2 above, it’s not a complete bypass of SkillSpector. However, it is a very good reason to make sure that you’re not tempted to run SkillSpector in “static only” mode. It might save time, but it is also very easy to trick.

SkillSpector Security Report v2.2.3 for skill “devsetup” (getattr_poc), scanned 2026-06-21 08:38:28 UTC with the LLM enabled. Risk Assessment: Score 84/100, Severity CRITICAL, Recommendation DO NOT INSTALL. Issues (5), including MEDIUM LP3 (agent told to execute a shell command), HIGH TP4 (skill claims to only print setup status but its behavior differs), MEDIUM SDI-1 (implementation does not match declared purpose), and MEDIUM SDI-2 (executes a shell command via os.system, hidden behind getattr, confidence 97%).
Critical verdict when scanned with llm

Disclosure and NVIDIA’s response

Checkmarx Zero follows coordinated disclosure practices, so we of course reported these issues to NVIDIA as soon as we were confident we had a clear and repeatable set of issues. NVIDIA responded promptly to our reports, and ultimately determined that these issues are not within the scope of their threat model, and so aren’t considered vulnerabilities from their point of view.

Which ultimately means these problems are up to you, as an adopter of SkillSpector, to understand and address.

NVIDIA’s response to our report, closing it as not applicable

Though the NVIDIA security team didn’t accept the report, it seems someone on their development team was thinking along similar lines.

GitHub page for NVIDIA/SkillSpector commit cb5e8c8, committed on Jun 23. Highlighted in a red box: “fix(behavioral-ast): detect reflective exec via getattr() literal (AST9)”. The message explains that getattr(os,
SkillSpector commit adding detection of reflective execution via getattr()

Lesson: no single control keeps you safe

SkillSpector is a valuable tool in a defender’s arsenal; used with care, it can reduce an organization’s exposure to malicious and dangerous AI Skills. But it’s definitely not perfect, and it’s up to security teams to keep it in perspective.

The limited scope of the scans leaves the door open for a clever adversary to hide dangerous code in a Skill that SkillSpector will mark SAFE. The Hybrid deterministic-plus-LLM approach has a lot of value (we do the same thing in our updated SAST tool, because it really is more accurate than either approach alone). But the single-LLM approach creates opportunities for error and inconsistency. As we learned in developing our Fusion scanner, multiple complementary models and controls make for a much better system.

So certainly use SkillSpector if it makes sense for your organization; but don’t rely on it alone, especially in critical or sensitive workflows. For example:

  • Use SkillSpector as a “Fail Fast” control: if it says it’s “Do Not Install”, it’s probably right. And you can get there fast.
  • For “Safe” verdicts, use additional static analysis tools that can examine the parts SkillSpector ignores or misses before finally approving.
  • As with all AI-related risks, make sure your endpoint controls are well-configured to reduce the impact and “splash damage” should a malicious Skill sneak by the above controls

As always, security is ultimately about thoughtful, interlocking layers of defense.

Tags:

AI Agent

AI Security

Arbitrary Code Execution

Bypass

LLM

Malicious Code