Figma Policy & Guardrails Overview Automated guardrails for Figma API integrations: prevent token leaks, enforce scope minimization, validate webhook configurations, and catch common anti-patterns in CI. Prerequisites - ESLint or similar linter - CI/CD pipeline (GitHub Actions) - Pre-commit hooks infrastructure Instructions Step 1: Token Leak Prevention Step 2: ESLint Rules for Figma Step 3: API Usage Policies Step 4: Configuration Validation Step 5: Audit Logging Output - Pre-commit hooks catching token leaks - CI pipeline scanning for hardcoded credentials - Runtime policies enforcing perfo…

; then\n echo \"::error::.env file committed to repository\"\n exit 1\n fi\n```\n\n### Step 2: ESLint Rules for Figma\n\n```javascript\n// eslint-rules/no-figma-token-literal.js\nmodule.exports = {\n meta: {\n type: 'problem',\n docs: { description: 'Disallow hardcoded Figma PATs' },\n },\n create(context) {\n return {\n Literal(node) {\n if (typeof node.value === 'string' && /^figd_[a-zA-Z0-9_-]{20,}/.test(node.value)) {\n context.report({\n node,\n message: 'Hardcoded Figma PAT detected. Use process.env.FIGMA_PAT instead.',\n });\n }\n },\n TemplateLiteral(node) {\n for (const quasi of node.quasis) {\n if (/figd_[a-zA-Z0-9_-]{20,}/.test(quasi.value.raw)) {\n context.report({\n node,\n message: 'Hardcoded Figma PAT in template literal.',\n });\n }\n }\n },\n };\n },\n};\n```\n\n### Step 3: API Usage Policies\n\n```typescript\n// Runtime guardrails for Figma API usage\n\n// Policy 1: No full-file fetches without justification\nfunction validateFigmaRequest(path: string) {\n // Block unoptimized full file fetches\n if (path.match(/\\/v1\\/files\\/[^/]+$/) && !path.includes('depth=')) {\n console.warn(\n '[figma-policy] Full file fetch without depth parameter. ' +\n 'Use ?depth=1 or /nodes endpoint for better performance.'\n );\n }\n\n // Block deprecated scope indicator\n if (path.includes('files:read')) {\n throw new Error(\n '[figma-policy] files:read scope is deprecated. ' +\n 'Use file_content:read instead.'\n );\n }\n}\n\n// Policy 2: Enforce timeout on all Figma calls\nfunction validateTimeout(options: RequestInit) {\n if (!options.signal) {\n console.warn(\n '[figma-policy] Figma request without AbortSignal. ' +\n 'Use AbortSignal.timeout() to prevent hung requests.'\n );\n }\n}\n\n// Policy 3: Rate limit safety margin\nconst MAX_REQUESTS_PER_MINUTE = 25; // Conservative limit\nlet requestsThisMinute = 0;\nlet minuteStart = Date.now();\n\nfunction enforceRatePolicy() {\n if (Date.now() - minuteStart > 60_000) {\n requestsThisMinute = 0;\n minuteStart = Date.now();\n }\n\n requestsThisMinute++;\n if (requestsThisMinute > MAX_REQUESTS_PER_MINUTE) {\n throw new Error(\n `[figma-policy] Rate limit safety: ${requestsThisMinute} requests/min ` +\n `exceeds policy limit of ${MAX_REQUESTS_PER_MINUTE}`\n );\n }\n}\n```\n\n### Step 4: Configuration Validation\n\n```typescript\n// Validate Figma config at startup, fail fast if misconfigured\nfunction validateFigmaConfig() {\n const errors: string[] = [];\n\n // Token format\n const pat = process.env.FIGMA_PAT;\n if (!pat) {\n errors.push('FIGMA_PAT is not set');\n } else if (!pat.startsWith('figd_')) {\n errors.push('FIGMA_PAT does not have expected figd_ prefix');\n }\n\n // File key format\n const fileKey = process.env.FIGMA_FILE_KEY;\n if (!fileKey) {\n errors.push('FIGMA_FILE_KEY is not set');\n } else if (fileKey.length \u003c 10) {\n errors.push('FIGMA_FILE_KEY seems too short');\n }\n\n // Webhook passcode (if webhooks are configured)\n if (process.env.FIGMA_WEBHOOK_ENABLED === 'true') {\n if (!process.env.FIGMA_WEBHOOK_PASSCODE) {\n errors.push('FIGMA_WEBHOOK_PASSCODE required when webhooks are enabled');\n } else if (process.env.FIGMA_WEBHOOK_PASSCODE.length \u003c 16) {\n errors.push('FIGMA_WEBHOOK_PASSCODE should be at least 16 characters');\n }\n }\n\n if (errors.length > 0) {\n console.error('[figma-policy] Configuration errors:');\n errors.forEach(e => console.error(` - ${e}`));\n throw new Error(`Figma configuration invalid: ${errors.length} errors`);\n }\n\n console.log('[figma-policy] Configuration validated');\n}\n\n// Call at startup\nvalidateFigmaConfig();\n```\n\n### Step 5: Audit Logging\n\n```typescript\n// Log all Figma API operations for compliance\ninterface FigmaAuditEntry {\n timestamp: string;\n action: string;\n endpoint: string;\n fileKey?: string;\n status: number;\n userId?: string;\n}\n\nfunction auditFigmaCall(entry: Omit\u003cFigmaAuditEntry, 'timestamp'>) {\n const log: FigmaAuditEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n };\n\n // Structured log for aggregation\n console.log(JSON.stringify({ type: 'figma_audit', ...log }));\n}\n```\n\n## Output\n\n- Pre-commit hooks catching token leaks\n- CI pipeline scanning for hardcoded credentials\n- Runtime policies enforcing performance best practices\n- Configuration validation at startup\n- Audit logging for compliance\n\n## Error Handling\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| False positive on token scan | Test fixture contains figd_ | Exclude test fixtures directory |\n| Policy blocks legitimate request | Too restrictive | Add exception list for specific paths |\n| Startup validation fails | Missing env vars | Check deployment config |\n| Audit log noise | Too many entries | Filter to write operations only |\n\n## Resources\n\n- [Figma API Scopes](https://developers.figma.com/docs/rest-api/scopes/)\n- [Pre-commit Framework](https://pre-commit.com/)\n- [ESLint Custom Rules](https://eslint.org/docs/latest/extend/custom-rules)\n\n## Next Steps\n\nFor architecture blueprints, see `figma-architecture-variants`.\n---","attachment_filenames":[],"attachments":[],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Figma Policy & Guardrails","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"Automated guardrails for Figma API integrations: prevent token leaks, enforce scope minimization, validate webhook configurations, and catch common anti-patterns in CI.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Prerequisites","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ESLint or similar linter","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CI/CD pipeline (GitHub Actions)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pre-commit hooks infrastructure","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Instructions","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1: Token Leak Prevention","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# .pre-commit-config.yaml -- catch Figma tokens before commit\nrepos:\n - repo: local\n hooks:\n - id: no-figma-tokens\n name: Check for Figma PAT leaks\n entry: bash -c '\n if git diff --cached --diff-filter=ACM -z -- . |\n xargs -0 grep -lP \"figd_[a-zA-Z0-9_-]{20,}\" 2>/dev/null; then\n echo \"ERROR: Figma PAT found in staged files\"\n echo \"Store tokens in .env files (which should be in .gitignore)\"\n exit 1\n fi\n '\n language: system\n pass_filenames: false","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"# GitHub Actions secret scanning\n# .github/workflows/figma-security.yml\nname: Figma Security Check\non: [push, pull_request]\n\njobs:\n security:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n\n - name: Scan for Figma tokens\n run: |\n if grep -rP \"figd_[a-zA-Z0-9_-]{20,}\" \\\n --include=\"*.ts\" --include=\"*.js\" --include=\"*.json\" \\\n --exclude-dir=node_modules .; then\n echo \"::error::Figma PAT found in source code\"\n exit 1\n fi\n\n - name: Check .env files not committed\n run: |\n if git ls-files --cached | grep -E '^\\.(env|env\\.local|env\\.production)

Figma Policy & Guardrails Overview Automated guardrails for Figma API integrations: prevent token leaks, enforce scope minimization, validate webhook configurations, and catch common anti-patterns in CI. Prerequisites - ESLint or similar linter - CI/CD pipeline (GitHub Actions) - Pre-commit hooks infrastructure Instructions Step 1: Token Leak Prevention Step 2: ESLint Rules for Figma Step 3: API Usage Policies Step 4: Configuration Validation Step 5: Audit Logging Output - Pre-commit hooks catching token leaks - CI pipeline scanning for hardcoded credentials - Runtime policies enforcing perfo…

; then\n echo \"::error::.env file committed to repository\"\n exit 1\n fi","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2: ESLint Rules for Figma","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// eslint-rules/no-figma-token-literal.js\nmodule.exports = {\n meta: {\n type: 'problem',\n docs: { description: 'Disallow hardcoded Figma PATs' },\n },\n create(context) {\n return {\n Literal(node) {\n if (typeof node.value === 'string' && /^figd_[a-zA-Z0-9_-]{20,}/.test(node.value)) {\n context.report({\n node,\n message: 'Hardcoded Figma PAT detected. Use process.env.FIGMA_PAT instead.',\n });\n }\n },\n TemplateLiteral(node) {\n for (const quasi of node.quasis) {\n if (/figd_[a-zA-Z0-9_-]{20,}/.test(quasi.value.raw)) {\n context.report({\n node,\n message: 'Hardcoded Figma PAT in template literal.',\n });\n }\n }\n },\n };\n },\n};","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3: API Usage Policies","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"// Runtime guardrails for Figma API usage\n\n// Policy 1: No full-file fetches without justification\nfunction validateFigmaRequest(path: string) {\n // Block unoptimized full file fetches\n if (path.match(/\\/v1\\/files\\/[^/]+$/) && !path.includes('depth=')) {\n console.warn(\n '[figma-policy] Full file fetch without depth parameter. ' +\n 'Use ?depth=1 or /nodes endpoint for better performance.'\n );\n }\n\n // Block deprecated scope indicator\n if (path.includes('files:read')) {\n throw new Error(\n '[figma-policy] files:read scope is deprecated. ' +\n 'Use file_content:read instead.'\n );\n }\n}\n\n// Policy 2: Enforce timeout on all Figma calls\nfunction validateTimeout(options: RequestInit) {\n if (!options.signal) {\n console.warn(\n '[figma-policy] Figma request without AbortSignal. ' +\n 'Use AbortSignal.timeout() to prevent hung requests.'\n );\n }\n}\n\n// Policy 3: Rate limit safety margin\nconst MAX_REQUESTS_PER_MINUTE = 25; // Conservative limit\nlet requestsThisMinute = 0;\nlet minuteStart = Date.now();\n\nfunction enforceRatePolicy() {\n if (Date.now() - minuteStart > 60_000) {\n requestsThisMinute = 0;\n minuteStart = Date.now();\n }\n\n requestsThisMinute++;\n if (requestsThisMinute > MAX_REQUESTS_PER_MINUTE) {\n throw new Error(\n `[figma-policy] Rate limit safety: ${requestsThisMinute} requests/min ` +\n `exceeds policy limit of ${MAX_REQUESTS_PER_MINUTE}`\n );\n }\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4: Configuration Validation","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"// Validate Figma config at startup, fail fast if misconfigured\nfunction validateFigmaConfig() {\n const errors: string[] = [];\n\n // Token format\n const pat = process.env.FIGMA_PAT;\n if (!pat) {\n errors.push('FIGMA_PAT is not set');\n } else if (!pat.startsWith('figd_')) {\n errors.push('FIGMA_PAT does not have expected figd_ prefix');\n }\n\n // File key format\n const fileKey = process.env.FIGMA_FILE_KEY;\n if (!fileKey) {\n errors.push('FIGMA_FILE_KEY is not set');\n } else if (fileKey.length \u003c 10) {\n errors.push('FIGMA_FILE_KEY seems too short');\n }\n\n // Webhook passcode (if webhooks are configured)\n if (process.env.FIGMA_WEBHOOK_ENABLED === 'true') {\n if (!process.env.FIGMA_WEBHOOK_PASSCODE) {\n errors.push('FIGMA_WEBHOOK_PASSCODE required when webhooks are enabled');\n } else if (process.env.FIGMA_WEBHOOK_PASSCODE.length \u003c 16) {\n errors.push('FIGMA_WEBHOOK_PASSCODE should be at least 16 characters');\n }\n }\n\n if (errors.length > 0) {\n console.error('[figma-policy] Configuration errors:');\n errors.forEach(e => console.error(` - ${e}`));\n throw new Error(`Figma configuration invalid: ${errors.length} errors`);\n }\n\n console.log('[figma-policy] Configuration validated');\n}\n\n// Call at startup\nvalidateFigmaConfig();","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 5: Audit Logging","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"// Log all Figma API operations for compliance\ninterface FigmaAuditEntry {\n timestamp: string;\n action: string;\n endpoint: string;\n fileKey?: string;\n status: number;\n userId?: string;\n}\n\nfunction auditFigmaCall(entry: Omit\u003cFigmaAuditEntry, 'timestamp'>) {\n const log: FigmaAuditEntry = {\n ...entry,\n timestamp: new Date().toISOString(),\n };\n\n // Structured log for aggregation\n console.log(JSON.stringify({ type: 'figma_audit', ...log }));\n}","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Output","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pre-commit hooks catching token leaks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"CI pipeline scanning for hardcoded credentials","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Runtime policies enforcing performance best practices","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Configuration validation at startup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Audit logging for compliance","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Error Handling","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Issue","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cause","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Solution","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"False positive on token scan","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Test fixture contains figd_","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Exclude test fixtures directory","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Policy blocks legitimate request","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Too restrictive","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add exception list for specific paths","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Startup validation fails","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Missing env vars","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check deployment config","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Audit log noise","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Too many entries","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Filter to write operations only","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Resources","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Figma API Scopes","type":"text","marks":[{"type":"link","attrs":{"href":"https://developers.figma.com/docs/rest-api/scopes/","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pre-commit Framework","type":"text","marks":[{"type":"link","attrs":{"href":"https://pre-commit.com/","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ESLint Custom Rules","type":"text","marks":[{"type":"link","attrs":{"href":"https://eslint.org/docs/latest/extend/custom-rules","title":null}}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Next Steps","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"For architecture blueprints, see ","type":"text"},{"text":"figma-architecture-variants","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"figma-policy-guardrails","tags":["saas","figma"],"author":"@skillopedia","source":{"stars":2275,"repo_name":"claude-code-plugins-plus-skills","origin_url":"https://github.com/jeremylongshore/claude-code-plugins-plus-skills/blob/HEAD/plugins/saas-packs/figma-pack/skills/figma-policy-guardrails/SKILL.md","repo_owner":"jeremylongshore","body_sha256":"da5d1aa8268f668550de0f5866b06eecad18dd6ea8781aeb803180341266295b","cluster_key":"901bacf74791fdacecc94f814e935491af8d1bbc37de795ca013a49669974467","clean_bundle":{"format":"clean-skill-bundle-v1","source":"jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/figma-pack/skills/figma-policy-guardrails/SKILL.md","bundle_sha256":"765cf1205d5c39600435f648cfa7904c207cf0edd31724208be397959c902edf","attachment_count":0,"text_attachments":0,"binary_attachments":0},"cluster_size":1,"skill_md_path":"plugins/saas-packs/figma-pack/skills/figma-policy-guardrails/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"security","category_label":"Security"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"security","import_tag":"clean-skills-v1","description":"Enforce security policies and coding standards for Figma API integrations.\nUse when setting up linting rules for Figma tokens, preventing accidental\ncredential leaks, or enforcing API usage best practices.\nTrigger with phrases like \"figma policy\", \"figma lint\",\n\"figma guardrails\", \"figma security rules\", \"figma best practices check\".\n","allowed-tools":"Read, Write, Edit, Bash(npx:*)","compatibility":"Designed for Claude Code"}},"renderedAt":1782981918922}

Figma Policy & Guardrails Overview Automated guardrails for Figma API integrations: prevent token leaks, enforce scope minimization, validate webhook configurations, and catch common anti-patterns in CI. Prerequisites - ESLint or similar linter - CI/CD pipeline (GitHub Actions) - Pre-commit hooks infrastructure Instructions Step 1: Token Leak Prevention Step 2: ESLint Rules for Figma Step 3: API Usage Policies Step 4: Configuration Validation Step 5: Audit Logging Output - Pre-commit hooks catching token leaks - CI pipeline scanning for hardcoded credentials - Runtime policies enforcing perfo…