Claude Code Plugins

Community-maintained marketplace

Feedback

security-aware-documentation

@tachyon-beep/skillpacks
0
0

Use when documenting systems with sensitive data or security features - covers sanitizing examples (never use real credentials/PII), threat disclosure decisions, compliance sensitivity, redaction patterns, and security feature documentation

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name security-aware-documentation
description Document systems safely - sanitize examples, avoid credentials/PII, handle threat disclosure

Security-Aware Documentation

Overview

Document systems without compromising security. Core principle: Documentation should inform, not expose.

Key insight: Examples with real credentials/PII leak secrets. Obviously fake examples are safe and clear.

When to Use

Load this skill when:

  • Documenting authentication/authorization
  • Creating API examples with credentials
  • Writing about systems handling PII or classified data
  • Documenting security features

Symptoms you need this:

  • "How do I show API key example without exposing real keys?"
  • Writing documentation for healthcare/finance systems
  • Creating examples with user data
  • Documenting security configurations

Don't use for:

  • General documentation without security concerns
  • Internal-only docs (though still good practice)

Sanitizing Examples

Rule 1: Never Use Real Credentials

WRONG:

# Don't mask real secrets
curl -H "Authorization: Bearer sk_live_51Hx***REDACTED***" \
  https://api.example.com/users

Problem: Pattern sk_live_51Hx... suggests real Stripe key structure. Reader might think they should unmask it.

RIGHT:

# Generate obviously fake credentials
curl -H "Authorization: Bearer fake_key_abc123_for_docs_only" \
  https://api.example.com/users

Better: Clearly fake, no confusion possible.


Rule 2: Use Obviously Fake Values

Fake Credentials Pattern:

fake_[type]_[random]_for_docs_only

Examples:

  • API key: fake_api_key_abc123_for_docs_only
  • JWT token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.FAKE_TOKEN_FOR_DOCUMENTATION.fake_signature_do_not_use
  • Database password: fake_password_p@ssw0rd_example_only
  • SSH key: fake_ssh_key_AAAAB3NzaC1yc2EAAAADAQABAAABAQ... (truncated for docs)

Fake PII Pattern:

[common_name]@example.com
000-00-0000 (SSN)
+1-555-0123 (phone - 555 is reserved for fiction)

Examples:

  • Email: jane.doe@example.com, user@example.org
  • SSN: 000-00-0000, 123-45-6789 (invalid format)
  • Phone: +1-555-0100, +1-555-0199
  • Address: 123 Main Street, Anytown, ST 12345

Rule 3: Use Reserved Domains

Reserved for documentation (RFC 2606):

  • example.com
  • example.net
  • example.org
  • test.com (not official but commonly accepted)

WRONG:

const API_URL = 'https://api.acmecorp.com';  // Real company?

RIGHT:

const API_URL = 'https://api.example.com';  // Obviously fake

Rule 4: Complete Fake Examples (Not Partial)

WRONG:

# Partial example - reader must guess
api_key = "YOUR_API_KEY_HERE"
client = APIClient(api_key)

Problem: Reader doesn't know what YOUR_API_KEY_HERE should look like.

RIGHT:

# Complete fake example - copy-paste-run (with fake backend)
api_key = "fake_api_key_abc123_for_docs_only"
client = APIClient(api_key)

# For real usage:
# 1. Get API key from https://dashboard.example.com/settings
# 2. Replace fake_api_key_abc123_for_docs_only with your real key
# 3. Never commit real keys to git

Better: Complete example + clear instructions for real usage.


Threat Disclosure Decisions

Document: Security Features Users Must Configure

DO document:

## Security Configuration

### Enable MFA (Required for Production)

Multi-factor authentication prevents unauthorized access even if passwords are compromised.

