[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6FADHB5ZQQWFJWN9FARNBK9":3,"skill-same:01M6FADHB5ZQQWFJWN9FARNBK9":84},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":61,"commitSha":62,"skillDirectory":63,"forksCount":64,"repositoryHtmlUrl":65,"repositoryHomepageUrl":66,"ownerHtmlUrl":67,"ownerBlogUrl":6,"ownerDescription":68,"updatedAt":69,"install":70,"resources":83},"01M6FADHB5ZQQWFJWN9FARNBK9","exa-security-basics",null,"Secure Exa API keys, implement content moderation, and manage domain restrictions.\nUse when securing API keys, auditing Exa security configuration,\nor implementing content safety filtering.\nTrigger with phrases like \"exa security\", \"exa secrets\",\n\"secure exa\", \"exa API key security\", \"exa content moderation\".","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fexa-security-basics\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"security","exa security basics","exa","basics","Content Moderation","Safety","api","secrets","read","write","moderation","filtering","code","manage","secure","domain","content safety","io","trigger","openclaw","2026-11-10 10:12:30",false,"---\nname: exa-security-basics\ndescription: |\n  Secure Exa API keys, implement content moderation, and manage domain restrictions.\n  Use when securing API keys, auditing Exa security configuration,\n  or implementing content safety filtering.\n  Trigger with phrases like \"exa security\", \"exa secrets\",\n  \"secure exa\", \"exa API key security\", \"exa content moderation\".\nallowed-tools: Read, Write, Grep\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\ncompatible-with: claude-code, codex, openclaw\ntags: [saas, exa, api, security]\n\n---\n# Exa Security Basics\n\n## Overview\nSecurity best practices for Exa API integrations. Exa authenticates via the `x-api-key` header. Key security concerns include API key protection, content moderation for search results, domain filtering to prevent exposure to malicious sources, and query sanitization.\n\n## Prerequisites\n- Exa API key from dashboard.exa.ai\n- Understanding of environment variable management\n- `.gitignore` configured for secrets\n\n## Instructions\n\n### Step 1: API Key Management\n```bash\n# .env (NEVER commit to git)\nEXA_API_KEY=your-api-key-here\n\n# .gitignore — add these entries\n.env\n.env.local\n.env.*.local\n```\n\n```typescript\n\u002F\u002F Validate API key exists before creating client\nimport Exa from \"exa-js\";\n\nfunction createSecureClient(): Exa {\n  const apiKey = process.env.EXA_API_KEY;\n  if (!apiKey) {\n    throw new Error(\"EXA_API_KEY not configured\");\n  }\n  if (apiKey.startsWith(\"sk_\") && apiKey.length \u003C 20) {\n    throw new Error(\"EXA_API_KEY appears malformed\");\n  }\n  return new Exa(apiKey);\n}\n```\n\n### Step 2: Enable Content Moderation\n```typescript\nconst exa = new Exa(process.env.EXA_API_KEY);\n\n\u002F\u002F Exa supports content moderation to filter unsafe results\nconst results = await exa.searchAndContents(\n  \"user-provided search query\",\n  {\n    numResults: 10,\n    text: true,\n    moderation: true,  \u002F\u002F filter unsafe content from results\n  }\n);\n```\n\n### Step 3: Domain Filtering for Safety\n```typescript\n\u002F\u002F Restrict results to trusted domains for sensitive use cases\nconst TRUSTED_DOMAINS = [\n  \"docs.python.org\", \"developer.mozilla.org\", \"nodejs.org\",\n  \"github.com\", \"stackoverflow.com\", \"arxiv.org\",\n];\n\nconst BLOCKED_DOMAINS = [\n  \"known-malware-site.com\", \"phishing-domain.net\",\n];\n\nasync function safeDomainSearch(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 10,\n    includeDomains: TRUSTED_DOMAINS,  \u002F\u002F only return results from these\n    text: { maxCharacters: 1000 },\n  });\n}\n\nasync function searchWithBlocklist(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 10,\n    excludeDomains: BLOCKED_DOMAINS,  \u002F\u002F never return results from these\n    text: { maxCharacters: 1000 },\n  });\n}\n```\n\n### Step 4: Query Sanitization\n```typescript\n\u002F\u002F Sanitize user-provided queries before sending to Exa\nfunction sanitizeQuery(input: string): string {\n  \u002F\u002F Remove potential injection patterns\n  let clean = input\n    .replace(\u002F[\u003C>{}]\u002Fg, \"\")           \u002F\u002F strip HTML\u002Ftemplate chars\n    .replace(\u002F\\0\u002Fg, \"\")              \u002F\u002F remove null bytes\n    .trim()\n    .substring(0, 500);              \u002F\u002F cap query length\n\n  if (!clean || clean.length \u003C 2) {\n    throw new Error(\"Query too short or empty after sanitization\");\n  }\n  return clean;\n}\n\n\u002F\u002F Usage\nconst userQuery = sanitizeQuery(req.body.query);\nconst results = await exa.search(userQuery, {\n  numResults: 10,\n  moderation: true,\n});\n```\n\n### Step 5: Per-Environment Key Isolation\n```typescript\n\u002F\u002F Use separate API keys per environment\nconst KEY_MAP: Record\u003Cstring, string> = {\n  development: process.env.EXA_API_KEY_DEV!,\n  staging: process.env.EXA_API_KEY_STAGING!,\n  production: process.env.EXA_API_KEY_PROD!,\n};\n\nfunction getExaForEnv(): Exa {\n  const env = process.env.NODE_ENV || \"development\";\n  const key = KEY_MAP[env];\n  if (!key) throw new Error(`No EXA key for ${env}`);\n  return new Exa(key);\n}\n```\n\n## Security Checklist\n- [ ] API key stored in environment variables (never hardcoded)\n- [ ] `.env` files in `.gitignore`\n- [ ] Separate API keys for dev\u002Fstaging\u002Fproduction\n- [ ] `moderation: true` enabled for user-facing search\n- [ ] Query input sanitized before API calls\n- [ ] Domain allowlist\u002Fblocklist applied for sensitive use cases\n- [ ] API key rotation procedure documented\n- [ ] Git history scanned for accidentally committed keys\n\n## Error Handling\n| Security Issue | Detection | Mitigation |\n|----------------|-----------|------------|\n| Exposed API key | `git log -p` search | Rotate key immediately at dashboard.exa.ai |\n| Unsafe search results | User reports | Enable `moderation: true` |\n| Untrusted domains | Review result URLs | Apply `includeDomains` filter |\n| Query injection | Input validation | Sanitize before search |\n\n## Examples\n\n### Scan Git History for Leaked Keys\n```bash\nset -euo pipefail\n# Check if API key was ever committed\ngit log -p --all -S \"EXA_API_KEY\" -- \"*.ts\" \"*.js\" \"*.py\" \"*.env\" | head -20\n```\n\n### Key Rotation Procedure\n```bash\nset -euo pipefail\n# 1. Generate new key in dashboard.exa.ai\n# 2. Update environment\nexport EXA_API_KEY=\"new-key-here\"\n# 3. Verify new key works\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n  -X POST https:\u002F\u002Fapi.exa.ai\u002Fsearch \\\n  -H \"x-api-key: $EXA_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"test\",\"numResults\":1}'\n# 4. Revoke old key in dashboard\n```\n\n## Resources\n- [Exa API Authentication](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Fgetting-started)\n- [Exa Error Codes](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Ferror-codes)\n\n## Next Steps\nFor production deployment, see `exa-prod-checklist`.\n\n","# Exa Security Basics\n\n## Overview\nSecurity best practices for Exa API integrations. Exa authenticates via the `x-api-key` header. Key security concerns include API key protection, content moderation for search results, domain filtering to prevent exposure to malicious sources, and query sanitization.\n\n## Prerequisites\n- Exa API key from dashboard.exa.ai\n- Understanding of environment variable management\n- `.gitignore` configured for secrets\n\n## Instructions\n\n### Step 1: API Key Management\n```bash\n# .env (NEVER commit to git)\nEXA_API_KEY=your-api-key-here\n\n# .gitignore — add these entries\n.env\n.env.local\n.env.*.local\n```\n\n```typescript\n\u002F\u002F Validate API key exists before creating client\nimport Exa from \"exa-js\";\n\nfunction createSecureClient(): Exa {\n  const apiKey = process.env.EXA_API_KEY;\n  if (!apiKey) {\n    throw new Error(\"EXA_API_KEY not configured\");\n  }\n  if (apiKey.startsWith(\"sk_\") && apiKey.length \u003C 20) {\n    throw new Error(\"EXA_API_KEY appears malformed\");\n  }\n  return new Exa(apiKey);\n}\n```\n\n### Step 2: Enable Content Moderation\n```typescript\nconst exa = new Exa(process.env.EXA_API_KEY);\n\n\u002F\u002F Exa supports content moderation to filter unsafe results\nconst results = await exa.searchAndContents(\n  \"user-provided search query\",\n  {\n    numResults: 10,\n    text: true,\n    moderation: true,  \u002F\u002F filter unsafe content from results\n  }\n);\n```\n\n### Step 3: Domain Filtering for Safety\n```typescript\n\u002F\u002F Restrict results to trusted domains for sensitive use cases\nconst TRUSTED_DOMAINS = [\n  \"docs.python.org\", \"developer.mozilla.org\", \"nodejs.org\",\n  \"github.com\", \"stackoverflow.com\", \"arxiv.org\",\n];\n\nconst BLOCKED_DOMAINS = [\n  \"known-malware-site.com\", \"phishing-domain.net\",\n];\n\nasync function safeDomainSearch(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 10,\n    includeDomains: TRUSTED_DOMAINS,  \u002F\u002F only return results from these\n    text: { maxCharacters: 1000 },\n  });\n}\n\nasync function searchWithBlocklist(query: string) {\n  return exa.searchAndContents(query, {\n    numResults: 10,\n    excludeDomains: BLOCKED_DOMAINS,  \u002F\u002F never return results from these\n    text: { maxCharacters: 1000 },\n  });\n}\n```\n\n### Step 4: Query Sanitization\n```typescript\n\u002F\u002F Sanitize user-provided queries before sending to Exa\nfunction sanitizeQuery(input: string): string {\n  \u002F\u002F Remove potential injection patterns\n  let clean = input\n    .replace(\u002F[\u003C>{}]\u002Fg, \"\")           \u002F\u002F strip HTML\u002Ftemplate chars\n    .replace(\u002F\\0\u002Fg, \"\")              \u002F\u002F remove null bytes\n    .trim()\n    .substring(0, 500);              \u002F\u002F cap query length\n\n  if (!clean || clean.length \u003C 2) {\n    throw new Error(\"Query too short or empty after sanitization\");\n  }\n  return clean;\n}\n\n\u002F\u002F Usage\nconst userQuery = sanitizeQuery(req.body.query);\nconst results = await exa.search(userQuery, {\n  numResults: 10,\n  moderation: true,\n});\n```\n\n### Step 5: Per-Environment Key Isolation\n```typescript\n\u002F\u002F Use separate API keys per environment\nconst KEY_MAP: Record\u003Cstring, string> = {\n  development: process.env.EXA_API_KEY_DEV!,\n  staging: process.env.EXA_API_KEY_STAGING!,\n  production: process.env.EXA_API_KEY_PROD!,\n};\n\nfunction getExaForEnv(): Exa {\n  const env = process.env.NODE_ENV || \"development\";\n  const key = KEY_MAP[env];\n  if (!key) throw new Error(`No EXA key for ${env}`);\n  return new Exa(key);\n}\n```\n\n## Security Checklist\n- [ ] API key stored in environment variables (never hardcoded)\n- [ ] `.env` files in `.gitignore`\n- [ ] Separate API keys for dev\u002Fstaging\u002Fproduction\n- [ ] `moderation: true` enabled for user-facing search\n- [ ] Query input sanitized before API calls\n- [ ] Domain allowlist\u002Fblocklist applied for sensitive use cases\n- [ ] API key rotation procedure documented\n- [ ] Git history scanned for accidentally committed keys\n\n## Error Handling\n| Security Issue | Detection | Mitigation |\n|----------------|-----------|------------|\n| Exposed API key | `git log -p` search | Rotate key immediately at dashboard.exa.ai |\n| Unsafe search results | User reports | Enable `moderation: true` |\n| Untrusted domains | Review result URLs | Apply `includeDomains` filter |\n| Query injection | Input validation | Sanitize before search |\n\n## Examples\n\n### Scan Git History for Leaked Keys\n```bash\nset -euo pipefail\n# Check if API key was ever committed\ngit log -p --all -S \"EXA_API_KEY\" -- \"*.ts\" \"*.js\" \"*.py\" \"*.env\" | head -20\n```\n\n### Key Rotation Procedure\n```bash\nset -euo pipefail\n# 1. Generate new key in dashboard.exa.ai\n# 2. Update environment\nexport EXA_API_KEY=\"new-key-here\"\n# 3. Verify new key works\ncurl -s -o \u002Fdev\u002Fnull -w \"%{http_code}\" \\\n  -X POST https:\u002F\u002Fapi.exa.ai\u002Fsearch \\\n  -H \"x-api-key: $EXA_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"query\":\"test\",\"numResults\":1}'\n# 4. Revoke old key in dashboard\n```\n\n## Resources\n- [Exa API Authentication](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Fgetting-started)\n- [Exa Error Codes](https:\u002F\u002Fdocs.exa.ai\u002Freference\u002Ferror-codes)\n\n## Next Steps\nFor production deployment, see `exa-prod-checklist`.\n\n",{"name":5,"tags":54,"author":56,"license":15,"version":57,"description":58,"allowed-tools":59,"compatible-with":60},[55,31,35,29],"saas","Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Secure Exa API keys, implement content moderation, and manage domain restrictions.\nUse when securing API keys, auditing Exa security configuration,\nor implementing content safety filtering.\nTrigger with phrases like \"exa security\", \"exa secrets\",\n\"secure exa\", \"exa API key security\", \"exa content moderation\".\n","Read, Write, Grep","claude-code, codex, openclaw","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fexa-security-basics",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":8,"skillName":5,"commands":71,"prompt":81,"zipAvailable":82},[72,75,78],{"tool":73,"command":74},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill exa-security-basics",{"tool":76,"command":77},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill exa-security-basics",{"tool":79,"command":80},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill exa-security-basics","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fexa-security-basics\u002FSKILL.md",true,[],[85,97,107,116,122,129],{"skillNo":86,"name":87,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":93,"publishedAt":49},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[90],{"categoryNo":91,"categoryName":92,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[94,95,96],"model","model hierarchy","model hierarchy skill",{"skillNo":98,"name":99,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":103,"publishedAt":49},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[102],{"categoryNo":91,"categoryName":92,"taxonomyType":21,"taxonomyTypeDesc":22},[104,105,106],"MCP","zoom","zoom mcp",{"skillNo":108,"name":109,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":110,"categories":111,"keywords":112,"publishedAt":49},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[113,114,115,105],"sdk","zoom apps sdk","apps",{"skillNo":117,"name":118,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":121,"publishedAt":49},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[118],{"skillNo":123,"name":124,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":125,"categories":126,"keywords":128,"publishedAt":49},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[127],{"categoryNo":91,"categoryName":92,"taxonomyType":21,"taxonomyTypeDesc":22},[124],{"skillNo":130,"name":131,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":132,"categories":133,"keywords":134,"publishedAt":49},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[131]]