Skip to content

feat(scanner): scan Claude plugin packages and marketplace provenance as hostile supply-chain artifacts #1099

Description

@seonghobae

Problem

CWL is evaluating anthropics/claude-plugins-community as a discovery source for narrowly approved developer-assist capabilities. Existing PR #1036 correctly adds detectors for mixed-script skill identity, prompt-injection directives, exfiltration instructions, and unresolved placeholders on skill/agent manifest surfaces. It does not yet provide a complete admission receipt for a Claude plugin package or marketplace entry.

The upstream catalog may reference third-party repositories, exact refs, local paths, skills, subagents, hooks, commands, MCP servers, package-manager commands, external accounts, and license notices. Anthropic review is upstream evidence only; Noema #545 requires CWL-owned, artifact-bound AppGuardrail evidence before admission or activation.

Observed upstream identity at issue creation:

  • anthropics/claude-plugins-community@a727be1c7bd6064419b6f60d71993a19198adc17
  • .claude-plugin/marketplace.json blob eb95bc96ea8434539aeb4cc1cec40abaca6d40aa

These values are observation-scoped and must be refetched and rebound when the source moves.

Canonical boundary

AppGuardrail owns deterministic static analysis, policy findings, SARIF, and an exact-artifact scan receipt. It does not own:

Implement this as the non-duplicative successor to #1036. Do not reimplement #1036's detectors or close it as obsolete; reuse its released rule identities and findings.

Artifact surfaces to inventory and scan

Support a bounded package graph containing, when present:

.claude-plugin/marketplace.json
.claude-plugin/plugin.json
.mcp.json
skills/**/SKILL.md
agents/**/*.md
commands/**/*.md
hooks/hooks.json
hooks/**/*.{sh,bash,zsh,js,mjs,cjs,ts,py,rs}
scripts/**
package.json / lockfiles
requirements*.txt / pyproject.toml / Cargo.toml / Cargo.lock
LICENSE* / NOTICE* / THIRD_PARTY*

Unknown executable or configuration surfaces must be reported and fail admission until classified; they must not be silently ignored.

Required checks

Source and provenance

  • Parse the exact marketplace entry and bind plugin name/version/category/source repository/ref/path to the retrieved artifact.
  • Require an immutable full commit SHA for remote Git sources; reject floating branches/tags and ref/path mismatches.
  • Distinguish catalog repository SHA, marketplace blob SHA, referenced repository SHA, package tree/artifact SHA-256, and scan-policy version.
  • Reject symlink/path escape, submodule indirection without recursively admitted identity, archive path traversal, duplicate JSON members, non-standard JSON constants, malformed Unicode, concealed control/format characters, and inconsistent normalized/raw names.
  • Record license expression, license file digests, notices, source availability, and unresolved commercial-use/redistribution questions without inventing legal approval.

Capability inventory

Produce a machine-readable inventory for:

filesystem_read
filesystem_write
process_spawn
shell_execution
package_install
network_egress
browser_profile_access
credential_access
mcp_server_start
mcp_remote_connect
github_read
github_write
github_review
github_merge
github_release
deployment_write
model_provider_access

Inventory is evidence, not permission. Undeclared or ambiguous authority fails admission.

Static security findings

Extend the released #1036 rules with package-level findings for at least:

  • direct model-provider secrets or routing (OPENAI_API_KEY, NVIDIA_NIM_API_KEY*, BYTEZ_API_KEY, OPENROUTER_API_KEY, provider/model fallback lists);
  • broad GitHub/PAT/App authority and review/merge/release/deployment commands;
  • raw secret/cookie/token access or copying secrets into prompts, files, logs, subprocess environment, network requests, or MCP arguments;
  • curl|wget piped to a shell, mutable runtime download, unpinned package-manager execution, lifecycle/post-install scripts, unsigned executable download, or dynamic code evaluation;
  • arbitrary shell/host filesystem/Docker socket/browser-profile/network access;
  • remote MCP endpoints or stdio MCP binaries without bounded schema/authentication/source identity;
  • command/agent/skill text that asks the model to override system/developer/user safety, hide actions, self-modify, exfiltrate, or escalate goals;
  • Unicode homoglyph/control/bidi concealment, duplicate/conflicting plugin/skill/command identities, unresolved templates, hidden files, and deceptive descriptions;
  • oversized/decompression-bomb/deep-recursion input and generated-file or vendored-code scope ambiguity;
  • source-to-artifact mismatch, undeclared executable surface, or license/NOTICE mismatch.

Do not mark every shell command or external connector as malicious. Emit explicit capability and policy findings that Noema can evaluate against a product/role-specific allowlist.

Scan receipt

Emit a bounded, deterministic receipt containing at least:

scan_receipt_id
scanner_name
scanner_version
scanner_policy_sha256
catalog_repository
catalog_commit_sha
marketplace_blob_sha
marketplace_entry_sha256
plugin_name
plugin_version
source_repository
source_commit_sha
source_path
artifact_sha256
file_count
scanned_byte_count
capability_inventory_sha256
sarif_sha256
finding_summary
license_evidence_summary
scan_started_at
scan_completed_at
scan_result

scan_result=pass means the exact artifact satisfied the exact AppGuardrail policy. It is not Noema admission, product activation, formal review, merge, release, legal approval, or dynamic-sandbox evidence.

The receipt must contain no secret values, raw product data, hidden reasoning, unnecessary personal data, or unbounded plugin text.

TDD acceptance

RED/GREEN fixtures must cover:

  1. one positive minimal pinned plugin;
  2. branch/tag instead of full SHA;
  3. marketplace source/ref/path differing from retrieved artifact;
  4. duplicate JSON members, malformed UTF-8/Unicode and bidi/control concealment;
  5. symlink/archive path traversal and nested submodule without admitted identity;
  6. feat(scanner): skill-supply-chain detectors (homoglyph, injection, exfil, placeholder) #1036 homoglyph, injection, exfiltration and placeholder findings through the real package scanner;
  7. direct provider key, broad GitHub write, Docker socket and secret-to-network flow;
  8. remote/stdio MCP with and without a complete bounded declaration;
  9. runtime installer and unsigned executable download;
  10. undeclared hook/script appearing after manifest inventory;
  11. license/NOTICE absence or mismatch;
  12. wrong artifact, wrong policy or stale receipt replay;
  13. hostile oversized/deep/large-file-count packages;
  14. deterministic identical receipt for identical source/policy and changed receipt for any source/policy byte change;
  15. SARIF and receipt findings remaining semantically consistent.

Use public metadata or purpose-built fixtures; do not vendor a third-party plugin corpus into AppGuardrail. Production statement/branch coverage and public docstrings remain 100%, with property/fuzz tests on parsers and hostile archives.

Integration and release acceptance

Guardrails

No blanket trust in anthropics/*, no silent allowlisting by popularity/category, no live plugin execution in the scanner, no provider credentials, no product runtime installation, no arbitrary network fetch from untrusted package instructions, no weakening central scanners, and no claim that AppGuardrail PASS alone authorizes activation.

Related: PR #1036; ContextualWisdomLab/noema#545; ContextualWisdomLab/macos_utility_packs#3.

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

    Type

    No type

    Projects

    • Status
      In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions