security-hardening

/security-hardening - Threat -> Mitigation -> Tests -> Gate

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "security-hardening" with this command: npx skills add yusuketsunoda/ppt-trans/yusuketsunoda-ppt-trans-security-hardening

/security-hardening - Threat -> Mitigation -> Tests -> Gate

Goal

単一の脅威シナリオを入力として受け取り、 (1) 脅威モデル化 → (2) 緩和設計 → (3) 実装方針 → (4) テスト/ログ → (5) release-gate化 までを一貫して出す。百科事典は作らない。

Input (required)

フィールド 説明 例

target

対象(endpoint/function/module) src/app/api/files/[id]/download/route.ts

threat

再現可能な脅威シナリオ(1文) "他ユーザーのfileIdを指定するとファイルがダウンロードできる"

environment

ランタイム Next.js 16 + Supabase

constraints

互換性/性能/運用制約(あれば) "admin-dashboardからも呼ぶ"

入力は「1つの脅威」に絞る。"IDOR全般" のような曖昧な入力は禁止。

Output (must deliver all 5)

出せないならスキル失敗。

成果物 内容

1 Threat Model 攻撃者/影響/悪用難易度/既存防御層

2 Mitigation Design fail-closed/最小権限/境界チェックの方針

3 Implementation Plan diff-oriented: どのファイルのどこをどう変えるか

4 Tests + Logging 再現テスト(修正前fail, 修正後pass) + SecurityMonitorログ

5 Release Gate 再発防止ゲートの提案(自動検出可能なもの)

Workflow

Step 0: Evidence (再現確認)

攻撃が実際に成立するか、コードを読んで確認する。

1. 対象ファイルを読む

Read <target>

2. 認証/認可チェックの有無を確認

Grep "performSecurityChecks|getRequestScopedAuth|auth.uid()" <target>

3. RLS policyの確認(DB関連の場合)

Grep "CREATE POLICY|ALTER POLICY" supabase/migrations/ --glob "*.sql"

出力: 攻撃が成立する根拠(コード引用付き) + 期待する失敗条件(403/401/400)

Step 1: Threat Model

以下のテンプレートを埋める:

Threat Model

  • 攻撃者: anonymous / authenticated / insider
  • 影響: data exfiltration / privilege escalation / DoS / billing fraud
  • 悪用難易度: low(ツール不要) / medium(カスタムリクエスト) / high(特殊条件)
  • 既存の防御層: [RLS / JWT / performSecurityChecks / rate-limit / CSP]
  • 欠落している防御: [具体的に何が足りないか]

Step 2: Mitigation Design

原則(この順に適用):

  • Fail-closed: エラー時はアクセス拒否(fail-open禁止)

  • Least privilege: identityはトークンから導出、入力から取らない

  • Input validation: schema + bounds + deny-list

  • Defense in depth: RLS + アプリ層の二重チェック

  • Observability: SecurityMonitor.logEvent(PIIなし)

Step 3: Implementation Plan (パターン参照)

対象の脅威に最も近いパターンを選び、diff方針を書く。

Pattern A: IDOR (認可バイパス)

// ❌ BEFORE: userIdを入力から取得 const { userId } = await request.json(); const { data } = await supabase.from("files").select().eq("user_id", userId);

// ✅ AFTER: auth.uid()に固定 + RLS二重防御 const auth = await getRequestScopedAuth(request); if (!auth.userId) return createErrorResponse("認証が必要です", 401); const { data } = await supabase.from("files").select().eq("user_id", auth.userId);

RLS側: USING (user_id = auth.uid())

Pattern B: Token Replay (JTIリプレイ)

// jti-tracker.ts のパターン const result = await isJtiUsed(jti); if (result.used && !result.withinGrace) { await invalidateUserSessions(userId); // 全セッション無効化 return; // fail-closed } await markJtiAsUsed(jti, userId, expiresAt);

grace window: 並行リクエスト許容(60秒デフォルト)

Pattern C: Input Injection (パス/URL/SQL)

// Path traversal防御 const allowedDir = path.resolve(process.cwd(), "uploads"); const resolvedPath = path.resolve(allowedDir, filePath); if (!resolvedPath.startsWith(allowedDir + path.sep)) { // reject }

// Open redirect防御 import { sanitizeNextPath } from "@/lib/security/url-sanitizer"; const safePath = sanitizeNextPath(next, appUrl); // null byte, backslash, //, 外部origin → 全てDEFAULT_PATHにフォールバック

Pattern D: Rate Limiting (新規エンドポイント)

// performSecurityChecks に rateLimit を渡す const securityResult = await performSecurityChecks(request, { rateLimit: { windowMs: 3600_000, max: 50, keyPrefix: "translate" }, csrf: true, origin: true, }); if (!securityResult.success) { return createErrorResponse(securityResult.error!, securityResult.status!, ...); }