Enable MFA for all admin accounts:
\```bash
user-admin mfa enable --user admin@example.com --method totp
\```

**Security impact**: Without MFA, stolen passwords grant full access.

Document: Security Best Practices

DO document:

## Hardening Guide

### Disable Unused Services

**Threat**: Unused services increase attack surface.

Disable SSH if not needed:
\```bash
systemctl disable sshd
systemctl stop sshd
\```

**Verification**: `systemctl status sshd` should show "inactive (dead)"

Don't Document: Specific Vulnerabilities

DON'T document:

## Known Issues

### CVE-2024-12345: SQL Injection in /api/users Endpoint

Vulnerable code in `user_controller.py:45`:
\```python
query = f"SELECT * FROM users WHERE id = {user_id}"  # Vulnerable!
\```

Attacker can inject SQL via: `/api/users?id=1 OR 1=1`

Problem: Provides exploit guide to attackers.

DO instead: Coordinate with security team for disclosure. Document fix after patch released:

## Security Updates

### Version 2.1.5 (2024-03-15)

**Security fix**: Resolved input validation issue in user API (CVE-2024-12345).
Upgrade immediately.

For technical details, see our security advisory: [link]

Don't Document: Internal Security Architecture (Unless Necessary)

DON'T document (in public docs):

## Internal Security Architecture

Our secrets vault runs on ec2-10-0-1-50.internal with:
- Port 8200 (HTTP API)
- Port 8201 (cluster communication)
- Root token stored in S3 bucket: company-secrets-prod
- Unsealing keys split across: admin1@company.com, admin2@company.com, admin3@company.com

Problem: Reveals infrastructure details aiding attackers (IP addresses, ports, bucket names, key custodians).

DO instead: Document what users need, abstract internals:

## Secrets Management

Secrets are stored in an encrypted vault. To access secrets:

1. Request access via [access-request-form]
2. Use provided vault token
3. Tokens expire after 8 hours

See [secrets-access-guide] for details.

Compliance Sensitivity

Rule: Document Controls Without Revealing Weaknesses

WRONG:

## SOC2 Compliance

### Access Control (CC6.1)

**Control**: Role-based access control (RBAC)

**Current gaps**:
- Admin users can bypass RBAC via debug mode (known issue #245)
- No access reviews conducted (planned for Q3)
- 3 dormant admin accounts still active (cleanup delayed)

Problem: Audit report publicly reveals control weaknesses.

RIGHT:

## SOC2 Compliance

### Access Control (CC6.1)

**Control**: Role-based access control (RBAC)

**Implementation**:
- Authentication: MFA required for admin accounts
- Authorization: Permissions enforced at API layer and database layer
- Access reviews: Quarterly review of all privileged accounts
- Account lifecycle: Automated disablement after 30 days inactivity

**Audit evidence**: Available to authorized auditors via [compliance-portal]

Better: Focus on what exists, keep gaps internal.


Redaction Patterns

Logs: Redact Sensitive Data

WRONG:

[2024-03-15 10:23:45] User login: user=john.smith@acme.com, password=MyP@ssw0rd123, token=eyJhbGci...
[2024-03-15 10:24:12] API call: GET /users/12345, auth_token=sk_live_51HxAbC123...

RIGHT:

[2024-03-15 10:23:45] User login: user=john.smith@acme.com, password=[REDACTED], token=[REDACTED]
[2024-03-15 10:24:12] API call: GET /users/12345, auth_token=[REDACTED]

Even better (for docs): Use fake data:

[2024-03-15 10:23:45] User login: user=jane.doe@example.com, password=[REDACTED], token=[REDACTED]
[2024-03-15 10:24:12] API call: GET /users/67890, auth_token=[REDACTED]

Screenshots: Blur Sensitive Data

Before sharing screenshot:

  1. Use test account (user@example.com, fake data)
  2. Blur any real data (names, emails, IDs)
  3. Use browser extensions: "Redact for Screenshot"

WRONG: Screenshot with production data visible

RIGHT: Screenshot with:

  • Fake user names (Jane Doe, John Smith)
  • Fake emails (jane@example.com)
  • Blurred real data if any leaked

Diagrams: Anonymize Infrastructure

WRONG:

[Load Balancer: lb-prod-01.company.com (52.12.34.56)]
       ↓
[API Servers: api-01.internal (10.0.1.10), api-02.internal (10.0.1.11)]
       ↓
[Database: postgres-master.internal (10.0.2.50)]

RIGHT:

[Load Balancer: lb.example.com (203.0.113.10)]  # RFC 5737 documentation IP
       ↓
[API Servers: api-01, api-02 (192.168.1.10-11)]  # RFC 1918 private IP
       ↓
[Database: postgres-master (192.168.2.50)]

Database Schemas: Use Synthetic Data

WRONG:

-- Example users table
SELECT * FROM users LIMIT 3;

| id | email                    | ssn         | credit_card      |
|----|--------------------------|-------------|------------------|
| 1  | alice@acmecorp.com       | 123-45-6789 | 4532-1234-5678-9012 |
| 2  | bob@acmecorp.com         | 987-65-4321 | 5105-1051-0510-5100 |
| 3  | charlie@acmecorp.com     | 456-78-9123 | 3782-822463-10005 |

RIGHT:

-- Example users table (synthetic data)
SELECT * FROM users LIMIT 3;

| id | email                  | ssn           | credit_card      |
|----|------------------------|---------------|------------------|
| 1  | alice@example.com      | 000-00-0001   | 0000-0000-0000-0001 |
| 2  | bob@example.com        | 000-00-0002   | 0000-0000-0000-0002 |
| 3  | charlie@example.com    | 000-00-0003   | 0000-0000-0000-0003 |

Security Feature Documentation

Pattern: Threat + Configuration + Impact

## Security Feature: [Name]

### Threat Prevented
[What attack does this prevent?]

### Configuration
[How to enable/configure?]
\```bash
[Example commands]
\```

### Security Impact
**If enabled**: [What protection do you get?]
**If disabled**: [What risk remains?]

### Verification
[How to verify it's working?]
\```bash
[Test commands]
\```

Example: Rate Limiting

## Security Feature: API Rate Limiting

### Threat Prevented
**Brute force attacks**: Attacker attempts thousands of login requests to guess passwords.
**DoS attacks**: Attacker overwhelms API with excessive requests.

### Configuration

Enable rate limiting in `config.yaml`:
\```yaml
rate_limiting:
  enabled: true
  max_requests: 100  # per minute per IP
  window: 60         # seconds
  block_duration: 300  # 5 minutes
\```

Restart API server:
\```bash
systemctl restart api-server
\```

### Security Impact
**If enabled**:
- Brute force attack limited to 100 attempts/minute (vs unlimited)
- Single IP cannot DoS entire service
- Legitimate users unaffected (typical usage: 10-20 req/min)

**If disabled**:
- Attacker can attempt 1000s of passwords per minute
- Single attacker can exhaust server resources
- No protection against credential stuffing attacks

### Verification

Test rate limit:
\```bash
# Attempt 101 requests in 1 minute
for i in {1..101}; do
  curl https://api.example.com/login -d "user=test&pass=fake"
done

# Expected: First 100 succeed, 101st returns:
# HTTP 429 Too Many Requests
# Retry-After: 60
\```

Check logs:
\```bash
grep "rate_limit_exceeded" /var/log/api-server.log
# Should show: [2024-03-15 10:25:45] Rate limit exceeded: IP 203.0.113.10, endpoint /login
\```

Quick Reference: Sanitization Checklist

Data Type ❌ Wrong ✅ Right
API Key sk_live_***REDACTED*** fake_api_key_abc123_for_docs_only
JWT Token eyJhbGci... (real masked) eyJhbGci...FAKE_TOKEN_FOR_DOCUMENTATION...
Email john.smith@acme.com jane.doe@example.com
SSN ***-**-1234 000-00-0000
Phone (555) ***-1234 +1-555-0100
IP Address 52.12.34.56 (real AWS) 203.0.113.10 (RFC 5737 docs)
Domain api.acme.com api.example.com
Database Password p@ssw*** fake_password_example_only

Common Mistakes

❌ Masking Real Secrets

Wrong: sk_live_***REDACTED*** (pattern suggests real key)

Right: fake_api_key_abc123_for_docs_only (obviously fake)

Why: Masked secrets still leak structure. Readers might try to unmask or think it's production data.


❌ Using Real Company Names

Wrong: curl https://api.acmecorp.com (might be real company)

Right: curl https://api.example.com (reserved for docs)

Why: Avoid accidental real company references. Use RFC-designated example domains.


❌ Documenting Exploits Before Patch

Wrong: Publish CVE details with exploit code before customers patch

Right: Coordinate disclosure with security team, publish after patch available

Why: Responsible disclosure prevents weaponizing vulnerabilities before users can protect themselves.


❌ Incomplete Redaction

Wrong: Redact password but leave username + server IP

Right: Redact all PII/credentials and use example IPs

Why: Partial redaction still enables attacks. Usernames + server IPs = reconnaissance.


Cross-References

Use WITH this skill:

  • muna/technical-writer/clarity-and-style - Write clear security documentation
  • ordis/security-architect/threat-modeling - Understand threats documentation might expose

Use AFTER this skill:

  • muna/technical-writer/documentation-testing - Verify examples work (with fake credentials)

Real-World Impact

Projects using security-aware documentation:

  • API Documentation (Healthcare): Sanitized all examples with jane.doe@example.com, fake_api_key_.... Prevented accidental PII exposure in publicly-accessible docs.
  • OAuth Flow Tutorial: Used complete fake examples (client_id=fake_client_abc123) vs placeholders (YOUR_CLIENT_ID_HERE). Support tickets reduced 60% ("I don't know what client ID looks like").
  • Database Migration Guide: Used synthetic data (SSN: 000-00-0000) vs redacted real data (SSN: ***-**-1234). Compliance audit passed with "exemplary PII handling in documentation".

Key lesson: Obviously fake examples are clearer and safer than masked real data. Complete fake examples enable copy-paste-run testing without security risk.