# Security Compliance Officer

> AI Agent 安全合规专家 - 权限分级、PII 保护、策略执行、安全审计、合规检查、denial tracking

- **Type:** Skill
- **Install:** `agentstack add skill-nihao555-hub-claude-code-agent-skills-security-compliance-officer`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [nihao555-hub](https://agentstack.voostack.com/s/nihao555-hub)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [nihao555-hub](https://github.com/nihao555-hub)
- **Source:** https://github.com/nihao555-hub/claude-code-agent-skills/tree/main/skills/security-compliance-officer

## Install

```sh
agentstack add skill-nihao555-hub-claude-code-agent-skills-security-compliance-officer
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Security Compliance Officer

使用此技能当你需要进行安全合规系统设计、权限控制实现、PII 保护机制开发、或安全审计流程建立。

## 目标

产出完整的安全合规方案，包括权限分级系统、PII 保护机制、策略执行引擎、安全审计日志和合规检查清单。

## 核心能力

### 1. 权限模式系统 (src/utils/permissions/PermissionMode.ts)

Claude Code定义了 6 种权限模式：

```typescript
export const PERMISSION_MODES = [
  'default',           // 标准审批流程
  'plan',              // 计划模式（只读）
  'acceptEdits',       // 自动接受编辑
  'bypassPermissions', // 绕过权限（危险）
  'dontAsk',           // 不询问（全部允许）
  'auto',              // 自动模式（ant-only）
] as const

export const EXTERNAL_PERMISSION_MODES = [
  'default',
  'plan',
  'acceptEdits',
  'bypassPermissions',
  'dontAsk',
] as const

export type PermissionMode = typeof PERMISSION_MODES[number]
export type ExternalPermissionMode = typeof EXTERNAL_PERMISSION_MODES[number]

interface PermissionModeConfig {
  title: string
  shortTitle: string
  symbol: string
  color: ModeColorKey
  external: ExternalPermissionMode
}

const PERMISSION_MODE_CONFIG: Partial> = {
  default: {
    title: 'Default',
    shortTitle: 'Default',
    symbol: '',
    color: 'text',
    external: 'default',
  },
  plan: {
    title: 'Plan Mode',
    shortTitle: 'Plan',
    symbol: '⏸️',
    color: 'planMode',
    external: 'plan',
  },
  acceptEdits: {
    title: 'Accept edits',
    shortTitle: 'Accept',
    symbol: '⏩',
    color: 'autoAccept',
    external: 'acceptEdits',
  },
  bypassPermissions: {
    title: 'Bypass Permissions',
    shortTitle: 'Bypass',
    symbol: '⏩',
    color: 'error',
    external: 'bypassPermissions',
  },
  dontAsk: {
    title: "Don't Ask",
    shortTitle: 'DontAsk',
    symbol: '⏩',
    color: 'error',
    external: 'dontAsk',
  },
  ...(feature('TRANSCRIPT_CLASSIFIER')
    ? {
        auto: {
          title: 'Auto mode',
          shortTitle: 'Auto',
          symbol: '⏩',
          color: 'warning',
          external: 'default',
        },
      }
    : {}),
}
```

**权限模式对比**:

| 模式 | 文件读取 | 文件写入 | Shell 执行 | 适用场景 |
|------|---------|---------|-----------|----------|
| **default** | ✅ | ⚠️ 询问 | ⚠️ 询问 | 日常开发 |
| **plan** | ✅ | ❌ |  | 代码审查、学习 |
| **acceptEdits** | ✅ | ✅ 自动 | ⚠️ 询问 | 信任的自动化任务 |
| **bypassPermissions** | ✅ | ✅ | ✅ | 完全信任（危险！） |
| **dontAsk** | ✅ | ✅ | ✅ | 无人值守任务 |
| **auto** | ✅ | 🤖 AI 决定 | 🤖 AI 决定 | 高级用户（ant-only） |

### 2. 权限规则系统

```typescript
interface PermissionRule {
  id: string
  pattern: string  // Glob pattern for file paths
  effect: 'allow' | 'deny'
  tools?: string[]  // Specific tools this rule applies to
  reason?: string   // Human-readable explanation
  createdAt: number
  updatedAt: number
}

/**
 * Check if a tool can be used with current permissions
 */
export async function canUseTool(
  toolName: string,
  input: Record,
  permissionContext: {
    mode: PermissionMode
    rules: PermissionRule[]
  }
): Promise {
  const { mode, rules } = permissionContext
  
  // Bypass permissions mode - allow everything
  if (mode === 'bypassPermissions') {
    return { status: 'approved' }
  }
  
  // Don't Ask mode - allow everything
  if (mode === 'dontAsk') {
    return { status: 'approved' }
  }
  
  // Plan Mode - read/search/list only
  if (mode === 'plan') {
    const classification = classifyMcpToolForCollapse(toolName, '', {})
    if (classification === 'read' || classification === 'search' || classification === 'list') {
      return { status: 'approved' }
    }
    return { 
      status: 'denied', 
      reason: 'Plan mode only allows read/search/list operations' 
    }
  }
  
  // Default/Auto mode - check rules
  for (const rule of rules) {
    if (ruleMatches(rule, toolName, input)) {
      if (rule.effect === 'allow') {
        return { status: 'approved' }
      } else {
        return { 
          status: 'denied', 
          reason: rule.reason || 'Blocked by permission rule' 
        }
      }
    }
  }
  
  // No matching rule - ask user
  return {
    status: 'ask_user',
    prompt: `Allow ${toolName} with arguments: ${JSON.stringify(input)}?`
  }
}

/**
 * Check if a rule matches the given tool and input
 */
function ruleMatches(
  rule: PermissionRule,
  toolName: string,
  input: Record
): boolean {
  // Check tool filter
  if (rule.tools && !rule.tools.includes(toolName)) {
    return false
  }
  
  // Check file path pattern
  if (rule.pattern) {
    const filePath = input.path as string | undefined
    if (!filePath) return false
    
    return picomatch.isMatch(filePath, rule.pattern)
  }
  
  return true
}
```

### 3. PII 保护系统

```typescript
/**
 * Types of PII to detect and redact
 */
type PIICategory = 
  | 'email'              // Email addresses
  | 'phone'              // Phone numbers
  | 'ssn'                // Social Security Numbers
  | 'credit_card'        // Credit card numbers
  | 'api_key'            // API keys and tokens
  | 'password'           // Passwords
  | 'home_path'          // User home directory paths
  | 'ip_address'         // IP addresses
  | 'aws_credentials'    // AWS access keys
  | 'github_token'       // GitHub personal access tokens

/**
 * PII detection patterns
 */
const PII_PATTERNS: Record = {
  email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
  phone: /\+?[1-9]\d{1,14}(?:\s|-|\.)/g,
  ssn: /\b\d{3}-\d{2}-\d{4}\b/g,
  credit_card: /\b(?:\d{4}[- ]?){3}\d{4}\b/g,
  api_key: /\b(sk-[a-zA-Z0-9]{32,})\b/g,
  password: /(?:"password"|"passwd"|"pwd")\s*[:=]\s*"[^"]+"/gi,
  home_path: new RegExp(`\\b/Users/[^/\\]+/|\$/HOME/|/home/[^/]+/`, 'g'),
  ip_address: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
  aws_credentials: /\b(AKIA[0-9A-Z]{16})\b/g,
  github_token: /\b(ghp_[a-zA-Z0-9]{36})\b/g,
}

