# Security Review & Hardening Workflow

This skill orchestrates a comprehensive security review and implements security best practices.

## Workflow Overview

```
┌──────────────┐
│     Scan     │ → Automated security scan
└──────────────┘
       ↓
┌──────────────┐
│   Analyze    │ → Manual code review (OWASP Top 10)
└──────────────┘
       ↓
┌──────────────┐
│   Harden     │ → Fix vulnerabilities
└──────────────┘
       ↓
┌──────────────┐
│     Test     │ → Security testing
└──────────────┘
       ↓
┌──────────────┐
│   Document   │ → Create ADR & security docs
└──────────────┘
       ↓
    ✅ Done
```

## Security by Level

### Rapid
- ✅ Input validation (Zod)
- ✅ Authentication
- ✅ Basic authorization
- ✅ SQL injection prevention (Prisma)
- ✅ XSS prevention (React)

### Balanced
All from Rapid +
- ✅ CSRF protection
- ✅ Rate limiting
- ✅ Security headers
- ✅ Secrets management
- ✅ Audit logging

### Crafted
All from Balanced +
- ✅ OWASP Top 10 compliance
- ✅ Security testing (SAST/DAST)
- ✅ Penetration testing
- ✅ Security ADRs
- ✅ Threat modeling

## Step-by-Step Process

### Step 1: Automated Scan

**Goal**: Detect known vulnerabilities

**Dependency Scanning**:
```bash
# Check for vulnerable dependencies
pnpm audit

# Check for outdated packages
pnpm outdated

# Update dependencies
pnpm update
```

**Code Scanning**:
```bash
# ESLint security rules
pnpm lint

# TypeScript strict mode
pnpm typecheck
```

**Tools**:
```typescript
// Using GitHub security features
mcp__github__search_code({
  q: "password repo:owner/repo"
})

mcp__github__search_code({
  q: "api_key OR apiKey repo:owner/repo"
})
```

**Output**: List of potential vulnerabilities

---

### Step 2: OWASP Top 10 Analysis

**Goal**: Manual review for common web vulnerabilities

#### 1. Broken Access Control

**Check for**:
- Missing authentication checks
- Missing authorization checks
- Insecure direct object references

**Example Issues**:
```typescript
// ❌ INSECURE
export const userRouter = createTRPCRouter({
  delete: procedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ input }) => {
      // No auth check! Anyone can delete any user
      return await db.user.delete({ where: { id: input.id } });
    }),
});

// ✅ SECURE
export const userRouter = createTRPCRouter({
  delete: protectedProcedure // Auth required
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      // Authorization check
      if (ctx.session.user.id !== input.id && !ctx.session.user.isAdmin) {
        throw new UnauthorizedError('Cannot delete other users');
      }

      return await db.user.delete({ where: { id: input.id } });
    }),
});
```

#### 2. Cryptographic Failures

**Check for**:
- Hardcoded secrets
- Weak hashing algorithms
- Unencrypted sensitive data

**Example Issues**:
```typescript
// ❌ INSECURE
const API_KEY = 'sk_live_abc123'; // Hardcoded secret

async function hashPassword(password: string) {
  return crypto.createHash('md5').update(password).digest('hex'); // Weak algorithm
}

// ✅ SECURE
const API_KEY = process.env.STRIPE_SECRET_KEY; // From environment

async function hashPassword(password: string) {
  return await bcrypt.hash(password, 12); // Strong algorithm
}
```

#### 3. Injection

**Check for**:
- SQL injection
- NoSQL injection
- Command injection
- XSS

**Example Issues**:
```typescript
// ❌ INSECURE (if using raw SQL)
const user = await db.$executeRaw(`SELECT * FROM users WHERE email = '${email}'`);

// ✅ SECURE (Prisma prevents SQL injection)
const user = await db.user.findUnique({ where: { email } });

// ❌ INSECURE (XSS)
<div dangerouslySetInnerHTML={{ __html: userInput }} />

// ✅ SECURE (React escapes by default)
<div>{userInput}</div>

// ✅ SECURE (if HTML needed, sanitize first)
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />
```

#### 4. Insecure Design

**Check for**:
- Missing rate limiting
- No CSRF protection
- Weak session management

**Example Fixes**:
```typescript
// Rate limiting (Balanced+)
import { Ratelimit } from '@upstash/ratelimit';

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, '10 s'),
});

export const apiRouter = createTRPCRouter({
  create: publicProcedure
    .mutation(async ({ ctx }) => {
      const { success } = await ratelimit.limit(ctx.ip);

      if (!success) {
        throw new TooManyRequestsError('Rate limit exceeded');
      }

      // ...
    }),
});

// CSRF protection (Balanced+)
// Use Supabase Auth or Next.js built-in CSRF protection
```

#### 5. Security Misconfiguration

**Check for**:
- Debug mode in production
- Default credentials
- Unnecessary features enabled
- Missing security headers

