Skip to content
Back to skills

Figma Policy Guardrails

ASecurity

'Enforce security policies and coding standards for Figma API integrations.

  • 2,719 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 21, 2026
ai-agentsjavascripttypescriptjavabashnoderailsgitapici/cdsecurity

Works with

  • claude code
  • api

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus --skill figma-policy-guardrails --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Figma Policy Guardrails?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Figma Policy Guardrails
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-figma-policy-guardrails-2592d970/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-figma-policy-guardrails-2592d970)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: figma-policy-guardrails
description: 'Enforce security policies and coding standards for Figma API integrations.

  Use when setting up linting rules for Figma tokens, preventing accidental

  credential leaks, or enforcing API usage best practices.

  Trigger with phrases like "figma policy", "figma lint",

  "figma guardrails", "figma security rules", "figma best practices check".

  '
allowed-tools: Read, Write, Edit, Bash(npx:*)
version: 1.6.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- figma
compatibility: Designed for Claude Code
---
# 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

```bash
# .pre-commit-config.yaml -- catch Figma tokens before commit
repos:
  - repo: local
    hooks:
      - id: no-figma-tokens
        name: Check for Figma PAT leaks
        entry: bash -c '
          if git diff --cached --diff-filter=ACM -z -- . |
             xargs -0 grep -lP "figd_[a-zA-Z0-9_-]{20,}" 2>/dev/null; then
            echo "ERROR: Figma PAT found in staged files"
            echo "Store tokens in .env files (which should be in .gitignore)"
            exit 1
          fi
        '
        language: system
        pass_filenames: false
```

```yaml
# GitHub Actions secret scanning
# .github/workflows/figma-security.yml
name: Figma Security Check
on: [push, pull_request]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Scan for Figma tokens
        run: |
          if grep -rP "figd_[a-zA-Z0-9_-]{20,}" \
            --include="*.ts" --include="*.js" --include="*.json" \
            --exclude-dir=node_modules .; then
            echo "::error::Figma PAT found in source code"
            exit 1
          fi

      - name: Check .env files not committed
        run: |
          if git ls-files --cached | grep -E '^\.(env|env\.local|env\.production)$'; then
            echo "::error::.env file committed to repository"
            exit 1
          fi
```

### Step 2: ESLint Rules for Figma

```javascript
// eslint-rules/no-figma-token-literal.js
module.exports = {
  meta: {
    type: 'problem',
    docs: { description: 'Disallow hardcoded Figma PATs' },
  },
  create(context) {
    return {
      Literal(node) {
        if (typeof node.value === 'string' && /^figd_[a-zA-Z0-9_-]{20,}/.test(node.value)) {
          context.report({
            node,
            message: 'Hardcoded Figma PAT detected. Use process.env.FIGMA_PAT instead.',
          });
        }
      },
      TemplateLiteral(node) {
        for (const quasi of node.quasis) {
          if (/figd_[a-zA-Z0-9_-]{20,}/.test(quasi.value.raw)) {
            context.report({
              node,
              message: 'Hardcoded Figma PAT in template literal.',
            });
          }
        }
      },
    };
  },
};
```

### Step 3: API Usage Policies

```typescript
// Runtime guardrails for Figma API usage

// Policy 1: No full-file fetches without justification
function validateFigmaRequest(path: string) {
  // Block unoptimized full file fetches
  if (path.match(/\/v1\/files\/[^/]+$/) && !path.includes('depth=')) {
    console.warn(
      '[figma-policy] Full file fetch without depth parameter. ' +
      'Use ?depth=1 or /nodes endpoint for better performance.'
    );
  }

  // Block deprecated scope indicator
  if (path.includes('files:read')) {
    throw new Error(
      '[figma-policy] files:read scope is deprecated. ' +
      'Use file_content:read instead.'
    );
  }
}

// Policy 2: Enforce timeout on all Figma calls
function validateTimeout(options: RequestInit) {
  if (!options.signal) {
    console.warn(
      '[figma-policy] Figma request without AbortSignal. ' +
      'Use AbortSignal.timeout() to prevent hung requests.'
    );
  }
}

// Policy 3: Rate limit safety margin
const MAX_REQUESTS_PER_MINUTE = 25; // Conservative limit
let requestsThisMinute = 0;
let minuteStart = Date.now();

function enforceRatePolicy() {
  if (Date.now() - minuteStart > 60_000) {
    requestsThisMinute = 0;
    minuteStart = Date.now();
  }

  requestsThisMinute++;
  if (requestsThisMinute > MAX_REQUESTS_PER_MINUTE) {
    throw new Error(
      `[figma-policy] Rate limit safety: ${requestsThisMinute} requests/min ` +
      `exceeds policy limit of ${MAX_REQUESTS_PER_MINUTE}`
    );
  }
}
```

