cc-skill-security-review
すべてのコードがセキュリティのベストプラクティスに従っているかを確認し、潜在的な脆弱性を特定するスキルです。認証・認可の実装、ユーザー入力やファイルアップロードの処理、新しいAPIエンドポイントの作成時に使用してください。
description の原文を見る
This skill ensures all code follows security best practices and identifies potential vulnerabilities. Use when implementing authentication or authorization, handling user input or file uploads, or creating new API endpoints.
SKILL.md 本文
セキュリティレビュー スキル
このスキルはすべてのコードがセキュリティのベストプラクティスに従っていることを保証し、潜在的な脆弱性を特定します。
使用時期
- 認証または認可の実装
- ユーザー入力またはファイルアップロードの処理
- 新しい API エンドポイントの作成
- シークレットまたは認証情報の操作
- 決済機能の実装
- 機密データの保存または送信
- サードパーティ API の統合
セキュリティチェックリスト
1. シークレット管理
❌ これをしてはいけません
const apiKey = "sk-proj-xxxxx" // Hardcoded secret
const dbPassword = "password123" // In source code
✅ 常にこのようにしてください
const apiKey = process.env.OPENAI_API_KEY
const dbUrl = process.env.DATABASE_URL
// Verify secrets exist
if (!apiKey) {
throw new Error('OPENAI_API_KEY not configured')
}
確認ステップ
- ハードコードされた API キー、トークン、またはパスワードがない
- すべてのシークレットが環境変数に配置されている
-
.env.localが .gitignore に含まれている - git 履歴にシークレットがない
- 本番環境のシークレットがホスティングプラットフォーム (Vercel, Railway) に配置されている
2. 入力検証
ユーザー入力の常時検証
import { z } from 'zod'
// Define validation schema
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().min(0).max(150)
})
// Validate before processing
export async function createUser(input: unknown) {
try {
const validated = CreateUserSchema.parse(input)
return await db.users.create(validated)
} catch (error) {
if (error instanceof z.ZodError) {
return { success: false, errors: error.errors }
}
throw error
}
}
ファイルアップロード検証
function validateFileUpload(file: File) {
// Size check (5MB max)
const maxSize = 5 * 1024 * 1024
if (file.size > maxSize) {
throw new Error('File too large (max 5MB)')
}
// Type check
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
if (!allowedTypes.includes(file.type)) {
throw new Error('Invalid file type')
}
// Extension check
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']
const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
if (!extension || !allowedExtensions.includes(extension)) {
throw new Error('Invalid file extension')
}
return true
}
確認ステップ
- すべてのユーザー入力がスキーマで検証されている
- ファイルアップロードが制限されている (サイズ、種類、拡張子)
- ユーザー入力がクエリで直接使用されていない
- ホワイトリスト検証 (ブラックリストではない)
- エラーメッセージが機密情報を漏らさない
3. SQL インジェクション対策
❌ SQL を連結してはいけません
// DANGEROUS - SQL Injection vulnerability
const query = `SELECT * FROM users WHERE email = '${userEmail}'`
await db.query(query)
✅ パラメータ化されたクエリを常に使用してください
// Safe - parameterized query
const { data } = await supabase
.from('users')
.select('*')
.eq('email', userEmail)
// Or with raw SQL
await db.query(
'SELECT * FROM users WHERE email = $1',
[userEmail]
)
確認ステップ
- すべてのデータベースクエリがパラメータ化されている
- SQL に文字列連結がない
- ORM/クエリビルダーが正しく使用されている
- Supabase クエリが適切にサニタイズされている
4. 認証と認可
JWT トークン処理
// ❌ 間違い: localStorage (XSS に脆弱)
localStorage.setItem('token', token)
// ✅ 正解: httpOnly クッキー
res.setHeader('Set-Cookie',
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
認可チェック
export async function deleteUser(userId: string, requesterId: string) {
// ALWAYS verify authorization first
const requester = await db.users.findUnique({
where: { id: requesterId }
})
if (requester.role !== 'admin') {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 403 }
)
}
// Proceed with deletion
await db.users.delete({ where: { id: userId } })
}
Row Level Security (Supabase)
-- Enable RLS on all tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Users can only view their own data
CREATE POLICY "Users view own data"
ON users FOR SELECT
USING (auth.uid() = id);
-- Users can only update their own data
CREATE POLICY "Users update own data"
ON users FOR UPDATE
USING (auth.uid() = id);
確認ステップ
- トークンが httpOnly クッキーに保存されている (localStorage ではない)
- 機密操作前に認可チェックが行われている
- Supabase で Row Level Security が有効になっている
- ロールベースのアクセス制御が実装されている
- セッション管理が安全である
5. XSS 対策
HTML のサニタイズ
import DOMPurify from 'isomorphic-dompurify'
// ALWAYS sanitize user-provided HTML
function renderUserContent(html: string) {
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],
ALLOWED_ATTR: []
})
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}
Content Security Policy
// next.config.js
const securityHeaders = [
{
key: 'Content-Security-Policy',
value: `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
`.replace(/\s{2,}/g, ' ').trim()
}
]
確認ステップ
- ユーザー提供の HTML がサニタイズされている
- CSP ヘッダーが設定されている
- 未検証の動的コンテンツがレンダリングされていない
- React の組み込み XSS 対策が使用されている
6. CSRF 対策
CSRF トークン
import { csrf } from '@/lib/csrf'
export async function POST(request: Request) {
const token = request.headers.get('X-CSRF-Token')
if (!csrf.verify(token)) {
return NextResponse.json(
{ error: 'Invalid CSRF token' },
{ status: 403 }
)
}
// Process request
}
SameSite クッキー
res.setHeader('Set-Cookie',
`session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)
確認ステップ
- 状態変化操作に CSRF トークンが使用されている
- すべてのクッキーで SameSite=Strict が設定されている
- ダブルサミットクッキーパターンが実装されている
7. レート制限
API レート制限
import rateLimit from 'express-rate-limit'
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: 'Too many requests'
})
// Apply to routes
app.use('/api/', limiter)
負荷の高い操作
// Aggressive rate limiting for searches
const searchLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // 10 requests per minute
message: 'Too many search requests'
})
app.use('/api/search', searchLimiter)
確認ステップ
- すべての API エンドポイントにレート制限が適用されている
- 負荷の高い操作にはより厳しい制限が適用されている
- IP ベースのレート制限が実装されている
- ユーザーベースのレート制限 (認証済み) が実装されている
8. 機密データの露出
ログ
// ❌ 間違い: 機密データをログに出力
console.log('User login:', { email, password })
console.log('Payment:', { cardNumber, cvv })
// ✅ 正解: 機密データをマスク
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
エラーメッセージ
// ❌ 間違い: 内部の詳細情報を公開
catch (error) {
return NextResponse.json(
{ error: error.message, stack: error.stack },
{ status: 500 }
)
}
// ✅ 正解: 汎用的なエラーメッセージ
catch (error) {
console.error('Internal error:', error)
return NextResponse.json(
{ error: 'An error occurred. Please try again.' },
{ status: 500 }
)
}
確認ステップ
- パスワード、トークン、またはシークレットがログに出力されていない
- ユーザー向けのエラーメッセージが汎用的である
- 詳細なエラーはサーバーログのみに記録されている
- スタックトレースがユーザーに公開されていない
9. ブロックチェーンセキュリティ (Solana)
ウォレット検証
import { verify } from '@solana/web3.js'
async function verifyWalletOwnership(
publicKey: string,
signature: string,
message: string
) {
try {
const isValid = verify(
Buffer.from(message),
Buffer.from(signature, 'base64'),
Buffer.from(publicKey, 'base64')
)
return isValid
} catch (error) {
return false
}
}
トランザクション検証
async function verifyTransaction(transaction: Transaction) {
// Verify recipient
if (transaction.to !== expectedRecipient) {
throw new Error('Invalid recipient')
}
// Verify amount
if (transaction.amount > maxAmount) {
throw new Error('Amount exceeds limit')
}
// Verify user has sufficient balance
const balance = await getBalance(transaction.from)
if (balance < transaction.amount) {
throw new Error('Insufficient balance')
}
return true
}
確認ステップ
- ウォレット署名が検証されている
- トランザクション詳細が検証されている
- トランザクション前に残高チェックが実施されている
- ブラインドトランザクション署名がない
10. 依存関係のセキュリティ
定期的な更新
# Check for vulnerabilities
npm audit
# Fix automatically fixable issues
npm audit fix
# Update dependencies
npm update
# Check for outdated packages
npm outdated
ロックファイル
# ALWAYS commit lock files
git add package-lock.json
# Use in CI/CD for reproducible builds
npm ci # Instead of npm install
確認ステップ
- 依存関係が最新である
- 既知の脆弱性がない (npm audit がクリーン)
- ロックファイルがコミットされている
- GitHub で Dependabot が有効になっている
- 定期的なセキュリティ更新が実施されている
セキュリティテスト
自動セキュリティテスト
// Test authentication
test('requires authentication', async () => {
const response = await fetch('/api/protected')
expect(response.status).toBe(401)
})
// Test authorization
test('requires admin role', async () => {
const response = await fetch('/api/admin', {
headers: { Authorization: `Bearer ${userToken}` }
})
expect(response.status).toBe(403)
})
// Test input validation
test('rejects invalid input', async () => {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ email: 'not-an-email' })
})
expect(response.status).toBe(400)
})
// Test rate limiting
test('enforces rate limits', async () => {
const requests = Array(101).fill(null).map(() =>
fetch('/api/endpoint')
)
const responses = await Promise.all(requests)
const tooManyRequests = responses.filter(r => r.status === 429)
expect(tooManyRequests.length).toBeGreaterThan(0)
})
本番環境デプロイ前セキュリティチェックリスト
本番環境へのデプロイ前に:
- シークレット: ハードコードされたシークレットがなく、すべて環境変数に配置
- 入力検証: すべてのユーザー入力が検証されている
- SQL インジェクション: すべてのクエリがパラメータ化されている
- XSS: ユーザーコンテンツがサニタイズされている
- CSRF: 保護が有効になっている
- 認証: 適切なトークン処理が実装されている
- 認可: ロールチェックが実装されている
- レート制限: すべてのエンドポイントで有効になっている
- HTTPS: 本番環境で強制されている
- セキュリティヘッダー: CSP、X-Frame-Options が設定されている
- エラー処理: エラーに機密データが含まれていない
- ログ: ログに機密データが含まれていない
- 依存関係: 最新で脆弱性がない
- Row Level Security: Supabase で有効になっている
- CORS: 適切に設定されている
- ファイルアップロード: 検証されている (サイズ、種類)
- ウォレット署名: 検証されている (ブロックチェーンの場合)
リソース
重要: セキュリティはオプションではありません。1 つの脆弱性がプラットフォーム全体を危険にさらす可能性があります。疑わしい場合は、慎重な方を選択してください。
使用時期
このスキルは、概要で説明されているワークフローまたはアクションを実行する場合に適用可能です。
制限事項
- このスキルは、上記で説明されているスコープに明確に該当するタスクの場合にのみ使用してください。
- 出力を環境固有の検証、テスト、または専門家の確認の代替として扱わないでください。
- 必要な入力、権限、セキュリティの境界、または成功基準が不足している場合は、停止して明確化を求めてください。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- sickn33
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/sickn33/antigravity-awesome-skills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。