**Example Fixes**:
```typescript
// next.config.js
const securityHeaders = [
  {
    key: 'X-DNS-Prefetch-Control',
    value: 'on'
  },
  {
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload'
  },
  {
    key: 'X-Frame-Options',
    value: 'SAMEORIGIN'
  },
  {
    key: 'X-Content-Type-Options',
    value: 'nosniff'
  },
  {
    key: 'Referrer-Policy',
    value: 'origin-when-cross-origin'
  },
];

module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: securityHeaders,
      },
    ];
  },
};
```

#### 6. Vulnerable and Outdated Components

**Check for**:
- Outdated dependencies
- Known CVEs

**Fix**:
```bash
pnpm audit fix
pnpm update
```

#### 7. Identification and Authentication Failures

**Check for**:
- Weak password requirements
- No MFA
- Session fixation
- Predictable session tokens

**Example Fixes**:
```typescript
// Strong password validation
const passwordSchema = z.string()
  .min(12, 'Password must be at least 12 characters')
  .regex(/[A-Z]/, 'Password must contain uppercase letter')
  .regex(/[a-z]/, 'Password must contain lowercase letter')
  .regex(/[0-9]/, 'Password must contain number')
  .regex(/[^A-Za-z0-9]/, 'Password must contain special character');

// Use Supabase Auth (handles sessions securely)
```

#### 8. Software and Data Integrity Failures

**Check for**:
- Unsigned updates
- Insecure CI/CD
- Deserialization vulnerabilities

**Example Fixes**:
```typescript
// Verify webhook signatures (e.g., Stripe)
import { buffer } from 'micro';

export const webhookHandler = async (req: NextApiRequest, res: NextApiResponse) => {
  const buf = await buffer(req);
  const sig = req.headers['stripe-signature'];

  const event = stripe.webhooks.constructEvent(
    buf,
    sig,
    process.env.STRIPE_WEBHOOK_SECRET!
  );

  // Process event...
};
```

#### 9. Security Logging and Monitoring Failures

**Check for**:
- No audit logs
- No alerting
- Insufficient logging

**Example Fixes**:
```typescript
// Audit logging (Balanced+)
export const auditLog = {
  async log(event: AuditEvent) {
    await db.auditLog.create({
      data: {
        userId: event.userId,
        action: event.action,
        resource: event.resource,
        ip: event.ip,
        userAgent: event.userAgent,
        timestamp: new Date(),
      },
    });
  },
};

// Usage
await auditLog.log({
  userId: ctx.session.user.id,
  action: 'USER_DELETED',
  resource: `user:${input.id}`,
  ip: ctx.ip,
  userAgent: ctx.userAgent,
});
```

#### 10. Server-Side Request Forgery (SSRF)

**Check for**:
- Unvalidated URLs
- Internal service exposure

**Example Fixes**:
```typescript
// ❌ INSECURE
export const fetchUrl = async (url: string) => {
  return await fetch(url); // Can access internal services!
};

// ✅ SECURE
const ALLOWED_DOMAINS = ['api.stripe.com', 'api.sendgrid.com'];

export const fetchUrl = async (url: string) => {
  const parsed = new URL(url);

  if (!ALLOWED_DOMAINS.includes(parsed.hostname)) {
    throw new Error('Domain not allowed');
  }

  // Prevent internal network access
  if (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1') {
    throw new Error('Internal network access forbidden');
  }

  return await fetch(url);
};
```

**Output**: Security issues identified

---

### Step 3: Harden

**Goal**: Fix identified vulnerabilities

**Prioritization**:
1. **Critical** (P0): Data breach, authentication bypass
2. **High** (P1): Privilege escalation, XSS
3. **Medium** (P2): CSRF, weak crypto
4. **Low** (P3): Information disclosure, missing headers

**Apply Fixes**:
- Fix critical issues immediately
- Follow level-appropriate code quality rules
- Add tests for security fixes

**Secrets Management**:
```typescript
// ✅ Use environment variables
const config = {
  stripe: {
    secretKey: process.env.STRIPE_SECRET_KEY!,
    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  },
  supabase: {
    url: process.env.NEXT_PUBLIC_SUPABASE_URL!,
    serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY!,
  },
};

// ✅ Validate environment variables on startup
const envSchema = z.object({
  STRIPE_SECRET_KEY: z.string().min(1),
  STRIPE_WEBHOOK_SECRET: z.string().min(1),
  NEXT_PUBLIC_SUPABASE_URL: z.string().url(),
  SUPABASE_SERVICE_ROLE_KEY: z.string().min(1),
});

envSchema.parse(process.env);
```

**Validation**:
```typescript
mcp__rules-validator__validate_code({
  code: hardenedCode,
  level: detectedLevel
})
```

**Output**: Vulnerabilities fixed

---

### Step 4: Security Testing

**Goal**: Verify security fixes

**Test Categories**:

1. **Authentication Tests**
   ```typescript
   describe('Authentication Security', () => {
     it('should reject unauthenticated requests', async () => {
       const result = await trpc.user.delete.mutate({ id: 'user-123' });
       expect(result).toThrow(UnauthorizedError);
     });

     it('should reject weak passwords', async () => {
       const result = await trpc.auth.register.mutate({
         email: 'test@example.com',
         password: '123', // Too weak
       });
       expect(result).toThrow('Password must be at least 12 characters');
     });
   });
   ```