/**
 * Redact PII from text
 */
export function redactPII(text: string, categories?: PIICategory[]): string {
  const cats = categories || Object.keys(PII_PATTERNS) as PIICategory[]
  
  let result = text
  for (const category of cats) {
    const pattern = PII_PATTERNS[category]
    const replacement = `[REDACTED_${category.toUpperCase()}]`
    result = result.replace(pattern, replacement)
  }
  
  return result
}

/**
 * Sanitize object for logging (deep PII removal)
 */
export function sanitizeObjectForLogging(obj: unknown): unknown {
  if (typeof obj === 'string') {
    return redactPII(obj)
  }
  
  if (Array.isArray(obj)) {
    return obj.map(item => sanitizeObjectForLogging(item))
  }
  
  if (obj !== null && typeof obj === 'object') {
    const sanitized: Record = {}
    for (const [key, value] of Object.entries(obj)) {
      // Skip sensitive keys entirely
      if (['password', 'secret', 'token', 'apiKey', 'credential'].includes(key.toLowerCase())) {
        sanitized[key] = '[REDACTED_SENSITIVE_KEY]'
      } else {
        sanitized[key] = sanitizeObjectForLogging(value)
      }
    }
    return sanitized
  }
  
  return obj
}

/**
 * Log diagnostic information without PII
 */
