[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EE9JW5YDSFDBJEPKBND009":3,"skill-same:01M6EE9JW5YDSFDBJEPKBND009":52},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":25,"linkOnly":26,"markdownContent":27,"markdownBody":27,"frontMatter":28,"refName":29,"commitSha":30,"skillDirectory":31,"forksCount":32,"repositoryHtmlUrl":33,"repositoryHomepageUrl":34,"ownerHtmlUrl":35,"ownerBlogUrl":6,"ownerDescription":36,"updatedAt":37,"install":38,"resources":51},"01M6EE9JW5YDSFDBJEPKBND009","agent-sandbox",null,"ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",66,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fagent-sandbox\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24],"sandbox","agent sandbox","2026-11-10 10:12:30",false,"# Agent Sandbox\n\n## Overview\n\nAI agents execute code, modify files, and run shell commands. Without guardrails, a bad prompt or hallucination can delete your database, overwrite production configs, or exfiltrate secrets. This skill builds safety layers — sandboxed execution, filesystem restrictions, network policies, audit trails, and kill switches.\n\n## When to Use\n\n- Running untrusted or AI-generated code in production\n- Adding safety controls to coding agents that modify your codebase\n- Restricting which files, directories, or commands an agent can access\n- Logging every agent action for compliance or debugging\n- Building multi-tenant agent platforms where agents need isolation\n\n## Instructions\n\n### Strategy 1: Filesystem + Process Sandbox (Zero Dependencies)\n\nThe simplest safety layer — restrict which paths the agent can read\u002Fwrite and which commands it can execute. No Docker required.\n\n```typescript\n\u002F\u002F sandbox.ts — Filesystem and process sandbox for AI agents\n\u002F**\n * Wraps agent operations with safety checks:\n * - Allowlist\u002Fdenylist for file paths\n * - Command blocklist (rm -rf, DROP TABLE, etc.)\n * - Audit log of every action\n * - Kill switch to halt agent immediately\n *\u002F\nimport { execSync } from \"child_process\";\nimport { readFileSync, writeFileSync, existsSync, appendFileSync } from \"fs\";\nimport { resolve, relative } from \"path\";\n\ninterface SandboxConfig {\n  workDir: string;                    \u002F\u002F Root directory agent can access\n  allowedPaths: string[];             \u002F\u002F Glob patterns of allowed paths\n  deniedPaths: string[];              \u002F\u002F Glob patterns of denied paths\n  blockedCommands: string[];          \u002F\u002F Commands that are never allowed\n  maxFileSize: number;                \u002F\u002F Max bytes per file write\n  auditLog: string;                   \u002F\u002F Path to audit log file\n  readOnly: boolean;                  \u002F\u002F If true, block all writes\n}\n\nconst DEFAULT_BLOCKED = [\n  \"rm -rf \u002F\", \"rm -rf ~\", \"rm -rf .\",\n  \"mkfs\", \"dd if=\", \"> \u002Fdev\u002Fsd\",\n  \"DROP DATABASE\", \"DROP TABLE\", \"TRUNCATE\",\n  \"curl.*|.*sh\", \"wget.*|.*bash\",           \u002F\u002F Pipe to shell\n  \"chmod 777\", \"chmod -R 777\",\n  \"env | curl\", \"printenv | curl\",           \u002F\u002F Secret exfiltration\n  \"ssh-keygen\", \"ssh-copy-id\",\n];\n\nexport class AgentSandbox {\n  private config: SandboxConfig;\n  private killed = false;\n\n  constructor(config: Partial\u003CSandboxConfig> & { workDir: string }) {\n    this.config = {\n      allowedPaths: [\"**\"],\n      deniedPaths: [\"**\u002F.env\", \"**\u002F.ssh\u002F**\", \"**\u002Fnode_modules\u002F**\"],\n      blockedCommands: DEFAULT_BLOCKED,\n      maxFileSize: 1024 * 1024,  \u002F\u002F 1MB default\n      auditLog: \".\u002Fagent-audit.jsonl\",\n      readOnly: false,\n      ...config,\n    };\n  }\n\n  \u002F**\n   * Read a file through the sandbox — checks path is allowed.\n   *\u002F\n  readFile(filePath: string): string {\n    this.checkKilled();\n    const absPath = resolve(this.config.workDir, filePath);\n    this.checkPathAllowed(absPath, \"read\");\n    this.audit(\"read\", filePath);\n    return readFileSync(absPath, \"utf-8\");\n  }\n\n  \u002F**\n   * Write a file through the sandbox — checks path, size, and read-only mode.\n   *\u002F\n  writeFile(filePath: string, content: string): void {\n    this.checkKilled();\n    if (this.config.readOnly) {\n      throw new SandboxError(\"Write blocked: sandbox is read-only\");\n    }\n\n    const absPath = resolve(this.config.workDir, filePath);\n    this.checkPathAllowed(absPath, \"write\");\n\n    if (Buffer.byteLength(content) > this.config.maxFileSize) {\n      throw new SandboxError(\n        `Write blocked: file exceeds max size (${this.config.maxFileSize} bytes)`\n      );\n    }\n\n    this.audit(\"write\", filePath, { size: Buffer.byteLength(content) });\n    writeFileSync(absPath, content);\n  }\n\n  \u002F**\n   * Execute a command through the sandbox — checks against blocklist.\n   *\u002F\n  exec(command: string, timeoutMs: number = 30000): string {\n    this.checkKilled();\n    this.checkCommandAllowed(command);\n    this.audit(\"exec\", command);\n\n    try {\n      return execSync(command, {\n        cwd: this.config.workDir,\n        encoding: \"utf-8\",\n        timeout: timeoutMs,\n        maxBuffer: 10 * 1024 * 1024,  \u002F\u002F 10MB output limit\n      });\n    } catch (error: any) {\n      this.audit(\"exec_error\", command, { error: error.message });\n      throw error;\n    }\n  }\n\n  \u002F**\n   * Kill switch — immediately halt all agent operations.\n   *\u002F\n  kill(reason: string): void {\n    this.killed = true;\n    this.audit(\"killed\", reason);\n    console.error(`? Agent sandbox killed: ${reason}`);\n  }\n\n  private checkKilled(): void {\n    if (this.killed) throw new SandboxError(\"Agent has been killed\");\n  }\n\n  private checkPathAllowed(absPath: string, operation: string): void {\n    const relPath = relative(this.config.workDir, absPath);\n\n    \u002F\u002F Must be within workDir (no ..\u002F escapes)\n    if (relPath.startsWith(\"..\")) {\n      throw new SandboxError(`${operation} blocked: path escapes sandbox (${relPath})`);\n    }\n\n    \u002F\u002F Check denylist\n    for (const pattern of this.config.deniedPaths) {\n      if (matchGlob(relPath, pattern)) {\n        throw new SandboxError(`${operation} blocked: path matches denylist (${pattern})`);\n      }\n    }\n  }\n\n  private checkCommandAllowed(command: string): void {\n    const lower = command.toLowerCase();\n    for (const blocked of this.config.blockedCommands) {\n      if (lower.includes(blocked.toLowerCase())) {\n        throw new SandboxError(`Command blocked: matches \"${blocked}\"`);\n      }\n    }\n  }\n\n  private audit(action: string, target: string, extra?: Record\u003Cstring, unknown>): void {\n    const entry = {\n      timestamp: new Date().toISOString(),\n      action,\n      target,\n      ...extra,\n    };\n    appendFileSync(this.config.auditLog, JSON.stringify(entry) + \"\\n\");\n  }\n}\n\nclass SandboxError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"SandboxError\";\n  }\n}\n\nfunction matchGlob(path: string, pattern: string): boolean {\n  const regex = pattern\n    .replace(\u002F\\*\\*\u002Fg, \".*\")\n    .replace(\u002F\\*\u002Fg, \"[^\u002F]*\")\n    .replace(\u002F\\?\u002Fg, \".\");\n  return new RegExp(`^${regex}$`).test(path);\n}\n```\n\n### Strategy 2: Docker Container Sandbox\n\nFor full isolation — the agent runs inside a container with limited CPU, memory, network, and filesystem access.\n\n```typescript\n\u002F\u002F docker-sandbox.ts — Run agent code in isolated Docker containers\n\u002F**\n * Spawns a Docker container for each agent session.\n * Mounts only the allowed workspace directory (read-only optional).\n * Enforces CPU, memory, and network limits.\n * Auto-kills containers that exceed time limits.\n *\u002F\nimport { execSync, spawn } from \"child_process\";\n\ninterface DockerSandboxConfig {\n  image: string;                 \u002F\u002F Base image (e.g., \"node:20-slim\")\n  workDir: string;               \u002F\u002F Host directory to mount\n  readOnly: boolean;             \u002F\u002F Mount workspace as read-only\n  cpuLimit: string;              \u002F\u002F CPU limit (e.g., \"1.0\" = 1 core)\n  memoryLimit: string;           \u002F\u002F Memory limit (e.g., \"512m\")\n  networkMode: string;           \u002F\u002F \"none\" for no network, \"bridge\" for limited\n  timeoutSeconds: number;        \u002F\u002F Kill container after this many seconds\n  allowedEnvVars: string[];      \u002F\u002F Env vars to pass through\n}\n\nexport class DockerSandbox {\n  private config: DockerSandboxConfig;\n  private containerId: string | null = null;\n\n  constructor(config: Partial\u003CDockerSandboxConfig> & { workDir: string }) {\n    this.config = {\n      image: \"node:20-slim\",\n      readOnly: false,\n      cpuLimit: \"1.0\",\n      memoryLimit: \"512m\",\n      networkMode: \"none\",        \u002F\u002F No network by default\n      timeoutSeconds: 300,        \u002F\u002F 5 minutes max\n      allowedEnvVars: [],\n      ...config,\n    };\n  }\n\n  \u002F**\n   * Start the sandbox container.\n   *\u002F\n  async start(): Promise\u003Cstring> {\n    const mountFlag = this.config.readOnly ? \"ro\" : \"rw\";\n    const envFlags = this.config.allowedEnvVars\n      .map((v) => `-e ${v}`)\n      .join(\" \");\n\n    const cmd = [\n      \"docker run -d\",\n      `--cpus=${this.config.cpuLimit}`,\n      `--memory=${this.config.memoryLimit}`,\n      `--network=${this.config.networkMode}`,\n      \"--security-opt=no-new-privileges\",    \u002F\u002F No privilege escalation\n      \"--read-only\",                          \u002F\u002F Root FS read-only\n      \"--tmpfs \u002Ftmp:size=100m\",              \u002F\u002F Writable tmp with size limit\n      `-v ${this.config.workDir}:\u002Fworkspace:${mountFlag}`,\n      `-w \u002Fworkspace`,\n      envFlags,\n      this.config.image,\n      \"tail -f \u002Fdev\u002Fnull\",                   \u002F\u002F Keep container alive\n    ].join(\" \");\n\n    this.containerId = execSync(cmd, { encoding: \"utf-8\" }).trim();\n\n    \u002F\u002F Auto-kill timer\n    setTimeout(() => this.kill(\"timeout\"), this.config.timeoutSeconds * 1000);\n\n    return this.containerId;\n  }\n\n  \u002F**\n   * Execute a command inside the sandbox container.\n   *\u002F\n  exec(command: string): string {\n    if (!this.containerId) throw new Error(\"Sandbox not started\");\n    return execSync(\n      `docker exec ${this.containerId} sh -c '${command.replace(\u002F'\u002Fg, \"'\\\\''\")}'`,\n      { encoding: \"utf-8\", timeout: 60000 }\n    );\n  }\n\n  \u002F**\n   * Kill the sandbox container and remove it.\n   *\u002F\n  kill(reason: string = \"manual\"): void {\n    if (this.containerId) {\n      console.log(`? Killing sandbox: ${reason}`);\n      execSync(`docker kill ${this.containerId} && docker rm ${this.containerId}`, {\n        encoding: \"utf-8\",\n      });\n      this.containerId = null;\n    }\n  }\n}\n```\n\n## Examples\n\n### Example 1: Add safety controls to a coding agent\n\n**User prompt:** \"I want my AI coding agent to only modify files in the src\u002F directory and never touch .env files or run destructive commands.\"\n\nThe agent will:\n- Create an AgentSandbox with workDir pointing to the project root\n- Set allowedPaths to `[\"src\u002F**\", \"tests\u002F**\"]`\n- Set deniedPaths to `[\"**\u002F.env*\", \"**\u002F.ssh\u002F**\", \"**\u002Fsecrets\u002F**\"]`\n- Enable audit logging to track every agent action\n- Wrap all file operations and command executions through the sandbox\n\n### Example 2: Run untrusted code in Docker isolation\n\n**User prompt:** \"We're building a code execution platform. User-submitted code needs to run in isolation with no network access, 512MB memory, and a 30-second timeout.\"\n\nThe agent will:\n- Set up DockerSandbox with networkMode \"none\", memory 512m, timeout 30s\n- Mount user code directory as read-only\n- Enable writable \u002Ftmp with 100MB limit for temporary files\n- Add security-opt no-new-privileges to prevent escalation\n- Implement cleanup on timeout or completion\n\n## Guidelines\n\n- **Default to deny** — block everything, then allowlist what the agent needs\n- **No Docker socket access** — mounting docker.sock gives root on the host\n- **Audit everything** — log every file read, write, and command for forensics\n- **Time limits prevent infinite loops** — always set exec timeouts\n- **Network \"none\" by default** — agents shouldn't make outbound calls unless explicitly needed\n- **Read-only mounts when possible** — agents that only analyze code don't need write access\n- **Separate audit logs from agent workspace** — the agent shouldn't be able to modify its own audit trail\n- **Test the sandbox itself** — try to escape it before trusting it with real data\n- **Kill switches save you** — always have a way to halt the agent immediately\n- **Container cleanup** — always `docker rm` after container stops to avoid disk waste\n",{},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002FTerminalSkills\u002Fskills\u002Fagent-sandbox",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":7,"skillName":5,"commands":39,"prompt":49,"zipAvailable":50},[40,43,46],{"tool":41,"command":42},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill agent-sandbox",{"tool":44,"command":45},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill agent-sandbox",{"tool":47,"command":48},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill agent-sandbox","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002FTerminalSkills\u002Fskills\u002Fagent-sandbox\u002FSKILL.md",true,[],[53,63,73,82,88,95],{"skillNo":54,"name":55,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":56,"categories":57,"keywords":59,"publishedAt":25},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[58],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[60,61,62],"model","model hierarchy","model hierarchy skill",{"skillNo":64,"name":65,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":66,"categories":67,"keywords":69,"publishedAt":25},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[68],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[70,71,72],"MCP","zoom","zoom mcp",{"skillNo":74,"name":75,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":78,"publishedAt":25},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[79,80,81,71],"sdk","zoom apps sdk","apps",{"skillNo":83,"name":84,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":25},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[84],{"skillNo":89,"name":90,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":91,"categories":92,"keywords":94,"publishedAt":25},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[93],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[90],{"skillNo":96,"name":97,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":25},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[97]]