2. **Authorization Tests**
   ```typescript
   describe('Authorization Security', () => {
     it('should prevent users from deleting other users', async () => {
       const result = await trpc.user.delete.mutate({ id: 'other-user-id' });
       expect(result).toThrow(UnauthorizedError);
     });

     it('should allow admins to delete users', async () => {
       const result = await trpc.user.delete.mutate({ id: 'any-user-id' });
       expect(result).toBeSuccessful();
     });
   });
   ```

3. **Input Validation Tests**
   ```typescript
   describe('Input Validation Security', () => {
     it('should reject SQL injection attempts', async () => {
       const result = await trpc.user.search.query({
         email: "'; DROP TABLE users; --",
       });
       expect(result).not.toThrow(); // Should be safely handled
       expect(result).toEqual([]); // No results
     });

     it('should sanitize XSS attempts', async () => {
       const result = await trpc.post.create.mutate({
         title: '<script>alert("XSS")</script>',
       });
       expect(result.title).not.toContain('<script>');
     });
   });
   ```

**Run Tests**:
```typescript
mcp__vitest__run_tests({ pattern: "security" })
```

**Output**: Security tests pass ✅

---

### Step 5: Document

**Goal**: Document security decisions

**Create Security ADR** (Balanced/Crafted):
```markdown
# ADR-XXX: Implement Rate Limiting

## Status
Accepted

## Context
API is vulnerable to brute-force attacks and DDoS.

## Decision
Implement rate limiting using Upstash Redis:
- 10 requests per 10 seconds per IP for public endpoints
- 100 requests per minute for authenticated endpoints

## Security Benefits
- Prevents brute-force attacks on login
- Mitigates DDoS attacks
- Reduces API abuse

## Consequences
- Positive: Improved security
- Positive: Reduced server load
- Negative: Legitimate users may hit limits
- Mitigation: Increase limits for premium users

## Implementation
- Use @upstash/ratelimit
- Apply to all public procedures
- Return 429 Too Many Requests on limit exceeded
```

**Update Security Docs**:
```markdown
# Security Guidelines

## Authentication
- All sensitive endpoints use `protectedProcedure`
- Passwords hashed with bcrypt (12 rounds)
- Sessions managed by Supabase Auth

## Authorization
- Role-based access control (RBAC)
- Admins can perform all actions
- Users can only modify their own data

## Input Validation
- All inputs validated with Zod
- Prisma prevents SQL injection
- React prevents XSS by default

## Rate Limiting
- 10 req/10s for public endpoints
- 100 req/min for authenticated endpoints

## Security Headers
- X-Frame-Options: SAMEORIGIN
- X-Content-Type-Options: nosniff
- Strict-Transport-Security enabled
```

**Output**: Security documentation complete

---

## Example Usage

### User Request
> "Review the security of our authentication system"

### Execution

```bash
# 1. Scan
pnpm audit
# Found 3 vulnerabilities

# 2. Analyze (OWASP Top 10)
# Issue 1: Missing rate limiting on login endpoint
# Issue 2: Weak password requirements (min 8 chars)
# Issue 3: No audit logging for sensitive actions

# 3. Harden
# Fix 1: Add rate limiting
import { Ratelimit } from '@upstash/ratelimit';

const loginRatelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(5, '1 m'), // 5 attempts per minute
});

# Fix 2: Strengthen password requirements
const passwordSchema = z.string()
  .min(12)
  .regex(/[A-Z]/)
  .regex(/[a-z]/)
  .regex(/[0-9]/)
  .regex(/[^A-Za-z0-9]/);

# Fix 3: Add audit logging
await auditLog.log({
  userId: user.id,
  action: 'USER_LOGIN',
  ip: ctx.ip,
});

# 4. Test
describe('Login Security', () => {
  it('should rate limit after 5 failed attempts', async () => {
    // Try 5 times
    for (let i = 0; i < 5; i++) {
      await trpc.auth.login.mutate({ email: 'test@example.com', password: 'wrong' });
    }

    // 6th attempt should be rate limited
    await expect(
      trpc.auth.login.mutate({ email: 'test@example.com', password: 'wrong' })
    ).rejects.toThrow('Rate limit exceeded');
  });
});

# 5. Document
# Create ADR-042: Authentication Security Hardening
# Update SECURITY.md

# ✅ Security review complete!
```

---

## Commands

```bash
# Invoke this skill
/security

# Or use for specific review
/security "Review authentication"
```

---

## Tips

1. **Automate scanning** - Run pnpm audit in CI
2. **Test security** - Write security tests
3. **Document decisions** - Create security ADRs
4. **Stay updated** - Monitor security advisories
5. **Principle of least privilege** - Grant minimum necessary access

---

## Common Pitfalls

❌ **Don't**:
- Hardcode secrets
- Skip input validation
- Trust user input
- Disable security features

✅ **Do**:
- Use environment variables for secrets
- Validate all inputs with Zod
- Sanitize user content
- Enable security headers
- Add rate limiting
- Log security events