### Step 4: Configuration Validation

```typescript
// Validate Figma config at startup, fail fast if misconfigured
function validateFigmaConfig() {
  const errors: string[] = [];

  // Token format
  const pat = process.env.FIGMA_PAT;
  if (!pat) {
    errors.push('FIGMA_PAT is not set');
  } else if (!pat.startsWith('figd_')) {
    errors.push('FIGMA_PAT does not have expected figd_ prefix');
  }

  // File key format
  const fileKey = process.env.FIGMA_FILE_KEY;
  if (!fileKey) {
    errors.push('FIGMA_FILE_KEY is not set');
  } else if (fileKey.length < 10) {
    errors.push('FIGMA_FILE_KEY seems too short');
  }

  // Webhook passcode (if webhooks are configured)
  if (process.env.FIGMA_WEBHOOK_ENABLED === 'true') {
    if (!process.env.FIGMA_WEBHOOK_PASSCODE) {
      errors.push('FIGMA_WEBHOOK_PASSCODE required when webhooks are enabled');
    } else if (process.env.FIGMA_WEBHOOK_PASSCODE.length < 16) {
      errors.push('FIGMA_WEBHOOK_PASSCODE should be at least 16 characters');
    }
  }

  if (errors.length > 0) {
    console.error('[figma-policy] Configuration errors:');
    errors.forEach(e => console.error(`  - ${e}`));
    throw new Error(`Figma configuration invalid: ${errors.length} errors`);
  }

  console.log('[figma-policy] Configuration validated');
}

// Call at startup
validateFigmaConfig();
```

### Step 5: Audit Logging

```typescript
// Log all Figma API operations for compliance
interface FigmaAuditEntry {
  timestamp: string;
  action: string;
  endpoint: string;
  fileKey?: string;
  status: number;
  userId?: string;
}

function auditFigmaCall(entry: Omit<FigmaAuditEntry, 'timestamp'>) {
  const log: FigmaAuditEntry = {
    ...entry,
    timestamp: new Date().toISOString(),
  };

  // Structured log for aggregation
  console.log(JSON.stringify({ type: 'figma_audit', ...log }));
}
```

## Output

- Pre-commit hooks catching token leaks
- CI pipeline scanning for hardcoded credentials
- Runtime policies enforcing performance best practices
- Configuration validation at startup
- Audit logging for compliance

## Error Handling

| Issue | Cause | Solution |
|-------|-------|----------|
| False positive on token scan | Test fixture contains figd_ | Exclude test fixtures directory |
| Policy blocks legitimate request | Too restrictive | Add exception list for specific paths |
| Startup validation fails | Missing env vars | Check deployment config |
| Audit log noise | Too many entries | Filter to write operations only |

## Examples

Catch a hardcoded Figma PAT before it reaches a commit (Step 1 pre-commit hook):

```bash
echo 'const PAT = "figd_AbCdEf123456789";' > leak.ts
git add leak.ts && git commit -m "test"
# pre-commit: BLOCKED — figd_ token detected in leak.ts
```

Lint a violation of the API usage policy (Step 2 ESLint rule flags full-file fetches):

```text
src/sync.ts
  14:3  error  Figma file fetch without depth parameter — use ?depth=1
                or /nodes?ids=... (figma/no-unbounded-file-fetch)
```

Policy rule catalog and the audit-log event shape: `references/api-usage-policies.md` and `references/audit-logging.md`.

## Resources

- [Figma API Scopes](https://developers.figma.com/docs/rest-api/scopes/)
- [Pre-commit Framework](https://pre-commit.com/)
- [ESLint Custom Rules](https://eslint.org/docs/latest/extend/custom-rules)

## Next Steps

For architecture blueprints, see `figma-architecture-variants`.

Files in this skill

  • SKILL.md7.9 KB
  • references/api-usage-policies.md1.7 KB
  • references/audit-logging.md785 B
  • references/configuration-validation.md1.6 KB
  • references/errors.md706 B
  • references/eslint-rules-for-figma.md1.1 KB
  • references/token-leak-prevention.md1.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.