E2E対応: DISABLE_RATE_LIMIT_IN_E2E=true

  • X-Bypass-Rate-Limit ヘッダー

Pattern E: Webhook Verification

// Stripe webhook: 署名検証は fail-closed const sig = request.headers.get("stripe-signature"); if (!sig) return createErrorResponse("Missing signature", 400); const event = stripe.webhooks.constructEvent(body, sig, webhookSecret); // 失敗 → 400, 成功 → 処理続行

Step 4: Tests + Logging

テスト構造: 修正前に攻撃が成功することを確認 → 修正後に失敗することを確認

// テストテンプレート describe("Security: [脅威名]", () => { // 正常系: 正当なリクエストは通る it("allows legitimate request", async () => { const response = await handler(validRequest); expect(response.status).toBe(200); });

// 攻撃系: 脅威シナリオが拒否される it("rejects [threat scenario]", async () => { const response = await handler(maliciousRequest); expect(response.status).toBe(403); // or 401, 400, 429 });

// ログ系: SecurityMonitorにイベントが記録される it("logs security event", async () => { await handler(maliciousRequest); expect(mockLogEvent).toHaveBeenCalledWith( expect.objectContaining({ type: expect.any(String), severity: expect.stringMatching(/high|critical/), }) ); }); });

Logging必須チェック:

  • SecurityMonitor.logEvent() が脅威パスで呼ばれるか

  • ログにPII(email, token等)が含まれないか

  • requestId がログに含まれるか(追跡用)

Step 5: Release Gate (mandatory)

修正だけでは再発する。自動検出可能なゲートを1つ提案する。

ゲート種別 検出方法 例

API Route呼び出し漏れ grep -rL "performSecurityChecks" src/app/api/

全API Routeで統合セキュリティチェック必須

RLS policy不在 SQLマイグレーションでCREATE TABLEがあるのにCREATE POLICYがない 新テーブルにはRLS必須

SecurityMonitor未導入 脅威ハンドリングコードでlogEventがない 脅威パスにはログ必須

認証チェック漏れ getRequestScopedAuth を呼ばずにuserIdを使用 Server Actionsで認証必須

ゲート検証コマンド例

1. performSecurityChecks 呼び出し漏れ

grep -rL "performSecurityChecks" src/app/api/*/route.ts
| grep -v "webhook|health|__test"

2. RLSなしテーブル検出

grep -l "CREATE TABLE" supabase/migrations/*.sql | while read f; do table=$(grep -oP 'CREATE TABLE (?:IF NOT EXISTS )?\K\w+' "$f") if ! grep -q "CREATE POLICY.*ON $table" "$f"; then echo "MISSING RLS: $table in $f" fi done

Allowlist (例外管理)

例外は必ずここに明記する。暗黙の例外は禁止。

対象 例外内容 理由

/api/stripe/webhook

CSRF検証スキップ 外部Webhookは自前署名検証

/api/health

認証スキップ ヘルスチェック(機密情報なし)

/api/test/*

E2E環境でのみアクセス可 validateE2eAccess() で保護

JTI tracker fail-open (DBエラー時) 可用性優先(ログは記録)

例外を追加する場合: このテーブルに行を追加し、PRで明示的にレビューを受ける。

Non-Goals

  • 複数脅威を1回で処理しない(1脅威1実行)

  • パターン辞典を増やすだけの作業はしない(必ずテスト+ゲートを伴う)

  • 既存の安全なコードを「念のため」で修正しない

AI Assistant Instructions

このスキルが有効化された時:

MUST

  • Step 0 (Evidence) を必ず最初に実行。再現できない脅威は扱わない

  • 5つの成果物すべてを出力する。1つでも欠けたらスキル失敗

  • テストは「修正前fail → 修正後pass」の構造にする

  • Release gateはgrepやASTで自動検出可能なものに限定する

  • Allowlistに載っていない例外を作る場合は、ユーザーに確認する

NEVER

  • 「セキュリティ全般を強化」のような曖昧なゴールで動かない

  • SecurityMonitor.logEventにPII(email, token, password)を渡さない

  • fail-openを暗黙に導入しない(やむを得ない場合はAllowlistに明記)

  • テストなしで緩和策を実装しない

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

security-threat-review

No summary provided by upstream source.

Repository SourceNeeds Review
Security

i18n-audit

No summary provided by upstream source.

Repository SourceNeeds Review
Security

security-audit-quick

No summary provided by upstream source.

Repository SourceNeeds Review
General

pptx-translation

No summary provided by upstream source.

Repository SourceNeeds Review