Skip to content

skill-security

MR-time security scanners for Claude Code skills, plugins, and other AI instruction-file repositories (SKILL.md, CLAUDE.md, .cursorrules, AGENTS.md, …). These files are source code an agent reads and executes, so they are an injectable attack surface: hidden instructions, Trojan-Source reordering, smuggled frontmatter.

Job Severity What it catches
hidden-chars hard fail Zero-width, bidirectional (Trojan-Source), line/paragraph-separator and other non-printing control characters that hide intent in a way a human reviewer cannot see in a diff.
injection-scan warn (allow_failure) Suspect instruction patterns — curl\|sh, base64-decode-pipe, "ignore previous instructions", and similar — flagged for human review.
plugin-schema hard fail Validates a Claude plugin marketplace's manifests and SKILL.md frontmatter: required keys, and only the allowed frontmatter keys (an unknown key is a smuggling smell). No-ops when the repo has no marketplace.json or SKILL.md.
gitleaks hard fail Secret-pattern scan, scoped to the MR's own commits.

Each scanner is a separate job — opt one out with <job>: { rules: [{ when: never }] }. MR-only by default. The custom scanners (hidden-chars, injection-scan, plugin-schema) run on a pinned Python image, standard library only — no installs, so no supply-chain surface of their own.

Jobs

Job What it runs
hidden-chars Walks $[[ inputs.paths ]], flags any disallowed Unicode code point (zero-width, bidi, line-separator, control chars, DEL, C1 range).
injection-scan Walks $[[ inputs.paths ]], regex-matches a fixed rule set (pipe-to-shell, base64-decode-pipe, eval-subshell, prompt-override phrasing, exfil-secret phrasing).
plugin-schema Validates every **/.claude-plugin/marketplace.json, **/.claude-plugin/plugin.json, and **/SKILL.md frontmatter against an allowed-key list.
gitleaks gitleaks detect, scoped to the MR diff base.

Inputs

Input Type Default Description
stage string security GitLab CI stage.
if string '$CI_PIPELINE_SOURCE == "merge_request_event"' Gating rules:if:.
paths string "**/*.md" Space-separated glob patterns the hidden-chars and injection-scan jobs walk. Widen with e.g. .cursorrules AGENTS.md or source globs.
python_image string "python:3.13-slim" Image for the custom Python scanners. Standard library only.
gitleaks_image string "zricethezav/gitleaks:v8.30.1" Gitleaks image.

Usage

include:
  - component: gitlab.com/phpboyscout/cicd/[email protected]

See also