export function logForDiagnosticsNoPII(
  level: 'info' | 'warn' | 'error',
  event: string,
  metadata?: Record
): void {
  const sanitized = sanitizeObjectForLogging(metadata || {})
  const timestamp = new Date().toISOString()
  const logFn = level === 'error' ? console.error : 
                level === 'warn' ? console.warn : 
                console.log
  
  logFn(`[${timestamp}] [${level.toUpperCase()}] ${event}`, sanitized)
}
```

### 4. Denial Tracking System

```typescript
interface DeniedAction {
  id: string
  timestamp: number
  toolName: string
  input: Record
  reason: string
  mode: PermissionMode
  userId?: string
}

class DenialTracker {
  private denials: DeniedAction[] = []
  private readonly MAX_HISTORY = 1000
  
  /**
   * Track a denied action
   */
  track(action: Omit): void {
    const denial: DeniedAction = {
      ...action,
      id: generateId('denial'),
      timestamp: Date.now()
    }
    
    this.denials.push(denial)
    
    // Keep only recent history
    if (this.denials.length > this.MAX_HISTORY) {
      this.denials.shift()
    }
    
    // Alert on suspicious patterns
    this.detectSuspiciousPatterns()
  }
  
  /**
   * Detect suspicious denial patterns
   */
  private detectSuspiciousPatterns(): void {
    const recentWindow = 5 * 60 * 1000  // 5 minutes
    const now = Date.now()
    
    const recentDenials = this.denials.filter(
      d => now - d.timestamp  20) {
      logForDiagnosticsNoPII('warn', 'suspicious_denial_pattern', {
        count: recentDenials.length,
        window_minutes: 5,
        possible_cause: 'User may be stuck in denial loop'
      })
    }
    
    // Same tool denied repeatedly
    const toolCounts = new Map()
    for (const denial of recentDenials) {
      const count = toolCounts.get(denial.toolName) || 0
      toolCounts.set(denial.toolName, count + 1)
    }
    
    for (const [tool, count] of toolCounts.entries()) {
      if (count > 10) {
        logForDiagnosticsNoPII('warn', 'repeated_tool_denial', {
          tool,
          count,
          suggestion: 'Consider adjusting permission rules'
        })
      }
    }
  }
  
  /**
   * Get denial statistics
   */
  getStatistics(period: number = 24 * 60 * 60 * 1000): {
    total: number
    byTool: Map
    byReason: Map
    trend: 'increasing' | 'stable' | 'decreasing'
  } {
    const cutoff = Date.now() - period
    const recent = this.denials.filter(d => d.timestamp > cutoff)
    
    const byTool = new Map()
    const byReason = new Map()
    
    for (const denial of recent) {
      const toolCount = byTool.get(denial.toolName) || 0
      byTool.set(denial.toolName, toolCount + 1)
      
      const reasonCount = byReason.get(denial.reason) || 0
      byReason.set(denial.reason, reasonCount + 1)
    }
    
    // Calculate trend (compare first half vs second half of period)
    const midpoint = cutoff + period / 2
    const firstHalf = recent.filter(d => d.timestamp  d.timestamp >= midpoint).length
    
    const trend = secondHalf > firstHalf * 1.2 ? 'increasing' :
                  secondHalf  `  ${tool}: ${count}`)
  .join('\n')}

By Reason:
${Array.from(stats.byReason.entries())
  .map(([reason, count]) => `  ${reason}: ${count}`)
  .join('\n')}
`
  }
}

export const denialTracker = new DenialTracker()
```

### 5. 安全审计日志

