Skip to content

skills/ClawHub: surface source, add lockfile, sandbox by default #92077

Description

@nmccready-tars

Surface source code provenance on ClawHub skill listings

Summary

ClawHub skill listings (web + API) currently expose no link to the underlying source code for a skill. As a user trying to verify a skill before installing it, I cannot find the actual code repository from either the listing page or the API. This makes informed trust decisions impossible and pushes responsible users toward avoiding ClawHub entirely.

Skills execute arbitrary shell on UserPromptSubmit, PreToolUse, Stop, and PreCompact hooks — a malicious skill is a persistent keylogger over the entire agent loop. The npm supply chain incidents of 2024–2026 (ua-parser-js, color, faker, eslint-config-prettier, the shai-hulud worm) show what happens when a package marketplace doesn't make source review easy. ClawHub is structurally the same surface with arguably worse blast radius.

Evidence

1. Web page has no source link

$ curl -s -L "https://clawhub.ai/isainazar/openclaw-find-skills" -o page.html -w "%{http_code}\n"
200
$ wc -c page.html
46478 page.html
$ grep -oE "(github\.com|gitlab\.com|bitbucket\.org)" page.html
(no output)
$ grep -oiE "(repository|source url)" page.html
(no output)

46KB of rendered page, zero references to any code-hosting domain, zero "repository" or "source" strings.

2. API has no sourceUrl field

$ curl -s "https://clawhub.ai/api/v1/skills/openclaw-find-skills"
{
  "skill": {"slug", "displayName", "summary", "tags", "stats", "license", ...},
  "latestVersion": {"version", "createdAt", "changelog", "license"},
  "owner": {"handle", "userId", "displayName", "image": "<github avatar URL>"},
  "moderation": {"verdict": "clean", "reasonCodes": ["review.llm_review"], "engineVersion": "v2.4.24"},
  "metadata": null
}

The owner's GitHub avatar URL is included (so ClawHub clearly knows the publisher's GitHub identity), but the code repository URL is not in the schema anywhere.

3. openclaw skills verify --card only surfaces self-attested risk

The skill card returned by openclaw skills verify --card <slug> shows publisher handle, version, license, and the publisher's self-declared "Known Risks and Mitigations." It does not show the source repo URL, the moderation report, the install tarball SHA, or any hash to compare against the publisher's git history.

Asks

Three concrete additions, in priority order:

1. Required sourceUrl field on every skill manifest

  • Surface in the API as skill.sourceUrl (or in latestVersion)
  • Display prominently on the listing page (above the install button)
  • Verify at publish time that the URL resolves and contains the published skill (e.g., SKILL.md at the referenced path matches the published artifact)
  • Reject publishes that don't provide a source URL

2. Publish the moderation report, not just the verdict

The API already includes moderation.verdict: "clean" and reasonCodes: ["review.llm_review"]. Expose:

  • What the LLM scanner actually checked (which files, which patterns)
  • Any flagged sections, even if ultimately marked clean
  • The scanner's version and prompt fingerprint so reviewers can reason about coverage

A "clean" verdict from an opaque LLM is not better than no verdict — it's worse, because it discourages independent review.

3. Pinned-SHA install support

openclaw skills install <slug> currently resolves to ClawHub's "latest" — a moving target. Add:

  • A reviewed-SHA install path: openclaw skills install <slug>@<sha256> that fails if the published tarball doesn't match the supplied hash
  • Listing UI prominently displays the install-time SHA so users can paste a pinned install command into their team's playbook / Terraform / .agents repo

4. Workspace lockfile (skills.lock / clawhub.lock)

Every other modern package ecosystem has one (package-lock.json, Cargo.lock, poetry.lock, Gemfile.lock, pnpm-lock.yaml). Skills should too. A lockfile makes reproducibility tractable and drift detectable.

Required contents per installed skill:

  • slug, resolved version, install-time tarball SHA256
  • sourceUrl at install time (so source-vs-published drift is detectable on re-resolve)
  • moderation.verdict + engineVersion at install time (so "the scanner that cleared this skill" is auditable)
  • Any nested skill dependencies, recursively pinned
  • Hash of the rendered SKILL.md so hook drift is detectable without re-fetching the tarball

CLI surface:

  • openclaw skills install writes/updates skills.lock next to the workspace skills directory
  • openclaw skills install --frozen (analog of npm ci / pnpm install --frozen-lockfile) fails if anything is missing from or drifts off the lock
  • openclaw skills audit re-checks every entry against ClawHub: flags SHA mismatches, source URL changes, moderation downgrades, removed publishers

This pairs with team sync workflows (commit the lockfile to git, CI verifies --frozen) and gives security review a single artifact to attest to.

5. Sandbox every skill by default; trust is an explicit promotion

Skills currently execute arbitrary shell with the full ambient privilege of the agent process — read any file the user can read, write anywhere, hit any network endpoint, exfiltrate any env var. That's the wrong default. The right default is deny-by-default, with the user explicitly granting capability.

Proposed model:

  • Every newly installed skill runs in a sandbox: no network, no filesystem outside $CLAUDE_SKILL_DIR and the explicit workspace paths it declares, no env-var read outside an allowlist (HOME, PATH, plus declared ones), no eval/exec/base64 -d of fetched content
  • Skill manifests declare requested capabilities up front:
    capabilities:
      network:
        - host: api.alpaca.markets
          ports: [443]
      filesystem:
        reads: ["$WORKSPACE/data/**"]
        writes: ["$WORKSPACE/reports/**"]
      env:
        - ALPACA_API_KEY
        - ALPACA_API_SECRET
  • First install prompts the user to review capabilities → grant or deny
  • "Trust" is an explicit openclaw skills trust <slug> action that unsandboxes (or grants superset of declared capabilities), gated by a confirmation that names the slug + version + SHA
  • Trust does not transfer across versions — re-trust required on update, so a malicious upgrade can't inherit prior privilege

This is the only model that survives a compromised publisher account or a moderation-scanner bypass. It is structurally larger than asks 1–4, but it's the only one that turns "did the scanner miss something?" from a catastrophic question into a contained one.

For implementation pragmatism, a phased rollout works: ship asks 1–4 first; ship sandbox as opt-in (openclaw skills install --sandbox <slug>) in the next minor; flip the default in a subsequent major with a migration that auto-trusts existing installs and warns.

Why this is the bare minimum

Without these, the only safe ClawHub install workflow is:

  1. Find the skill on ClawHub
  2. Guess where the source might be (the marketplace doesn't tell you)
  3. Find the repo manually (via GitHub search, the publisher's profile, or the skill author's website if they have one)
  4. Verify the repo's published SKILL.md matches what ClawHub will install (no SHA to compare against)
  5. Install and pray

That is not a trust model. It is "trust ClawHub's LLM moderator." Compare with npm/PyPI/RubyGems all surfacing a repository URL on every listing, lockfile-based reproducibility being table stakes since ~2017, and Deno / Bun / capability-based runtimes treating sandboxing as the obvious default for arbitrary downloaded code.

Asks 1–3 are mostly schema and UI changes over data ClawHub already has. Ask 4 (lockfile) is a tooling lift, but every other ecosystem solved it a decade ago and the design space is well understood. Ask 5 (sandbox-by-default) is the only one that is structurally large — and it's also the only one that meaningfully changes the threat model rather than just helping users reason about it.

Reproducer

curl -s "https://clawhub.ai/api/v1/skills/openclaw-find-skills" | jq '.skill.sourceUrl // "MISSING"'
# → "MISSING"

Same result for every skill I've sampled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions