You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue adds an automatic safety check that every skill must pass before it can be published to the hub. A skill can contain both written instructions and runnable code that get loaded straight into an agent, so an unchecked skill is a genuine security risk — a competing platform was once flooded with over a thousand malicious skills. The check scans both the code and the text of a skill, returns a clear pass / needs-review / blocked result, and decides how trusted the skill is allowed to be.
Why this matters
Before: The skills marketplace (#2467) lets anyone publish a SKILL.md (± tools.py/scripts) that other users install and load straight into an agent's context and tool registry. Nothing inspects a skill for malicious code, permission over-reach, or prompt-injection before it reaches users. A competing hub was flooded with 1,184 malicious skills (see #647) — an open, unaudited publish path is the single biggest risk in the whole skills feature.
After: Every skill published to the hub passes an automated security audit gate that inspects both its code and its instruction body, emits a machine-readable ALLOW / REVIEW / BLOCK verdict, and gates publication + the security tier it may claim. Trusted-from-day-one is what differentiates the GAIA marketplace, and this is the mechanism that delivers it.
This also resolves the body-injection scanning open question already flagged in both docs/spec/agent-skills and docs/plans/skill-format.
Approach — reuse what exists
Mirror the existing .github/workflows/claude-security-audit.yml pattern for the CI/LLM-assisted analysis stage.
Emit findings as the governance GovernanceDecision shape (DecisionType = ALLOW | REVIEW | BLOCK, src/gaia/governance/schemas.py:17) so verdicts are consistent with the rest of GAIA.
Hook the gate into the marketplace publish path (workers/agent-hub/src/publish.ts, Hub Worker: per-type publish + validation + R2 storage namespace #1718) so no skill enters the catalog un-audited, and expose the same engine as gaia skill audit ./skill/ so authors can self-check before publishing.
Scope
A. Audit engine (gaia skill audit)
Two analyzers over a skill directory, keyed to the two skill flavors:
Permission-truth check: does the code touch domains (network, shell, filesystem, env, …) it did not declare in metadata.gaia.permissions? A declared-vs-actual mismatch is a hard finding.
Supply-chain: flag undeclared or pinned-to-risky dependencies / node_dependencies.
Instruction analysis (all skills — the Markdown body):
Prompt-injection / jailbreak pattern scan (the body is injected into model context and is untrusted input). Resolves the specs' body-injection open question.
B. Verdict + tier gating
Output a GovernanceDecision-shaped report: ALLOW (publish proceeds), REVIEW (quarantined pending maintainer sign-off), BLOCK (publish rejected with an actionable findings report naming file/line and the fix).
Not the AMD-Verified audit policy/process (program/governance decision) — this delivers the automated gate + verdict that the human tier consumes.
Not a general repository security audit (that is claude-security-audit.yml / claude-weekly-audit.yml); this is skill-artifact-scoped.
No sandboxed runtime execution enforcement here — that is the Phase 2 permission sandbox; this is a pre-publish, static gate.
Acceptance criteria
gaia skill audit ./skill/ runs code + instruction analyzers and prints an ALLOW/REVIEW/BLOCK verdict with file:line findings.
A skill whose tools.py uses a domain not in its declared permissions is flagged (declared-vs-actual mismatch).
A skill body containing known prompt-injection patterns is flagged.
Publish is gated: BLOCK rejects, REVIEW quarantines, ALLOW writes the catalog entry with the recorded verdict + tier; a skill cannot claim a tier it did not clear.
CI workflow runs the audit on skill-submission PRs; re-audit fires on version bump.
Security findings follow the repo's private-disclosure policy; specs' body-injection open question marked resolved.
This issue adds an automatic safety check that every skill must pass before it can be published to the hub. A skill can contain both written instructions and runnable code that get loaded straight into an agent, so an unchecked skill is a genuine security risk — a competing platform was once flooded with over a thousand malicious skills. The check scans both the code and the text of a skill, returns a clear pass / needs-review / blocked result, and decides how trusted the skill is allowed to be.
Why this matters
Before: The skills marketplace (#2467) lets anyone publish a
SKILL.md(±tools.py/scripts) that other users install and load straight into an agent's context and tool registry. Nothing inspects a skill for malicious code, permission over-reach, or prompt-injection before it reaches users. A competing hub was flooded with 1,184 malicious skills (see #647) — an open, unaudited publish path is the single biggest risk in the whole skills feature.After: Every skill published to the hub passes an automated security audit gate that inspects both its code and its instruction body, emits a machine-readable
ALLOW / REVIEW / BLOCKverdict, and gates publication + the security tier it may claim. Trusted-from-day-one is what differentiates the GAIA marketplace, and this is the mechanism that delivers it.This also resolves the body-injection scanning open question already flagged in both
docs/spec/agent-skillsanddocs/plans/skill-format.Approach — reuse what exists
.github/workflows/claude-security-audit.ymlpattern for the CI/LLM-assisted analysis stage.GovernanceDecisionshape (DecisionType = ALLOW | REVIEW | BLOCK,src/gaia/governance/schemas.py:17) so verdicts are consistent with the rest of GAIA.workers/agent-hub/src/publish.ts, Hub Worker: per-type publish + validation + R2 storage namespace #1718) so no skill enters the catalog un-audited, and expose the same engine asgaia skill audit ./skill/so authors can self-check before publishing.Scope
A. Audit engine (
gaia skill audit)Two analyzers over a skill directory, keyed to the two skill flavors:
tools.py,scripts/):subprocess/shell,eval/exec, dynamic import, raw sockets/exfil, filesystem writes outside declared scope, environment/credential access.network,shell,filesystem,env, …) it did not declare inmetadata.gaia.permissions? A declared-vs-actual mismatch is a hard finding.dependencies/node_dependencies.B. Verdict + tier gating
GovernanceDecision-shaped report:ALLOW(publish proceeds),REVIEW(quarantined pending maintainer sign-off),BLOCK(publish rejected with an actionable findings report naming file/line and the fix).experimental— scan is advisory (findings surfaced, install still requires--allow-experimental).community— automated scan required to pass + publisher signature; dangerous findings forceREVIEW.verified— scan required plus the human/AMD audit hook (this issue provides the automated gate the human step builds on, not the audit policy itself).C. Publish workflow integration
BLOCK→ rejected,REVIEW→ held out of the public lane,ALLOW→ catalog entry written with the audit result + tier recorded..github/workflows/) that runs the same audit on skill-submission PRs, mirroringclaude-security-audit.yml.skill-formatalready requires) — a new version re-earns its verdict.D. Reporting
Dependencies
claude-security-audit.yml(CI pattern), governance schemas, Code-sign & notarize all Agent Hub artifacts (installers + agent binaries) #1710 (signing).agent-skills/skill-format.skill-format(needsmetadata.gaia.permissionsto run the permission-truth check).Non-goals
claude-security-audit.yml/claude-weekly-audit.yml); this is skill-artifact-scoped.Acceptance criteria
gaia skill audit ./skill/runs code + instruction analyzers and prints anALLOW/REVIEW/BLOCKverdict with file:line findings.tools.pyuses a domain not in its declaredpermissionsis flagged (declared-vs-actual mismatch).BLOCKrejects,REVIEWquarantines,ALLOWwrites the catalog entry with the recorded verdict + tier; a skill cannot claim a tier it did not clear.