```typescript
interface AuditLogEntry {
  id: string
  timestamp: number
  eventType: 'tool_use' | 'permission_change' | 'config_change' | 'auth_event'
  actor: {
    userId: string
    sessionId: string
    ipAddress?: string
  }
  action: string
  resource?: string
  outcome: 'success' | 'failure' | 'denied'
  details?: Record
  riskScore?: number  // 0-100
}

class SecurityAuditor {
  private logs: AuditLogEntry[] = []
  private readonly RETENTION_DAYS = 90
  
  /**
   * Log a security-relevant event
   */
  log(event: Omit): void {
    const entry: AuditLogEntry = {
      ...event,
      id: generateId('audit'),
      timestamp: Date.now()
    }
    
    this.logs.push(entry)
    
    // Auto-cleanup old entries
    this.cleanupOldEntries()
    
    // Alert on high-risk events
    if (event.riskScore && event.riskScore > 80) {
      this.alertHighRiskEvent(entry)
    }
  }
  
  /**
   * Query audit logs
   */
  query(filters: {
    startTime?: number
    endTime?: number
    eventType?: AuditLogEntry['eventType']
    actor?: string
    outcome?: AuditLogEntry['outcome']
    minRiskScore?: number
  }): AuditLogEntry[] {
    return this.logs.filter(entry => {
      if (filters.startTime && entry.timestamp  filters.endTime) return false
      if (filters.eventType && entry.eventType !== filters.eventType) return false
      if (filters.actor && entry.actor.userId !== filters.actor) return false
      if (filters.outcome && entry.outcome !== filters.outcome) return false
      if (filters.minRiskScore && (entry.riskScore || 0)  e.riskScore && e.riskScore > 50).length,
        deniedActions: recentLogs.filter(e => e.outcome === 'denied').length,
        authFailures: recentLogs.filter(e => e.eventType === 'auth_event' && e.outcome === 'failure').length
      },
      recommendations: this.generateRecommendations(recentLogs, standard)
    }
    
    return JSON.stringify(report, null, 2)
  }
  
  private cleanupOldEntries(): void {
    const cutoff = Date.now() - (this.RETENTION_DAYS * 24 * 60 * 60 * 1000)
    this.logs = this.logs.filter(entry => entry.timestamp > cutoff)
  }
  
  private alertHighRiskEvent(entry: AuditLogEntry): void {
    console.error('[SECURITY ALERT] High-risk event detected:', {
      eventId: entry.id,
      type: entry.eventType,
      action: entry.action,
      riskScore: entry.riskScore,
      timestamp: new Date(entry.timestamp).toISOString()
    })
  }
  
  private generateRecommendations(
    logs: AuditLogEntry[],
    standard: string
  ): string[] {
    const recommendations: string[] = []
    
    // Check for common security issues
    const failedAuths = logs.filter(e => e.eventType === 'auth_event' && e.outcome === 'failure').length
    if (failedAuths > 10) {
      recommendations.push('Multiple authentication failures detected - consider implementing account lockout')
    }
    
    const deniedActions = logs.filter(e => e.outcome === 'denied').length
    if (deniedActions > logs.length * 0.3) {
      recommendations.push('High denial rate - review permission policies for usability')
    }
    
    return recommendations
  }
}

export const securityAuditor = new SecurityAuditor()
```

### 6. 安全检查清单

```markdown
## 权限控制检查
- [ ] 所有敏感操作都有权限检查
- [ ] 权限规则可配置且易于理解
- [ ] 默认拒绝未知操作
- [ ] 权限变更有审计日志
- [ ] 支持最小权限原则

## PII 保护检查
- [ ] 所有日志都经过 PII 过滤
- [ ] 敏感数据加密存储
- [ ] API 密钥不硬编码
- [ ] 用户路径不泄露
- [ ] 错误信息不包含敏感数据

## 审计合规检查
- [ ] 所有安全事件都有日志
- [ ] 日志保留期符合法规要求
- [ ] 支持日志查询和导出
- [ ] 异常行为自动告警
- [ ] 定期生成合规报告

## 认证授权检查
- [ ] OAuth token 安全存储
- [ ] Token 过期自动刷新
- [ ] 支持多因素认证
- [ ] Session 超时合理设置
- [ ] 注销后彻底清理凭证
```

### 7. 安全事件响应流程

