Summary
The standard per-client skill folders are dot-folders: .claude/skills/<name>/ for Claude Code and .agents/skills/<name>/ for Codex. When a scan root contains such a folder, SC9 "Concealed Executable Artifact" reports every script inside it as HIGH, with confidence 1.0 and concealment_reasons: ["hidden_artifact"].
Two things show the classification depends on the path, not the file:
- the byte-identical file in a folder without a leading dot is not reported;
- scanning the skill folder itself reports nothing.
So a skill's own, plainly visible helper scripts score the same as a payload hidden inside a document.
Environment
- SkillSpector v2.12.0 (
c7958a3268d9498644b22edb75d0f051bbc8cbfc), installed with pip install "git+https://github.com/NVIDIA/skillspector.git@c7958a3268d9498644b22edb75d0f051bbc8cbfc".
- Python 3.13.1 on macOS.
- Static mode:
skillspector scan <path> --no-llm --format json --output <file>.
- For comparison, v2.5.1 (
3f11bfa, before SC9 existed) reports nothing for either repro.
Reproduce
mkdir repro
for d in .claude/skills/hello .agents/skills/hello skills/hello; do
mkdir -p "repro/$d/scripts"
printf -- '---\nname: hello\ndescription: Print a greeting.\n---\n\nRun `python scripts/hello.py`.\n' > "repro/$d/SKILL.md"
printf 'print("hello")\n' > "repro/$d/scripts/hello.py"
done
skillspector scan repro --no-llm --format json --output repro.json
skillspector scan repro/.claude/skills/hello --no-llm --format json --output skill.json
Actual (v2.12.0)
repro.json reports 2 findings, with risk score 48:
| Rule |
Severity |
Confidence |
File |
concealment_reasons |
| SC9 |
HIGH |
1.0 |
.agents/skills/hello/scripts/hello.py |
["hidden_artifact"] |
| SC9 |
HIGH |
1.0 |
.claude/skills/hello/scripts/hello.py |
["hidden_artifact"] |
- The identical
skills/hello/scripts/hello.py gets no finding.
skill.json, from scanning the .claude/skills/hello folder directly, has 0 findings and risk 0.
This crosses the default exit threshold quickly:
- One skill with three one-line scripts,
.agents/skills/tools/scripts/{check,fmt,lint}.py, each a single print("…"), gives 3 SC9 HIGH findings.
- That scan scores risk 56,
DO_NOT_INSTALL, and scan exits 1.
- A real repository that keeps its Codex skills under
.agents/skills/ got 99 SC9 HIGH findings, one for every .py file in that folder. That is 99 of its 123 HIGH findings.
- These files are still analyzed normally: other rules reported findings inside them. So SC9 adds no coverage here. It only adds a HIGH per file.
Expected
A script in a skill's own folder is not concealed. It is part of the content under review, and it is inventoried and analyzed like any other file. SC9 should keep catching the following:
- executables inside documents and archives;
- disguised files;
- files that are themselves hidden.
What it should not flag is the conventional agent-client directories that skills are designed to live in.
Where it comes from (v2.12.0)
build_context.py treats any path segment that starts with . as hidden, and marks every executable under one as concealed:
_analyze_concealed_executables then emits SC9 at HIGH, with confidence 1.0.
main at 4a55062 (4 Oct) has the same logic.
Possible directions
These are suggestions only; the maintainers know the threat model better.
- Don't count a leading-dot segment as concealment when it is a conventional agent-client directory (
.claude/, .agents/, .codex/, .github/, …). Or don't count it when the executable sits inside a folder that discovery recognised as a skill, meaning one with a SKILL.md.
- Or judge "hidden" by the file's own name and by non-conventional hidden directories, rather than by any ancestor.
- Either way, a configurable list would let strict users keep today's behaviour.
Related: #382, which introduced hidden-file inspection and SC9.
Summary
The standard per-client skill folders are dot-folders:
.claude/skills/<name>/for Claude Code and.agents/skills/<name>/for Codex. When a scan root contains such a folder, SC9 "Concealed Executable Artifact" reports every script inside it as HIGH, with confidence 1.0 andconcealment_reasons: ["hidden_artifact"].Two things show the classification depends on the path, not the file:
So a skill's own, plainly visible helper scripts score the same as a payload hidden inside a document.
Environment
c7958a3268d9498644b22edb75d0f051bbc8cbfc), installed withpip install "git+https://github.com/NVIDIA/skillspector.git@c7958a3268d9498644b22edb75d0f051bbc8cbfc".skillspector scan <path> --no-llm --format json --output <file>.3f11bfa, before SC9 existed) reports nothing for either repro.Reproduce
Actual (v2.12.0)
repro.jsonreports 2 findings, with risk score 48:concealment_reasons.agents/skills/hello/scripts/hello.py["hidden_artifact"].claude/skills/hello/scripts/hello.py["hidden_artifact"]skills/hello/scripts/hello.pygets no finding.skill.json, from scanning the.claude/skills/hellofolder directly, has 0 findings and risk 0.This crosses the default exit threshold quickly:
.agents/skills/tools/scripts/{check,fmt,lint}.py, each a singleprint("…"), gives 3 SC9 HIGH findings.DO_NOT_INSTALL, andscanexits 1..agents/skills/got 99 SC9 HIGH findings, one for every.pyfile in that folder. That is 99 of its 123 HIGH findings.Expected
A script in a skill's own folder is not concealed. It is part of the content under review, and it is inventoried and analyzed like any other file. SC9 should keep catching the following:
What it should not flag is the conventional agent-client directories that skills are designed to live in.
Where it comes from (v2.12.0)
build_context.pytreats any path segment that starts with.as hidden, and marks every executable under one as concealed:_is_hidden_component, L797–L799;"concealed_executable": True, "concealment_reasons": ["hidden_artifact"]._analyze_concealed_executablesthen emits SC9 at HIGH, with confidence 1.0.mainat4a55062(4 Oct) has the same logic.Possible directions
These are suggestions only; the maintainers know the threat model better.
.claude/,.agents/,.codex/,.github/, …). Or don't count it when the executable sits inside a folder that discovery recognised as a skill, meaning one with aSKILL.md.Related: #382, which introduced hidden-file inspection and SC9.