[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6AEYQZFFB6Y921Q8CCF6P12":3,"skill-same:01M6AEYQZFFB6Y921Q8CCF6P12":120},{"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":31,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":79,"commitSha":80,"skillDirectory":81,"forksCount":82,"repositoryHtmlUrl":83,"repositoryHomepageUrl":84,"ownerHtmlUrl":85,"ownerBlogUrl":86,"ownerDescription":87,"updatedAt":88,"install":89,"resources":102},"01M6AEYQZFFB6Y921Q8CCF6P12","implementing-api-key-security-controls",null,"Implements secure API key generation with sufficient entropy, server-side hashing (SHA-256\u002Fbcrypt) instead of plaintext storage, per-key scoping to endpoints\u002FIPs\u002Frate limits, zero-downtime rotation, and automated leak monitoring across GitHub repos, logs, and client-side code. Use when designing API key formats, building key rotation or revocation workflows, or protecting server-to-server API credentials from leakage, brute force, and abuse.","mukul975\u002FAnthropic-Cybersecurity-Skills","mukul975","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F42860185?v=4","01M6ADEQR8T5M4EEG6C67BQCWF","Mahipal","01M6ADJPMYWG1E5GM1FWBE3128",36078,"Apache-2.0","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fimplementing-api-key-security-controls\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"security","implementing api key security controls","ZeRO","github","secret-management","key-rotation","credential-management","api-keys","t1059","entropy","ips","cybersecurity","api-security","server","monitoring","logs","code","pr","workflows","storage","2026-11-10 10:12:30",false,"---\nname: implementing-api-key-security-controls\ndescription: 'Implements secure API key generation with sufficient entropy, server-side\n  hashing (SHA-256\u002Fbcrypt) instead of plaintext storage, per-key scoping to endpoints\u002FIPs\u002Frate\n  limits, zero-downtime rotation, and automated leak monitoring across GitHub repos,\n  logs, and client-side code. Use when designing API key formats, building key rotation\n  or revocation workflows, or protecting server-to-server API credentials from leakage,\n  brute force, and abuse.'\ndomain: cybersecurity\nsubdomain: api-security\ntags:\n- api-security\n- api-keys\n- credential-management\n- key-rotation\n- secret-management\nversion: 1.0.0\nauthor: mahipal\nlicense: Apache-2.0\nnist_ai_rmf:\n- MEASURE-2.7\n- MAP-5.1\n- MANAGE-2.4\natlas_techniques:\n- AML.T0070\n- AML.T0066\n- AML.T0082\nnist_csf:\n- PR.PS-01\n- ID.RA-01\n- PR.DS-10\n- DE.CM-01\nmitre_attack:\n- T1190\n- T1059.007\n- T1552.001\n- T1003\n- T1110\n---\n# Implementing API Key Security Controls\n\n## When to Use\n\n- Designing secure API key generation with sufficient entropy and identifiable prefixes for leak detection\n- Implementing server-side API key hashing (never storing keys in plaintext) with SHA-256 or bcrypt\n- Building key rotation workflows that allow zero-downtime key replacement for API consumers\n- Configuring per-key scoping to limit each API key to specific endpoints, IP ranges, and rate limits\n- Setting up automated monitoring for API key leakage in GitHub repos, logs, and client-side code\n\n**Do not use** API keys as the sole authentication mechanism for user-facing applications. API keys are best suited for server-to-server communication and developer access.\n\n## Prerequisites\n\n- Secure random number generator (os.urandom, secrets module) for key generation\n- Database with proper encryption at rest for storing hashed API keys\n- Redis or similar store for key-to-metadata caching and rate limiting\n- Secret scanning tools (GitHub secret scanning, truffleHog, gitleaks)\n- Monitoring and alerting infrastructure for key usage anomalies\n\n## Workflow\n\n### Step 1: Secure API Key Generation\n\n```python\nimport secrets\nimport hashlib\nimport hmac\nimport time\nimport json\nfrom datetime import datetime, timedelta\n\nclass APIKeyManager:\n    \"\"\"Manages secure API key lifecycle: generation, storage, validation, rotation.\"\"\"\n\n    # Key format: prefix_base64random (e.g., sk_live_a1b2c3d4e5f6...)\n    # Prefix identifies the key type and environment for leak detection\n    KEY_PREFIXES = {\n        \"live_secret\": \"sk_live_\",\n        \"test_secret\": \"sk_test_\",\n        \"live_public\": \"pk_live_\",\n        \"test_public\": \"pk_test_\",\n    }\n\n    def __init__(self, db_connection, redis_connection):\n        self.db = db_connection\n        self.redis = redis_connection\n\n    def generate_key(self, key_type=\"live_secret\", owner_id=None, scopes=None,\n                     rate_limit=None, ip_allowlist=None, expires_days=365):\n        \"\"\"Generate a new API key with metadata.\"\"\"\n        prefix = self.KEY_PREFIXES.get(key_type, \"sk_live_\")\n\n        # Generate 32 bytes (256 bits) of randomness\n        random_bytes = secrets.token_bytes(32)\n        key_body = secrets.token_urlsafe(32)  # Base64url-encoded\n\n        # Full API key that the client receives (shown only once)\n        full_key = f\"{prefix}{key_body}\"\n\n        # Hash the key for storage (never store the raw key)\n        key_hash = hashlib.sha256(full_key.encode()).hexdigest()\n\n        # Create a short key ID for reference (first 8 chars)\n        key_id = f\"{prefix}{key_body[:8]}...\"\n\n        # Store the hashed key with metadata\n        key_metadata = {\n            \"key_hash\": key_hash,\n            \"key_id\": key_id,\n            \"key_type\": key_type,\n            \"owner_id\": owner_id,\n            \"scopes\": scopes or [\"read\"],\n            \"rate_limit\": rate_limit or {\"requests\": 1000, \"window\": 3600},\n            \"ip_allowlist\": ip_allowlist or [],\n            \"created_at\": datetime.utcnow().isoformat(),\n            \"expires_at\": (datetime.utcnow() + timedelta(days=expires_days)).isoformat(),\n            \"last_used\": None,\n            \"is_active\": True,\n            \"usage_count\": 0,\n        }\n\n        # Store in database\n        self.db.execute(\n            \"INSERT INTO api_keys (key_hash, key_id, metadata) VALUES (?, ?, ?)\",\n            (key_hash, key_id, json.dumps(key_metadata))\n        )\n\n        # Cache in Redis for fast validation\n        self.redis.setex(\n            f\"apikey:{key_hash}\",\n            86400,  # 24-hour cache TTL\n            json.dumps(key_metadata)\n        )\n\n        return {\n            \"api_key\": full_key,       # Show to user ONCE\n            \"key_id\": key_id,          # For reference\u002Fmanagement\n            \"scopes\": key_metadata[\"scopes\"],\n            \"expires_at\": key_metadata[\"expires_at\"],\n        }\n\n    def validate_key(self, api_key):\n        \"\"\"Validate an API key and return its metadata.\"\"\"\n        key_hash = hashlib.sha256(api_key.encode()).hexdigest()\n\n        # Check Redis cache first\n        cached = self.redis.get(f\"apikey:{key_hash}\")\n        if cached:\n            metadata = json.loads(cached)\n        else:\n            # Fall back to database\n            row = self.db.execute(\n                \"SELECT metadata FROM api_keys WHERE key_hash = ?\",\n                (key_hash,)\n            ).fetchone()\n            if not row:\n                return None, \"invalid_key\"\n            metadata = json.loads(row[0])\n            # Refresh cache\n            self.redis.setex(f\"apikey:{key_hash}\", 86400, row[0])\n\n        # Validation checks\n        if not metadata.get(\"is_active\"):\n            return None, \"key_revoked\"\n\n        if metadata.get(\"expires_at\"):\n            if datetime.fromisoformat(metadata[\"expires_at\"]) \u003C datetime.utcnow():\n                return None, \"key_expired\"\n\n        # Update last used\n        metadata[\"last_used\"] = datetime.utcnow().isoformat()\n        metadata[\"usage_count\"] = metadata.get(\"usage_count\", 0) + 1\n        self.redis.setex(f\"apikey:{key_hash}\", 86400, json.dumps(metadata))\n\n        return metadata, \"valid\"\n\n    def revoke_key(self, key_id):\n        \"\"\"Immediately revoke an API key.\"\"\"\n        row = self.db.execute(\n            \"SELECT key_hash, metadata FROM api_keys WHERE key_id = ?\",\n            (key_id,)\n        ).fetchone()\n        if row:\n            key_hash = row[0]\n            metadata = json.loads(row[1])\n            metadata[\"is_active\"] = False\n            metadata[\"revoked_at\"] = datetime.utcnow().isoformat()\n\n            self.db.execute(\n                \"UPDATE api_keys SET metadata = ? WHERE key_id = ?\",\n                (json.dumps(metadata), key_id)\n            )\n            # Invalidate cache immediately\n            self.redis.delete(f\"apikey:{key_hash}\")\n            return True\n        return False\n\n    def rotate_key(self, old_key_id, grace_period_hours=24):\n        \"\"\"Rotate an API key with a grace period where both old and new keys work.\"\"\"\n        old_row = self.db.execute(\n            \"SELECT key_hash, metadata FROM api_keys WHERE key_id = ?\",\n            (old_key_id,)\n        ).fetchone()\n        if not old_row:\n            return None, \"key_not_found\"\n\n        old_metadata = json.loads(old_row[1])\n\n        # Generate new key with same settings\n        new_key_data = self.generate_key(\n            key_type=old_metadata[\"key_type\"],\n            owner_id=old_metadata[\"owner_id\"],\n            scopes=old_metadata[\"scopes\"],\n            rate_limit=old_metadata[\"rate_limit\"],\n            ip_allowlist=old_metadata[\"ip_allowlist\"],\n        )\n\n        # Schedule old key revocation after grace period\n        revoke_at = datetime.utcnow() + timedelta(hours=grace_period_hours)\n        old_metadata[\"scheduled_revocation\"] = revoke_at.isoformat()\n        self.db.execute(\n            \"UPDATE api_keys SET metadata = ? WHERE key_id = ?\",\n            (json.dumps(old_metadata), old_key_id)\n        )\n\n        return {\n            \"new_key\": new_key_data,\n            \"old_key_id\": old_key_id,\n            \"old_key_revokes_at\": revoke_at.isoformat(),\n            \"message\": f\"Old key will be revoked in {grace_period_hours} hours\"\n        }, \"success\"\n```\n\n### Step 2: API Key Validation Middleware\n\n```python\nfrom flask import Flask, request, jsonify, g\nfrom functools import wraps\n\napp = Flask(__name__)\n\ndef require_api_key(required_scopes=None):\n    \"\"\"Middleware to validate API key and check scopes.\"\"\"\n    def decorator(f):\n        @wraps(f)\n        def wrapped(*args, **kwargs):\n            # Extract API key from header\n            api_key = request.headers.get(\"X-API-Key\")\n            if not api_key:\n                # Also check Authorization: Bearer \u003Ckey>\n                auth_header = request.headers.get(\"Authorization\", \"\")\n                if auth_header.startswith(\"Bearer \"):\n                    api_key = auth_header[7:]\n\n            if not api_key:\n                return jsonify({\"error\": \"missing_api_key\"}), 401\n\n            # Validate the key\n            metadata, status = key_manager.validate_key(api_key)\n            if status != \"valid\":\n                return jsonify({\"error\": status}), 401\n\n            # Check IP allowlist\n            if metadata.get(\"ip_allowlist\"):\n                client_ip = request.remote_addr\n                if client_ip not in metadata[\"ip_allowlist\"]:\n                    return jsonify({\"error\": \"ip_not_allowed\"}), 403\n\n            # Check scopes\n            if required_scopes:\n                key_scopes = set(metadata.get(\"scopes\", []))\n                if not key_scopes.intersection(required_scopes):\n                    return jsonify({\"error\": \"insufficient_scope\"}), 403\n\n            # Attach metadata to request context\n            g.api_key_metadata = metadata\n            return f(*args, **kwargs)\n        return wrapped\n    return decorator\n\n@app.route('\u002Fapi\u002Fv1\u002Fdata', methods=['GET'])\n@require_api_key(required_scopes=[\"read\", \"admin\"])\ndef get_data():\n    return jsonify({\"data\": \"sensitive information\"})\n\n@app.route('\u002Fapi\u002Fv1\u002Fdata', methods=['POST'])\n@require_api_key(required_scopes=[\"write\", \"admin\"])\ndef create_data():\n    return jsonify({\"created\": True})\n```\n\n### Step 3: Automated Key Leakage Detection\n\n```bash\n# Scan GitHub repositories for leaked API keys using gitleaks\ngitleaks detect --source=\u002Fpath\u002Fto\u002Frepo --config=gitleaks.toml --report-path=leaks.json\n\n# Custom gitleaks configuration for API key prefix detection\n# gitleaks.toml\ncat \u003C\u003C'EOF'\n[[rules]]\nid = \"company-api-key-live\"\ndescription = \"Company Live API Key\"\nregex = '''sk_live_[A-Za-z0-9_-]{32,}'''\ntags = [\"api-key\", \"live\", \"critical\"]\n\n[[rules]]\nid = \"company-api-key-test\"\ndescription = \"Company Test API Key\"\nregex = '''sk_test_[A-Za-z0-9_-]{32,}'''\ntags = [\"api-key\", \"test\"]\n\n[[rules]]\nid = \"company-public-key\"\ndescription = \"Company Public API Key\"\nregex = '''pk_live_[A-Za-z0-9_-]{32,}'''\ntags = [\"api-key\", \"public\"]\nEOF\n```\n\n```python\n# Automated leaked key revocation\nimport json\n\ndef process_leaked_keys(leaks_file):\n    \"\"\"Automatically revoke API keys detected in public repositories.\"\"\"\n    with open(leaks_file) as f:\n        leaks = json.load(f)\n\n    for leak in leaks:\n        key_match = leak.get(\"match\", \"\")\n        # Extract the key from the match\n        for prefix in [\"sk_live_\", \"sk_test_\", \"pk_live_\"]:\n            if prefix in key_match:\n                start = key_match.index(prefix)\n                potential_key = key_match[start:start+50]  # Max key length\n                # Validate and revoke\n                metadata, status = key_manager.validate_key(potential_key)\n                if status == \"valid\":\n                    key_manager.revoke_key(metadata[\"key_id\"])\n                    print(f\"[REVOKED] Key {metadata['key_id']} leaked in {leak.get('file')}\")\n                    # Notify the key owner\n                    notify_owner(metadata[\"owner_id\"], metadata[\"key_id\"], leak)\n```\n\n## Key Concepts\n\n| Term | Definition |\n|------|------------|\n| **API Key** | A secret string used to authenticate API requests, typically passed in headers or query parameters |\n| **Key Hashing** | Storing only the hash (SHA-256) of the API key in the database, never the plaintext key, similar to password hashing |\n| **Key Rotation** | Replacing an API key with a new one while maintaining a grace period where both keys work, ensuring zero-downtime transition |\n| **Key Scoping** | Limiting each API key to specific endpoints, HTTP methods, IP ranges, and rate limits to minimize blast radius |\n| **Key Prefix** | An identifiable prefix (e.g., sk_live_) that enables automated detection of leaked keys in logs, code, and public repositories |\n| **Secret Scanning** | Automated monitoring of repositories, logs, and public sources for exposed API keys and credentials |\n\n## Tools & Systems\n\n- **GitHub Secret Scanning**: Built-in GitHub feature that detects exposed secrets in repositories and alerts key providers\n- **gitleaks**: Open-source tool for detecting secrets in git repositories using customizable regex patterns\n- **truffleHog**: Secret scanning tool that searches entire git history for high-entropy strings and known secret patterns\n- **HashiCorp Vault**: Enterprise secret management system for API key storage, rotation, and dynamic credential generation\n- **AWS Secrets Manager**: Managed secret storage with automatic rotation support for API keys and credentials\n\n## Common Scenarios\n\n### Scenario: API Key Security Program for Developer Platform\n\n**Context**: A developer platform provides public APIs authenticated with API keys. The platform has 10,000+ API consumers generating 50M+ requests per day. Keys are frequently leaked in public GitHub repositories.\n\n**Approach**:\n1. Implement prefixed API keys (sk_live_, sk_test_) with 256-bit entropy for leak detection\n2. Store only SHA-256 hashes of keys in the database, cache validated keys in Redis\n3. Implement per-key scoping: each key restricted to specific endpoints, rate limits, and optional IP allowlists\n4. Build key rotation API with 24-hour grace period for seamless transitions\n5. Integrate with GitHub Secret Scanning to automatically detect and revoke leaked keys within minutes\n6. Run gitleaks in CI\u002FCD pipelines to prevent key commits in first place\n7. Implement anomaly detection: alert on keys used from unusual IPs or with abnormal traffic patterns\n8. Add key expiration policy: all keys expire after 365 days with 30-day advance notification\n\n**Pitfalls**:\n- Storing API keys in plaintext in the database (use SHA-256 hashing)\n- Using predictable or low-entropy key generation (use cryptographically secure random generators)\n- Not implementing key prefixes, making it impossible to identify leaked keys in automated scans\n- Allowing API keys in URL query parameters where they leak in logs, browser history, and Referer headers\n- Not implementing rate limiting per key, allowing a single compromised key to abuse the entire API\n\n## Output Format\n\n```\n## API Key Security Implementation Report\n\n**Platform**: Developer API v3\n**Total Active Keys**: 12,450\n**Daily Key Validations**: 52M\n\n### Security Controls\n\n| Control | Implementation | Status |\n|---------|---------------|--------|\n| Key Entropy | 256-bit (secrets.token_urlsafe(32)) | Implemented |\n| Key Format | sk_live_\u002Fsk_test_ prefixed | Implemented |\n| Storage | SHA-256 hashed, Redis cached | Implemented |\n| Scoping | Per-key endpoint\u002FIP\u002Frate limits | Implemented |\n| Rotation | 24-hour grace period API | Implemented |\n| Expiration | 365-day max TTL | Implemented |\n| Leak Detection | GitHub Secret Scanning + gitleaks | Active |\n| Auto-Revocation | Leaked keys revoked within 5 min | Active |\n\n### Key Leakage Stats (Last 30 Days)\n- Keys detected in public repos: 23\n- Average time to revocation: 3.2 minutes\n- Keys detected in CI\u002FCD pre-commit: 7 (prevented)\n```\n","# Implementing API Key Security Controls\n\n## When to Use\n\n- Designing secure API key generation with sufficient entropy and identifiable prefixes for leak detection\n- Implementing server-side API key hashing (never storing keys in plaintext) with SHA-256 or bcrypt\n- Building key rotation workflows that allow zero-downtime key replacement for API consumers\n- Configuring per-key scoping to limit each API key to specific endpoints, IP ranges, and rate limits\n- Setting up automated monitoring for API key leakage in GitHub repos, logs, and client-side code\n\n**Do not use** API keys as the sole authentication mechanism for user-facing applications. API keys are best suited for server-to-server communication and developer access.\n\n## Prerequisites\n\n- Secure random number generator (os.urandom, secrets module) for key generation\n- Database with proper encryption at rest for storing hashed API keys\n- Redis or similar store for key-to-metadata caching and rate limiting\n- Secret scanning tools (GitHub secret scanning, truffleHog, gitleaks)\n- Monitoring and alerting infrastructure for key usage anomalies\n\n## Workflow\n\n### Step 1: Secure API Key Generation\n\n```python\nimport secrets\nimport hashlib\nimport hmac\nimport time\nimport json\nfrom datetime import datetime, timedelta\n\nclass APIKeyManager:\n    \"\"\"Manages secure API key lifecycle: generation, storage, validation, rotation.\"\"\"\n\n    # Key format: prefix_base64random (e.g., sk_live_a1b2c3d4e5f6...)\n    # Prefix identifies the key type and environment for leak detection\n    KEY_PREFIXES = {\n        \"live_secret\": \"sk_live_\",\n        \"test_secret\": \"sk_test_\",\n        \"live_public\": \"pk_live_\",\n        \"test_public\": \"pk_test_\",\n    }\n\n    def __init__(self, db_connection, redis_connection):\n        self.db = db_connection\n        self.redis = redis_connection\n\n    def generate_key(self, key_type=\"live_secret\", owner_id=None, scopes=None,\n                     rate_limit=None, ip_allowlist=None, expires_days=365):\n        \"\"\"Generate a new API key with metadata.\"\"\"\n        prefix = self.KEY_PREFIXES.get(key_type, \"sk_live_\")\n\n        # Generate 32 bytes (256 bits) of randomness\n        random_bytes = secrets.token_bytes(32)\n        key_body = secrets.token_urlsafe(32)  # Base64url-encoded\n\n        # Full API key that the client receives (shown only once)\n        full_key = f\"{prefix}{key_body}\"\n\n        # Hash the key for storage (never store the raw key)\n        key_hash = hashlib.sha256(full_key.encode()).hexdigest()\n\n        # Create a short key ID for reference (first 8 chars)\n        key_id = f\"{prefix}{key_body[:8]}...\"\n\n        # Store the hashed key with metadata\n        key_metadata = {\n            \"key_hash\": key_hash,\n            \"key_id\": key_id,\n            \"key_type\": key_type,\n            \"owner_id\": owner_id,\n            \"scopes\": scopes or [\"read\"],\n            \"rate_limit\": rate_limit or {\"requests\": 1000, \"window\": 3600},\n            \"ip_allowlist\": ip_allowlist or [],\n            \"created_at\": datetime.utcnow().isoformat(),\n            \"expires_at\": (datetime.utcnow() + timedelta(days=expires_days)).isoformat(),\n            \"last_used\": None,\n            \"is_active\": True,\n            \"usage_count\": 0,\n        }\n\n        # Store in database\n        self.db.execute(\n            \"INSERT INTO api_keys (key_hash, key_id, metadata) VALUES (?, ?, ?)\",\n            (key_hash, key_id, json.dumps(key_metadata))\n        )\n\n        # Cache in Redis for fast validation\n        self.redis.setex(\n            f\"apikey:{key_hash}\",\n            86400,  # 24-hour cache TTL\n            json.dumps(key_metadata)\n        )\n\n        return {\n            \"api_key\": full_key,       # Show to user ONCE\n            \"key_id\": key_id,          # For reference\u002Fmanagement\n            \"scopes\": key_metadata[\"scopes\"],\n            \"expires_at\": key_metadata[\"expires_at\"],\n        }\n\n    def validate_key(self, api_key):\n        \"\"\"Validate an API key and return its metadata.\"\"\"\n        key_hash = hashlib.sha256(api_key.encode()).hexdigest()\n\n        # Check Redis cache first\n        cached = self.redis.get(f\"apikey:{key_hash}\")\n        if cached:\n            metadata = json.loads(cached)\n        else:\n            # Fall back to database\n            row = self.db.execute(\n                \"SELECT metadata FROM api_keys WHERE key_hash = ?\",\n                (key_hash,)\n            ).fetchone()\n            if not row:\n                return None, \"invalid_key\"\n            metadata = json.loads(row[0])\n            # Refresh cache\n            self.redis.setex(f\"apikey:{key_hash}\", 86400, row[0])\n\n        # Validation checks\n        if not metadata.get(\"is_active\"):\n            return None, \"key_revoked\"\n\n        if metadata.get(\"expires_at\"):\n            if datetime.fromisoformat(metadata[\"expires_at\"]) \u003C datetime.utcnow():\n                return None, \"key_expired\"\n\n        # Update last used\n        metadata[\"last_used\"] = datetime.utcnow().isoformat()\n        metadata[\"usage_count\"] = metadata.get(\"usage_count\", 0) + 1\n        self.redis.setex(f\"apikey:{key_hash}\", 86400, json.dumps(metadata))\n\n        return metadata, \"valid\"\n\n    def revoke_key(self, key_id):\n        \"\"\"Immediately revoke an API key.\"\"\"\n        row = self.db.execute(\n            \"SELECT key_hash, metadata FROM api_keys WHERE key_id = ?\",\n            (key_id,)\n        ).fetchone()\n        if row:\n            key_hash = row[0]\n            metadata = json.loads(row[1])\n            metadata[\"is_active\"] = False\n            metadata[\"revoked_at\"] = datetime.utcnow().isoformat()\n\n            self.db.execute(\n                \"UPDATE api_keys SET metadata = ? WHERE key_id = ?\",\n                (json.dumps(metadata), key_id)\n            )\n            # Invalidate cache immediately\n            self.redis.delete(f\"apikey:{key_hash}\")\n            return True\n        return False\n\n    def rotate_key(self, old_key_id, grace_period_hours=24):\n        \"\"\"Rotate an API key with a grace period where both old and new keys work.\"\"\"\n        old_row = self.db.execute(\n            \"SELECT key_hash, metadata FROM api_keys WHERE key_id = ?\",\n            (old_key_id,)\n        ).fetchone()\n        if not old_row:\n            return None, \"key_not_found\"\n\n        old_metadata = json.loads(old_row[1])\n\n        # Generate new key with same settings\n        new_key_data = self.generate_key(\n            key_type=old_metadata[\"key_type\"],\n            owner_id=old_metadata[\"owner_id\"],\n            scopes=old_metadata[\"scopes\"],\n            rate_limit=old_metadata[\"rate_limit\"],\n            ip_allowlist=old_metadata[\"ip_allowlist\"],\n        )\n\n        # Schedule old key revocation after grace period\n        revoke_at = datetime.utcnow() + timedelta(hours=grace_period_hours)\n        old_metadata[\"scheduled_revocation\"] = revoke_at.isoformat()\n        self.db.execute(\n            \"UPDATE api_keys SET metadata = ? WHERE key_id = ?\",\n            (json.dumps(old_metadata), old_key_id)\n        )\n\n        return {\n            \"new_key\": new_key_data,\n            \"old_key_id\": old_key_id,\n            \"old_key_revokes_at\": revoke_at.isoformat(),\n            \"message\": f\"Old key will be revoked in {grace_period_hours} hours\"\n        }, \"success\"\n```\n\n### Step 2: API Key Validation Middleware\n\n```python\nfrom flask import Flask, request, jsonify, g\nfrom functools import wraps\n\napp = Flask(__name__)\n\ndef require_api_key(required_scopes=None):\n    \"\"\"Middleware to validate API key and check scopes.\"\"\"\n    def decorator(f):\n        @wraps(f)\n        def wrapped(*args, **kwargs):\n            # Extract API key from header\n            api_key = request.headers.get(\"X-API-Key\")\n            if not api_key:\n                # Also check Authorization: Bearer \u003Ckey>\n                auth_header = request.headers.get(\"Authorization\", \"\")\n                if auth_header.startswith(\"Bearer \"):\n                    api_key = auth_header[7:]\n\n            if not api_key:\n                return jsonify({\"error\": \"missing_api_key\"}), 401\n\n            # Validate the key\n            metadata, status = key_manager.validate_key(api_key)\n            if status != \"valid\":\n                return jsonify({\"error\": status}), 401\n\n            # Check IP allowlist\n            if metadata.get(\"ip_allowlist\"):\n                client_ip = request.remote_addr\n                if client_ip not in metadata[\"ip_allowlist\"]:\n                    return jsonify({\"error\": \"ip_not_allowed\"}), 403\n\n            # Check scopes\n            if required_scopes:\n                key_scopes = set(metadata.get(\"scopes\", []))\n                if not key_scopes.intersection(required_scopes):\n                    return jsonify({\"error\": \"insufficient_scope\"}), 403\n\n            # Attach metadata to request context\n            g.api_key_metadata = metadata\n            return f(*args, **kwargs)\n        return wrapped\n    return decorator\n\n@app.route('\u002Fapi\u002Fv1\u002Fdata', methods=['GET'])\n@require_api_key(required_scopes=[\"read\", \"admin\"])\ndef get_data():\n    return jsonify({\"data\": \"sensitive information\"})\n\n@app.route('\u002Fapi\u002Fv1\u002Fdata', methods=['POST'])\n@require_api_key(required_scopes=[\"write\", \"admin\"])\ndef create_data():\n    return jsonify({\"created\": True})\n```\n\n### Step 3: Automated Key Leakage Detection\n\n```bash\n# Scan GitHub repositories for leaked API keys using gitleaks\ngitleaks detect --source=\u002Fpath\u002Fto\u002Frepo --config=gitleaks.toml --report-path=leaks.json\n\n# Custom gitleaks configuration for API key prefix detection\n# gitleaks.toml\ncat \u003C\u003C'EOF'\n[[rules]]\nid = \"company-api-key-live\"\ndescription = \"Company Live API Key\"\nregex = '''sk_live_[A-Za-z0-9_-]{32,}'''\ntags = [\"api-key\", \"live\", \"critical\"]\n\n[[rules]]\nid = \"company-api-key-test\"\ndescription = \"Company Test API Key\"\nregex = '''sk_test_[A-Za-z0-9_-]{32,}'''\ntags = [\"api-key\", \"test\"]\n\n[[rules]]\nid = \"company-public-key\"\ndescription = \"Company Public API Key\"\nregex = '''pk_live_[A-Za-z0-9_-]{32,}'''\ntags = [\"api-key\", \"public\"]\nEOF\n```\n\n```python\n# Automated leaked key revocation\nimport json\n\ndef process_leaked_keys(leaks_file):\n    \"\"\"Automatically revoke API keys detected in public repositories.\"\"\"\n    with open(leaks_file) as f:\n        leaks = json.load(f)\n\n    for leak in leaks:\n        key_match = leak.get(\"match\", \"\")\n        # Extract the key from the match\n        for prefix in [\"sk_live_\", \"sk_test_\", \"pk_live_\"]:\n            if prefix in key_match:\n                start = key_match.index(prefix)\n                potential_key = key_match[start:start+50]  # Max key length\n                # Validate and revoke\n                metadata, status = key_manager.validate_key(potential_key)\n                if status == \"valid\":\n                    key_manager.revoke_key(metadata[\"key_id\"])\n                    print(f\"[REVOKED] Key {metadata['key_id']} leaked in {leak.get('file')}\")\n                    # Notify the key owner\n                    notify_owner(metadata[\"owner_id\"], metadata[\"key_id\"], leak)\n```\n\n## Key Concepts\n\n| Term | Definition |\n|------|------------|\n| **API Key** | A secret string used to authenticate API requests, typically passed in headers or query parameters |\n| **Key Hashing** | Storing only the hash (SHA-256) of the API key in the database, never the plaintext key, similar to password hashing |\n| **Key Rotation** | Replacing an API key with a new one while maintaining a grace period where both keys work, ensuring zero-downtime transition |\n| **Key Scoping** | Limiting each API key to specific endpoints, HTTP methods, IP ranges, and rate limits to minimize blast radius |\n| **Key Prefix** | An identifiable prefix (e.g., sk_live_) that enables automated detection of leaked keys in logs, code, and public repositories |\n| **Secret Scanning** | Automated monitoring of repositories, logs, and public sources for exposed API keys and credentials |\n\n## Tools & Systems\n\n- **GitHub Secret Scanning**: Built-in GitHub feature that detects exposed secrets in repositories and alerts key providers\n- **gitleaks**: Open-source tool for detecting secrets in git repositories using customizable regex patterns\n- **truffleHog**: Secret scanning tool that searches entire git history for high-entropy strings and known secret patterns\n- **HashiCorp Vault**: Enterprise secret management system for API key storage, rotation, and dynamic credential generation\n- **AWS Secrets Manager**: Managed secret storage with automatic rotation support for API keys and credentials\n\n## Common Scenarios\n\n### Scenario: API Key Security Program for Developer Platform\n\n**Context**: A developer platform provides public APIs authenticated with API keys. The platform has 10,000+ API consumers generating 50M+ requests per day. Keys are frequently leaked in public GitHub repositories.\n\n**Approach**:\n1. Implement prefixed API keys (sk_live_, sk_test_) with 256-bit entropy for leak detection\n2. Store only SHA-256 hashes of keys in the database, cache validated keys in Redis\n3. Implement per-key scoping: each key restricted to specific endpoints, rate limits, and optional IP allowlists\n4. Build key rotation API with 24-hour grace period for seamless transitions\n5. Integrate with GitHub Secret Scanning to automatically detect and revoke leaked keys within minutes\n6. Run gitleaks in CI\u002FCD pipelines to prevent key commits in first place\n7. Implement anomaly detection: alert on keys used from unusual IPs or with abnormal traffic patterns\n8. Add key expiration policy: all keys expire after 365 days with 30-day advance notification\n\n**Pitfalls**:\n- Storing API keys in plaintext in the database (use SHA-256 hashing)\n- Using predictable or low-entropy key generation (use cryptographically secure random generators)\n- Not implementing key prefixes, making it impossible to identify leaked keys in automated scans\n- Allowing API keys in URL query parameters where they leak in logs, browser history, and Referer headers\n- Not implementing rate limiting per key, allowing a single compromised key to abuse the entire API\n\n## Output Format\n\n```\n## API Key Security Implementation Report\n\n**Platform**: Developer API v3\n**Total Active Keys**: 12,450\n**Daily Key Validations**: 52M\n\n### Security Controls\n\n| Control | Implementation | Status |\n|---------|---------------|--------|\n| Key Entropy | 256-bit (secrets.token_urlsafe(32)) | Implemented |\n| Key Format | sk_live_\u002Fsk_test_ prefixed | Implemented |\n| Storage | SHA-256 hashed, Redis cached | Implemented |\n| Scoping | Per-key endpoint\u002FIP\u002Frate limits | Implemented |\n| Rotation | 24-hour grace period API | Implemented |\n| Expiration | 365-day max TTL | Implemented |\n| Leak Detection | GitHub Secret Scanning + gitleaks | Active |\n| Auto-Revocation | Leaked keys revoked within 5 min | Active |\n\n### Key Leakage Stats (Last 30 Days)\n- Keys detected in public repos: 23\n- Average time to revocation: 3.2 minutes\n- Keys detected in CI\u002FCD pre-commit: 7 (prevented)\n```\n",{"name":5,"tags":57,"author":58,"domain":43,"license":15,"version":59,"nist_csf":60,"subdomain":44,"description":7,"nist_ai_rmf":65,"mitre_attack":69,"atlas_techniques":75},[44,39,38,37,36],"mahipal","1.0.0",[61,62,63,64],"PR.PS-01","ID.RA-01","PR.DS-10","DE.CM-01",[66,67,68],"MEASURE-2.7","MAP-5.1","MANAGE-2.4",[70,71,72,73,74],"T1190","T1059.007","T1552.001","T1003","T1110",[76,77,78],"AML.T0070","AML.T0066","AML.T0082","main","54a798831d2266a3ca61ce68a7acb80b81160d57","skills\u002Fimplementing-api-key-security-controls",4414,"https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills","https:\u002F\u002Fmahipal.engineer\u002FAnthropic-Cybersecurity-Skills\u002F","https:\u002F\u002Fgithub.com\u002Fmukul975","Mahipal.engineer","🔐 Cybersecurity | 💻 Dev | 📷 Street Photographer\r\n🎓 MSc | 📚 Research & AI Security","2026-08-31 12:32:44",{"source":8,"skillName":5,"commands":90,"prompt":100,"zipAvailable":101},[91,94,97],{"tool":92,"command":93},"npx","npx skills add mukul975\u002FAnthropic-Cybersecurity-Skills --skill implementing-api-key-security-controls",{"tool":95,"command":96},"bunx","bunx skills add mukul975\u002FAnthropic-Cybersecurity-Skills --skill implementing-api-key-security-controls",{"tool":98,"command":99},"pnpm","pnpm dlx skills add mukul975\u002FAnthropic-Cybersecurity-Skills --skill implementing-api-key-security-controls","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fimplementing-api-key-security-controls\u002FSKILL.md",true,[103,108,114],{"path":104,"resourceType":104,"resourceTypeDesc":105,"sizeBytes":106,"sourceHtmlUrl":107},"LICENSE","许可证",11255,"https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fimplementing-api-key-security-controls\u002FLICENSE",{"path":109,"resourceType":110,"resourceTypeDesc":111,"sizeBytes":112,"sourceHtmlUrl":113},"references\u002Fapi-reference.md","REFERENCE","参考文档",1327,"https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fimplementing-api-key-security-controls\u002Freferences\u002Fapi-reference.md",{"path":115,"resourceType":116,"resourceTypeDesc":117,"sizeBytes":118,"sourceHtmlUrl":119},"scripts\u002Fagent.py","SCRIPT","脚本",6010,"https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fimplementing-api-key-security-controls\u002Fscripts\u002Fagent.py",[121,145,168,196,221,248],{"skillNo":122,"name":123,"nameZh":6,"description":124,"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":52},"01M6AGDM3HJXTKXX15ZZ0ZVCJ3","verifying-build-provenance-with-slsa-sigstore","Verifies artifact signatures and SLSA provenance using Sigstore's cosign (verify, verify-attestation, verify-blob-attestation) and slsa-verifier (verify-artifact), enforcing keyless OIDC builder identity and source repo against SLSA Build levels. Use in CI\u002FCD before deploying artifacts, when consuming third-party attestations, establishing a SLSA Build L3 pipeline, or confirming provenance during incident response or admission control.","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fverifying-build-provenance-with-slsa-sigstore\u002FSKILL.md",[127],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[129,130,131,132,32,43,133,134,49,48,135,136,137,138,139,140,141,142,143,144],"sigstore","provenance","slsa","verifying build provenance with slsa sigstore","incident response","identity","artifacts","ci","supply-chain","pipeline","supply-chain-security","t1195","attestation","code-signing","cosign","keyless",{"skillNo":146,"name":147,"nameZh":6,"description":148,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":149,"categories":150,"keywords":152,"publishedAt":52},"01M6AGDGBPWYVZ2F11GFKJ4HZ9","validating-tpm-measured-boot-attestation","Verifies TPM 2.0 measured-boot integrity and remote attestation with tpm2-tools -- reading PCRs (tpm2_pcrread), replaying the boot event log, generating and checking signed quotes (tpm2_quote\u002Ftpm2_checkquote), and sealing secrets to a PCR policy. Use to confirm a system booted trusted firmware\u002Fkernel for Zero Trust device posture, detect boot-chain tampering via PCR drift, or build a golden-value baseline for fleet attestation.","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fvalidating-tpm-measured-boot-attestation\u002FSKILL.md",[151],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[153,141,154,155,32,156,43,49,157,34,158,159,160,161,162,163,164,165,166,167],"boot","TPM","validating tpm measured boot attestation","policy","verification","firmware","Tools","measured-boot","PCR","integrity","secrets","remote-attestation","tpm2-tools","integrity-verification","trusted-computing",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":178,"publishedAt":52},"01M6AGDCW0Y4FXZ3362GT1941M","validating-backup-integrity-for-recovery","Validates backup integrity through cryptographic hash verification, automated restore testing, corruption detection, and recoverability checks to confirm backups are reliable for disaster recovery and ransomware response. Use before relying on backups for recovery, when building post-backup validation pipelines, auditing backup infrastructure for compliance, or checking immutable\u002Fair-gapped backups for silent corruption or tampering.","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Fvalidating-backup-integrity-for-recovery\u002FSKILL.md",[174,177],{"categoryNo":175,"categoryName":176,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[162,179,180,181,182,43,183,184,157,185,186,187,188,189,190,191,192,193,194,195],"backup","recovery","validating backup integrity for recovery","testing","infrastructure","validation","compliance","hash-verification","incident-response","ransomware","cryptocurrency","detection","t1078","t1490","immutable","disaster-recovery","restore-testing",{"skillNo":197,"name":198,"nameZh":6,"description":199,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":200,"categories":201,"keywords":203,"publishedAt":52},"01M6AGD9GBG2KZ336AE763J3WH","triaging-windows-with-kape","Runs KAPE (Kroll Artifact Parser and Extractor) to collect targeted forensic artifacts (registry hives, $MFT, event logs, prefetch, browser data) via Targets and parse them with Modules wrapping Eric Zimmerman's EZ Tools (PECmd, MFTECmd, RECmd). Use during early incident containment\u002Ftriage when full disk imaging is impractical but a defensible, parseable Windows artifact set is needed quickly, including at-scale remote collection.","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Ftriaging-windows-with-kape\u002FSKILL.md",[202],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[204,205,206,43,207,208,47,209,210,211,212,213,214,215,216,217,159,218,219,220],"windows","kape","triaging windows with kape","registry","browser","windows-forensics","dfir","mft","mftecmd","data","prefetch","eric-zimmerman","digital-forensics","SET","collection","pecmd","artifact-collection",{"skillNo":222,"name":223,"nameZh":6,"description":224,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":225,"categories":226,"keywords":228,"publishedAt":52},"01M6AGD5PW5J4EVZM958WD74ZQ","triaging-vulnerabilities-with-ssvc-framework","Triages and prioritizes vulnerabilities with CISA's Stakeholder-Specific Vulnerability Categorization (SSVC) decision tree, weighing exploitation status (via the CISA KEV catalog and FIRST EPSS API), technical impact, automatability, and mission prevalence to output Track\u002FTrack*\u002FAttend\u002FAct decisions. Use when prioritizing vulnerability scan results (OpenVAS, Nessus, Qualys) for remediation planning beyond raw CVSS scores.","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Ftriaging-vulnerabilities-with-ssvc-framework\u002FSKILL.md",[227],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[229,230,231,43,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247],"vulnerabilities","framework","triaging vulnerabilities with ssvc framework","status","planning","CISA","vulnerability-management","risk-management","nessus","qualys","openvas","cvss","remediation","risk","vulnerability","api","prioritization","ssvc","decision-tree",{"skillNo":249,"name":250,"nameZh":6,"description":251,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":252,"categories":253,"keywords":255,"publishedAt":52},"01M6AGD24TTQQM4CXG69E3B9TJ","triaging-security-incident","Performs initial triage of security incidents using the NIST SP 800-61r3 and SANS PICERL frameworks, classifying incident type, assigning priority by business impact, and routing to the appropriate response team. Use when a SIEM\u002FEDR alert needs human classification, concurrent alerts must be prioritized, or a user report or threat-intel IOC match requires initial incident categorization.","https:\u002F\u002Fgithub.com\u002Fmukul975\u002FAnthropic-Cybersecurity-Skills\u002Fblob\u002Fmain\u002Fskills\u002Ftriaging-security-incident\u002FSKILL.md",[254],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[32,256,43,257,258,259,260,261,262,263,264,191,265,192,266,267,268,269,270,271],"triaging security incident","siem","file","ioc","soc","NIST-800-61","NIST","severity","edr","execution","analysis","classification","severity-classification","incident-triage","SANS-PICERL","SOC-operations"]