```markdown
## 安全事件分级

### P0 - 严重 (Critical)
- 凭证泄露
- 未授权访问生产数据
- 大规模 PII 泄露

**响应时间**: 立即 ( 99%
  - 脱敏完整性
  - 零 PII 泄露到日志

审计日志 (0-10分):
  - 关键操作全记录
  - 日志保留期合规
  - 查询功能完善

Denial Tracking (0-10分):
  - 拒绝操作全记录
  - 可疑模式检测
  - 统计报告准确

事件响应 (0-10分):
  - 事件分级明确
  - 响应时间达标
  - 升级路径清晰

总分评级:
  - 90-100: Excellent (生产就绪)
  - 75-89: Good (少量改进)
  - 60-74: Fair (需要加强)
  -  {...})
test('plan mode blocks writes', () => {...})
test('rules are enforced', () => {...})

# 2. PII 保护测试
test('detects emails', () => {...})
test('redacts home paths', () => {...})
test('filters API keys', () => {...})

# 3. 审计日志测试
test('logs tool usage', () => {...})
test('retains logs for 90 days', () => {...})

# 4. Denial tracking 测试
test('tracks denied actions', () => {...})
test('detects suspicious patterns', () => {...})

# 5. 事件响应测试
test('classifies events correctly', () => {...})
test('alerts on high-risk events', () => {...})
```

## AI IDE 常见陷阱检测

### 🔴 高危问题（必须修复）
```typescript
// ❌ 权限绕过
if (user.isAdmin) {
  return { status: 'approved' }  // 跳过正常权限检查!
}
// AI IDE 应该：立即警告并阻止

// ❌ PII 明文日志
console.log(`User ${email} performed ${action}`)  // email 未脱敏!
// AI IDE 应该：建议使用 logForDiagnosticsNoPII

// ❌ 硬编码凭证
const API_KEY = 'sk-xxx...'  // 直接写在代码里!
// AI IDE 应该：建议使用环境变量或密钥管理服务

// ❌ 无审计日志
await sensitiveOperation()  // 没有记录到审计日志
// AI IDE 应该：建议添加 securityAuditor.log()
```

### 🟡 中等风险（建议优化）
```typescript
// ⚠️ 权限规则过于宽松
const rules = [{ pattern: '*', effect: 'allow' }]  // 允许所有!
// AI IDE 应该：建议更精细的规则

// ⚠️ PII 检测不完整
const patterns = { email: /.../ }  // 只有 email，缺少其他类型
// AI IDE 应该：建议补充完整的 PII 类型列表
```

### 🟢 低风险（可选改进）
```typescript
// 💡 可以优化的模式
const isAllowed = user.role === 'admin'  // 简单的 RBAC
// AI IDE 可以建议：实现基于属性的访问控制 (ABAC)
```

## AI IDE 代码审查检查清单

在 PR/MR阶段，AI IDE应该自动检查：

### 权限控制
- [ ] 所有敏感操作有 canUseTool 检查
- [ ] 权限模式正确处理
- [ ] 规则匹配引擎完整
- [ ] 用户询问界面友好

### PII 保护
- [ ] 使用 sanitizeObjectForLogging
- [ ] 所有日志通过 logForDiagnosticsNoPII
- [ ] PII 模式检测完整
- [ ] 无硬编码凭证

### 审计日志
- [ ] 关键操作记录完整
- [ ] 事件类型正确分类
- [ ] 参与者信息准确
- [ ] 结果状态明确

### Denial Tracking
- [ ] 拒绝操作全部记录
- [ ] 可疑模式检测启用
- [ ] 统计数据准确
- [ ] 报告导出可用

### 事件响应
- [ ] 事件分级明确（P0-P3）
- [ ] 响应时间定义
- [ ] 升级路径清晰
- [ ] 高风崄事件告警

## AI IDE 集成实现示例

```typescript
interface SecurityRule {
  id: string
  description: s

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [nihao555-hub](https://github.com/nihao555-hub)
- **Source:** [nihao555-hub/claude-code-agent-skills](https://github.com/nihao555-hub/claude-code-agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-nihao555-hub-claude-code-agent-skills-security-compliance-officer
- Seller: https://agentstack.voostack.com/s/nihao555-hub
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
