Skip to content

SC9 reports every script under .claude/skills/ and .agents/skills/ as a concealed executable (HIGH, confidence 1.0) #732

Description

@the-black-beard

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions