Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@ The open network feeds the premium layer. The premium layer funds the open netwo
## 📦 What's inside (today)

> **The registry is live and growing every week. All packages are free to download, fork and run.**
> The **In this repo** column is the open seed you can `git clone` today; the **Hosted registry** column is the full, continuously-evolved library on [superagentskill.com](https://superagentskill.com/marketplace).

| Type | Count | Examples |
|---|---|---|
| 🛠 **Skills** | **370+** | code review, OWASP audit, SQL translator, OSINT, ECG triage, MEDDPICC discovery |
| 📘 **Playbooks** | **30+** | bug triage → fix → PR, content pipeline, incident response |
| 🎭 **Souls** | **50+** | pragmatic SRE, empathetic support, senior product designer |
| 🛡 **Guardrails** | **50+** | no-PII, no-medical-advice, GDPR, brand safety |
| Type | In this repo (open seed) | Hosted registry | Examples |
|---|---|---|---|
| 🛠 **Skills** | **76** | **370+** | code review, OWASP audit, SQL translator, OSINT, ECG triage, MEDDPICC discovery |
| 📘 **Playbooks** | **2** | **30+** | bug triage → fix → PR, content pipeline, incident response |
| 🎭 **Souls** | **6** | **50+** | pragmatic SRE, empathetic support, senior product designer |
| 🛡 **Guardrails** | **2** | **50+** | no-PII, no-medical-advice, GDPR, brand safety |

➡️ **[Browse the full marketplace at superagentskill.com →](https://superagentskill.com/marketplace)**

Expand Down Expand Up @@ -100,6 +101,7 @@ bun install && bun run dev

- 🛡 **Proprietary adversarial harness.** Every skill is benchmarked against attacks before it can publish — prompt injection, jailbreaks, exfiltration, blast-radius, policy bypass, PII/PHI leakage. Cases are curated per vertical (OWASP LLM, FINRA, HIPAA Safe Harbor, PCI-DSS, SRE).
- 🔏 **Ed25519-signed releases.** Every published version is cryptographically signed. Verify offline with `npm run release:verify` — exactly what air-gapped enterprise customers need.
- 🧾 **Signed per-package trust attestations.** `npm run trust:attest` binds a package's exact content hash + version to its adversarial result and signs it with the release key. Your security team runs `npm run trust:verify -- --attestation pkg.trust.json --pkg pkg.yaml --pubkey pub.pem` and confirms offline that *this exact file* passed *N* adversarial cases — no need to trust the hosted Trust Score endpoint.
- 📊 **Public, verifiable Trust Score.** A transparent weighted formula over adversarial robustness, real-world success rate, signed releases and package age. Embed the badge in your README; reviewers see the same number you do.
- 🏛 **Verticalized Souls.** Fintech compliance officer (FINRA / Reg E / PCI-DSS), HIPAA-aware clinical liaison, SOC 2 auditor (TSC-mapped), Kubernetes SRE (blast-radius-first). Souls that cite the rule before the recommendation.
- 🔌 **One MCP endpoint, every IDE.** Claude, Cursor, ChatGPT, Continue, Cline — same URL, same `npx super-agent install <slug>` command. No SDK, no glue code.
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"preview": "vite preview",
"lint": "eslint .",
"format": "prettier --write .",
"validate:content": "node scripts/validate-content.mjs",
"validate:content": "node --experimental-strip-types scripts/validate-content.mjs",
"sync:content": "node scripts/sync-content-to-registry.mjs",
"sync:adversarial": "node scripts/sync-adversarial-cases.mjs",
"eval:adversarial": "node scripts/eval-adversarial.mjs",
Expand All @@ -19,8 +19,10 @@
"release:sign": "node scripts/sign-release-bundle.mjs",
"release:verify": "node scripts/verify-release-bundle.mjs",
"release:changelog": "node scripts/generate-changelog.mjs",
"trust:attest": "node scripts/generate-trust-attestation.mjs",
"trust:verify": "node scripts/verify-trust-attestation.mjs",
"test": "npm run test:plain && npm run test:ts",
"test:plain": "node --test tests/adversarial-harness.test.mjs tests/trust.test.mjs tests/release-signing.test.mjs tests/cli-install.test.mjs",
"test:plain": "node --test tests/adversarial-harness.test.mjs tests/trust.test.mjs tests/release-signing.test.mjs tests/cli-install.test.mjs tests/trust-attestation.test.mjs",
"test:ts": "node --experimental-strip-types --test tests/prompt-injection-guard.test.mjs tests/runtime.test.mjs tests/integrations.test.mjs tests/growth-revenue-split.test.mjs tests/trust-badge.test.mjs tests/bounties.test.mjs"
},
"dependencies": {
Expand Down
119 changes: 119 additions & 0 deletions scripts/generate-trust-attestation.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env node
// Produces a signed, independently-verifiable trust attestation for a single
// package. It binds the package's exact content hash + version to the result
// of the adversarial harness, signed with the same Ed25519 release key
// (sign-release-bundle.mjs). A security team can hand the attestation +
// the package file to verify-trust-attestation.mjs and confirm offline that
// "this exact file passed N adversarial cases at score X" — no need to trust
// the hosted Trust Score endpoint.
//
// Usage:
// node scripts/eval-adversarial.mjs --skill code-reviewer --mock --out eval.json
// SIGNING_PRIVATE_KEY=$(cat priv.pem) SIGNING_PUBLIC_KEY=$(cat pub.pem) \
// node scripts/generate-trust-attestation.mjs \
// --pkg content/skills/code-reviewer.yaml --eval eval.json

import { createHash, createPrivateKey, createPublicKey, sign } from "node:crypto";
import { readFileSync, writeFileSync } from "node:fs";
import { basename } from "node:path";

const args = parse(process.argv.slice(2));
const pkgPath = args.pkg;
const evalPath = args.eval;
if (!pkgPath || !evalPath) {
console.error("Usage: --pkg <package.yaml> --eval <eval-report.json> [--out <file>]");
process.exit(1);
}

const { SIGNING_PRIVATE_KEY, SIGNING_PUBLIC_KEY } = process.env;
if (!SIGNING_PRIVATE_KEY || !SIGNING_PUBLIC_KEY) {
console.error("SIGNING_PRIVATE_KEY and SIGNING_PUBLIC_KEY env vars required (PEM contents).");
process.exit(1);
}
const priv = createPrivateKey(SIGNING_PRIVATE_KEY);
const pubDer = createPublicKey(SIGNING_PUBLIC_KEY).export({ format: "der", type: "spki" });
const keyId = createHash("sha256").update(pubDer).digest("hex").slice(0, 16);

const pkgBytes = readFileSync(pkgPath);
const pkgText = pkgBytes.toString("utf8");
const contentSha256 = createHash("sha256").update(pkgBytes).digest("hex");

// Top-level scalar fields only — enough to cross-check identity against the
// eval report. Avoids a YAML dependency so this stays in lockstep with the
// dependency-free offline verifier.
function topScalar(key) {
const m = pkgText.match(new RegExp(`^${key}:[ \\t]*["']?([^"'\\n#]+?)["']?[ \\t]*(?:#.*)?$`, "m"));
return m ? m[1].trim() : undefined;
}
const pkgSlug = topScalar("slug");
const pkgVersion = topScalar("version");
const pkgType = topScalar("type");

const report = JSON.parse(readFileSync(evalPath, "utf8"));
const rp = report.package ?? {};
if (rp.slug && pkgSlug && rp.slug !== pkgSlug) {
console.error(`✗ eval report is for slug "${rp.slug}" but package file is "${pkgSlug}"`);
process.exit(2);
}
if (rp.version && pkgVersion && rp.version !== pkgVersion) {
console.error(`✗ eval report is for version "${rp.version}" but package file is "${pkgVersion}"`);
process.exit(2);
}

const payload = {
schema_version: 1,
attested_at: new Date().toISOString(),
package: {
type: pkgType ?? rp.type ?? null,
slug: pkgSlug ?? rp.slug ?? null,
version: pkgVersion ?? rp.version ?? null,
file: basename(pkgPath),
},
content_sha256: contentSha256,
adversarial: {
total: report.total ?? 0,
passed: report.passed ?? 0,
failed: report.failed ?? 0,
pass_rate: report.pass_rate ?? 0,
severity_weighted_score: report.severity_weighted_score ?? 0,
by_severity: report.by_severity ?? {},
},
};

const canonical = stableStringify(payload);
const payloadHash = createHash("sha256").update(canonical).digest("hex");
const signature = sign(null, Buffer.from(payloadHash), priv).toString("base64");

const attestation = { ...payload, signing_key_id: keyId, algorithm: "ed25519", signature };
const outPath = args.out ?? `${payload.package.slug ?? "package"}.trust.json`;
writeFileSync(outPath, `${JSON.stringify(attestation, null, 2)}\n`);

console.log(`✓ trust attestation written: ${outPath}`);
console.log(` package: ${payload.package.type}:${payload.package.slug}@${payload.package.version}`);
console.log(` content: sha256:${contentSha256.slice(0, 16)}…`);
console.log(` adversarial: ${payload.adversarial.passed}/${payload.adversarial.total} cases, score ${(payload.adversarial.severity_weighted_score * 100).toFixed(1)}%`);
console.log(` signed by: key_id=${keyId}`);

// Deterministic JSON: object keys sorted recursively so the signed bytes are
// reproducible regardless of insertion order.
function stableStringify(value) {
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
if (value && typeof value === "object") {
return `{${Object.keys(value)
.sort()
.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`)
.join(",")}}`;
}
return JSON.stringify(value);
}

function parse(argv) {
const o = {};
for (let i = 0; i < argv.length; i++) {
if (!argv[i].startsWith("--")) continue;
const k = argv[i].slice(2), n = argv[i + 1];
if (!n || n.startsWith("--")) o[k] = true;
else { o[k] = n; i++; }
}
return o;
}
29 changes: 27 additions & 2 deletions scripts/validate-content.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { readdirSync, readFileSync, statSync } from "node:fs";
import { join, basename } from "node:path";
import Ajv from "ajv";
import { parse as parseYaml } from "yaml";
import { inspectContent } from "../src/lib/security/prompt-injection-guard.ts";

const ROOT = new URL("..", import.meta.url).pathname;
const TYPES = ["skill", "playbook", "soul", "guardrail", "integration"];
Expand All @@ -26,6 +27,7 @@ const adversarialSchema = JSON.parse(
const validateAdversarial = ajv.compile(adversarialSchema);

let errors = 0;
let warnings = 0;
const slugs = new Map(); // slug -> file
const adversarialIds = new Map(); // id -> file

Expand Down Expand Up @@ -64,6 +66,21 @@ for (const type of TYPES) {
} else {
slugs.set(pkg.slug, full);
}

// Prompt-injection gate for community contributions. The MCP upload path
// already scans (lib/uploads/uploads.server.ts); this closes the same hole
// for packages added via PR/git. `critical` signals (fake SYSTEM/control
// tokens, secret-exfiltration URLs) block the build; `high` is reported as
// a non-fatal warning since legitimate skill prose ("run this skill with
// …") trips the heuristic. Skills that legitimately demonstrate attacks
// (e.g. a prompt-injection tester) set `x_security_research: true` to opt
// out of the warning.
const guard = inspectContent(readFileSync(full, "utf8"), { fence: false });
if (guard.severity === "critical") {
fail(full, `prompt-injection: critical signal(s) — ${guard.findings.filter((g) => g.severity === "critical").map((g) => g.pattern).join("; ")}`);
} else if ((guard.severity === "high" || guard.severity === "medium") && pkg.x_security_research !== true) {
warn(full, `prompt-injection: ${guard.severity} signal(s) — ${guard.findings.map((g) => g.pattern).join("; ")} (set x_security_research: true if intentional)`);
}
}
}

Expand Down Expand Up @@ -114,8 +131,16 @@ function fail(file, msg) {
console.error(`\u001b[31m✗\u001b[0m ${file.replace(ROOT, "")}: ${msg}`);
}

function warn(file, msg) {
warnings++;
console.warn(`⚠ ${file.replace(ROOT, "")}: ${msg}`);
}

if (errors > 0) {
console.error(`\n${errors} validation error(s).`);
console.error(`\n${errors} validation error(s)${warnings ? `, ${warnings} warning(s)` : ""}.`);
process.exit(1);
}
console.log(`✓ ${slugs.size} package(s) and ${adversarialIds.size} adversarial case(s) validated.`);
console.log(
`✓ ${slugs.size} package(s) and ${adversarialIds.size} adversarial case(s) validated.` +
(warnings ? ` ${warnings} warning(s)` : ""),
);
95 changes: 95 additions & 0 deletions scripts/verify-trust-attestation.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env node
// Offline verifier for a trust attestation produced by
// generate-trust-attestation.mjs. Designed to be run by a consumer's security
// team with nothing but: the package file, the .trust.json, and the publisher's
// SIGNING_PUBLIC_KEY.pem. No network, no trust in the hosted registry.
//
// Usage:
// node scripts/verify-trust-attestation.mjs \
// --attestation code-reviewer.trust.json \
// --pkg content/skills/code-reviewer.yaml \
// --pubkey pub.pem
//
// Exits non-zero if the package was tampered with or the signature is invalid.

import { createHash, createPublicKey, verify } from "node:crypto";
import { readFileSync } from "node:fs";

const args = parse(process.argv.slice(2));
if (!args.attestation || !args.pkg) {
console.error("Usage: --attestation <file.trust.json> --pkg <package.yaml> [--pubkey <pub.pem>]");
process.exit(1);
}

const att = JSON.parse(readFileSync(args.attestation, "utf8"));
const pubPem = args.pubkey
? readFileSync(args.pubkey, "utf8")
: process.env.SIGNING_PUBLIC_KEY;
if (!pubPem) {
console.error("Provide --pubkey <pem> or SIGNING_PUBLIC_KEY env (PEM contents).");
process.exit(1);
}
const pubKey = createPublicKey(pubPem);
const pubDer = pubKey.export({ format: "der", type: "spki" });
const fingerprint = createHash("sha256").update(pubDer).digest("hex").slice(0, 16);

let failed = 0;

if (fingerprint !== att.signing_key_id) {
console.error(`✗ public key fingerprint mismatch: attestation=${att.signing_key_id} key=${fingerprint}`);
failed++;
}

const pkgBytes = readFileSync(args.pkg);
const contentSha256 = createHash("sha256").update(pkgBytes).digest("hex");
if (contentSha256 !== att.content_sha256) {
console.error(`✗ package content changed since attestation`);
console.error(` attested: sha256:${att.content_sha256}`);
console.error(` actual: sha256:${contentSha256}`);
failed++;
}

const { signature, signing_key_id: _kid, algorithm: _alg, ...payload } = att;
const payloadHash = createHash("sha256").update(stableStringify(payload)).digest("hex");
const sigOk = signature
? verify(null, Buffer.from(payloadHash), pubKey, Buffer.from(signature, "base64"))
: false;
if (!sigOk) {
console.error(`✗ invalid signature — attestation body does not match the signature`);
failed++;
}

if (failed > 0) {
console.error(`\n${failed} verification failure(s). DO NOT trust this package.`);
process.exit(3);
}

const a = att.adversarial ?? {};
console.log(`✓ trust attestation VERIFIED`);
console.log(` package: ${att.package?.type}:${att.package?.slug}@${att.package?.version}`);
console.log(` content: sha256:${contentSha256} (matches)`);
console.log(` attested at: ${att.attested_at}`);
console.log(` adversarial: ${a.passed}/${a.total} cases passed, severity-weighted ${(((a.severity_weighted_score) ?? 0) * 100).toFixed(1)}%`);
console.log(` signed by: key_id=${fingerprint}`);

function stableStringify(value) {
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
if (value && typeof value === "object") {
return `{${Object.keys(value)
.sort()
.map((k) => `${JSON.stringify(k)}:${stableStringify(value[k])}`)
.join(",")}}`;
}
return JSON.stringify(value);
}

function parse(argv) {
const o = {};
for (let i = 0; i < argv.length; i++) {
if (!argv[i].startsWith("--")) continue;
const k = argv[i].slice(2), n = argv[i + 1];
if (!n || n.startsWith("--")) o[k] = true;
else { o[k] = n; i++; }
}
return o;
}
Loading
Loading