sharp-edges
エラーが発生しやすいAPI、危険な設定、セキュリティ上のミスを誘発する設計上の落とし穴を特定します。APIデザインや設定スキーマ、暗号化ライブラリの使い勝手のレビュー、または「デフォルトでセキュア」や「成功の落とし穴」原則にコードが準拠しているかの評価時に活用してください。誤用しにくい設計・安全なデフォルト値・APIの使いやすさの観点から問題箇所を洗い出します。
description の原文を見る
Identifies error-prone APIs, dangerous configurations, and footgun designs that enable security mistakes. Use when reviewing API designs, configuration schemas, cryptographic library ergonomics, or evaluating whether code follows 'secure by default' and 'pit of success' principles. Triggers: footgun, misuse-resistant, secure defaults, API usability, dangerous configuration.
SKILL.md 本文
Sharp Edges 分析
API、設定、インターフェースが開発者の誤用に対する耐性を持つかどうかを評価します。「簡単な道」が不安全性につながる設計を特定します。
使用時
- APIまたはライブラリの設計判断をレビューする場合
- 設定スキーマで危険なオプションを監査する場合
- 暗号化APIの使いやすさを評価する場合
- 認証・認可インターフェースを評価する場合
- セキュリティに関連する選択肢を開発者に露出させるコードをレビューする場合
使用しない場合
- 実装バグ(標準的なコードレビューを使用)
- ビジネスロジックの欠陥(ドメイン固有の分析を使用)
- パフォーマンス最適化(異なる関心事)
エージェント
sharp-edges-analyzer エージェントは、完全な sharp edges 分析ワークフローを自律的に実行します。API、設定、インターフェースの誤用耐性とフットガンの可能性を専用で分析したい場合に使用してください。このエージェントは4段階のワークフロー(表面識別、エッジケース調査、脅威モデリング、検証)に従い、必要に応じて言語固有のリファレンスを読み込みます。
コア原則
成功のための実装: セキュアな使用法が最も抵抗の少ないパスであるべきです。開発者が暗号化を理解したり、ドキュメントを注意深く読んだり、脆弱性を回避するために特別なルールを記憶する必要がある場合、そのAPIは失敗しています。
却下すべき言い訳
| 言い訳 | なぜ間違いか | 必要なアクション |
|---|---|---|
| 「ドキュメントに書いてある」 | 開発者は締切圧力下ではドキュメントを読まない | セキュアな選択肢をデフォルトまたは唯一の選択肢にする |
| 「上級ユーザーには柔軟性が必要」 | 柔軟性はフットガンを生む;ほとんどの「上級」使用法はコピペ | セキュアなハイレベルAPIを提供;プリミティブを隠す |
| 「開発者の責任だ」 | 責任転嫁;あなたがフットガンを設計した | フットガンを削除するか、誤用不可能にする |
| 「実際にそんなことをする人いないだろう」 | 開発者は締切圧力下であらゆることをやる | 開発者が最大限混乱することを想定する |
| 「単なる設定オプションだ」 | 設定はコード;間違った設定は本番環境に展開される | 設定を検証;危険な組み合わせを拒否する |
| 「後方互換性が必要」 | セキュアでないデフォルトは祖父条項の対象にできない | 大々的に非推奨化;移行を強制する |
Sharp Edge カテゴリー
1. アルゴリズム・モード選択のフットガン
開発者がアルゴリズムを選択できるAPIは、間違ったものを選択することを招きます。
JWT パターン(標準的な例):
- ヘッダーがアルゴリズムを指定:攻撃者が
"alg": "none"を設定して署名をバイパス可能 - アルゴリズムの混同:RS256→HS256に切り替える際にRSA公開鍵がHMAC秘密として使用される
- 根本原因:信頼できない入力がセキュリティ的に重要な判断を制御できる
検出パターン:
algorithm、mode、cipher、hash_typeのような関数パラメータ- 暗号プリミティブを選択するEnums/文字列
- セキュリティメカニズムの設定オプション
例 - PHPの password_hash が弱いアルゴリズムを許可:
// 危険: crc32, md5, sha1 を許可
password_hash($password, PASSWORD_DEFAULT); // 良好 - 選択肢なし
hash($algorithm, $password); // 悪い: "crc32" を受け入れる
2. 危険なデフォルト
セキュアでないデフォルト、またはセキュリティを無効化するゼロ/空の値。
OTP 有効期限パターン:
# lifetime=0 のときは何が起こるか?
def verify_otp(code, lifetime=300): # 300秒がデフォルト
if lifetime == 0:
return True # おっと:0 は「すべてを受け入れる」?
# それとも「直ちに期限切れ」?
検出パターン:
- 0を受け入れるタイムアウト/有効期限(無限?直ちに期限切れ?)
- チェックをバイパスする空文字列
- 検証をスキップするNull値
- セキュリティ機能を無効化するBoolean デフォルト
- 意味が不明確な負の値
質問すべきこと:
timeout=0のときは何が起こるか?max_attempts=0は?key=""は?- デフォルトは最もセキュアなオプションか?
- セキュリティを完全に無効化できるデフォルト値があるか?
3. プリミティブ vs セマンティックAPI
生バイトを露出させるAPIではなく、意味のある型を使用するAPIはタイプの混同を招きます。
Libsodium vs Halite パターン:
// Libsodium (プリミティブ): バイトはバイト
sodium_crypto_box($message, $nonce, $keypair);
// 容易に:nonce/keypair を入れ替え、nonce を再利用、間違った鍵タイプを使用
// Halite (セマンティック): 型が正しい使用法を強制
Crypto::seal($message, new EncryptionPublicKey($key));
// 間違った鍵タイプ = 型エラー、無言の失敗ではない
検出パターン:
- 異なるセキュリティコンセプトに対して
bytes、string、[]byteを取る関数 - 型エラーなしで入れ替え可能なパラメータ
- 鍵、nonce、暗号文、署名に同じ型を使用
比較のフットガン:
// タイミング安全な比較は安全でないものと同じに見える
if hmac == expected { } // 悪い:タイミング攻撃
if hmac.Equal(mac, expected) { } // 良好:定時間
// 同じ型、異なるセキュリティプロパティ
4. 設定クリフ
ひとつの間違った設定が壊滅的な失敗を引き起こす(警告なし)。
検出パターン:
- セキュリティを完全に無効化するブール値フラグ
- 検証されない文字列設定
- 危険に相互作用する設定の組み合わせ
- セキュリティ設定をオーバーライドする環境変数
- 合理的なデフォルト値を持つコンストラクタパラメータですが検証なし(呼び出し元がセキュアでない値でオーバーライド可能)
例:
# タイプミス = 災害
verify_ssl: fasle # タイプミスが黙って truthy として受け入れられるか?
# マジック値
session_timeout: -1 # これは「決して期限切れにしない」?
# 危険な組み合わせが無言で受け入れられる
auth_required: true
bypass_auth_for_health_checks: true
health_check_path: "/" # おっと
// 合理的なデフォルトは悪い呼び出し元に対して保護されない
public function __construct(
public string $hashAlgo = 'sha256', // 良好なデフォルト...
public int $otpLifetime = 120, // ...しかし md5, 0 等を受け入れる
) {}
詳細なパターンについては config-patterns.md を参照してください。
5. 無言の失敗
表面に出ないエラー、または失敗をマスクする成功。
検出パターン:
- セキュリティ失敗時に例外をスローするのではなくブール値を返す関数
- セキュリティ操作の周囲の空の catch ブロック
- パース エラー時に代替値が挿入される
- 不正な形式の入力で「成功」する検証関数
例:
# 無言のバイパス
def verify_signature(sig, data, key):
if not key:
return True # 鍵がない = 検証をスキップ?!
# 戻り値は無視される
signature.verify(data, sig) # 失敗時にスロー
crypto.verify(data, sig) # 失敗時に False を返す
# 開発者が戻り値をチェックするのを忘れる
6. Stringly-Typed セキュリティ
平文の文字列としてのセキュリティ的に重要な値はインジェクションと混同を可能にします。
検出パターン:
- 文字列の連結から構築されたSQL/コマンド
- カンマで区切られた文字列としてのパーミッション
- 任意の文字列ではなく enum としてのロール/スコープ
- 文字列を連結して構築されたURL
パーミッション累積のフットガン:
permissions = "read,write"
permissions += ",admin" # スケーレーションが簡単すぎる
# vs 型安全
permissions = {Permission.READ, Permission.WRITE}
permissions.add(Permission.ADMIN) # 少なくとも明示的
分析ワークフロー
フェーズ 1: 表面識別
- セキュリティ関連APIをマップ:認証、認可、暗号化、セッション管理、入力検証
- 開発者選択ポイントを特定:開発者がアルゴリズムを選択、タイムアウトを設定、モードを選択できる場所はどこか?
- 設定スキーマを探す:環境変数、設定ファイル、コンストラクタパラメータ
フェーズ 2: エッジケース調査
各選択ポイントについて、以下を質問:
- ゼロ/空/null:
0、""、null、[]のときは何が起こるか? - 負の値:
-1は何を意味するか?無限?エラー? - 型の混同:異なるセキュリティコンセプトを入れ替え可能か?
- デフォルト値:デフォルトはセキュアか?記述されているか?
- エラーパス:無効な入力時は何が起こるか?無言で受け入れられるか?
フェーズ 3: 脅威モデリング
3つの敵対者を考慮:
-
悪漢:悪意のある開発者または設定を制御する攻撃者
- 設定経由でセキュリティを無効化できるか?
- アルゴリズムをダウングレード可能か?
- 悪意のある値を注入可能か?
-
怠け者開発者:例をコピペ、ドキュメント読まず
- 最初に見つかった例はセキュアか?
- 最も抵抗の少ないパスはセキュアか?
- エラーメッセージはセキュアな使用法へ誘導するか?
-
混乱した開発者:APIを誤解
- パラメータを型エラーなしで入れ替え可能か?
- 間違った鍵/アルゴリズム/モードを誤って使用できるか?
- 失敗モードは明白か、それとも無言か?
フェーズ 4: 検証
各特定された sharp edge について:
- 誤用を再現:フットガンを示す最小限のコードを記述
- 利用可能性を確認:誤用は実際の脆弱性を作成するか?
- ドキュメントを確認:危険性は記述されているか?(ドキュメントは悪い設計を正当化しませんが、重大度に影響)
- 軽減策をテスト:合理的な努力でAPIを安全に使用できるか?
見つけた内容が疑わしい場合は、フェーズ 2 に戻ってさらにエッジケースを調査してください。
重大度分類
| 重大度 | 基準 | 例 |
|---|---|---|
| 重大 | デフォルトまたは明白な使用法がセキュアでない | verify: false デフォルト;空のパスワードが許可 |
| 高 | 簡単な設定誤りがセキュリティを破壊 | アルゴリズムパラメータが「none」を受け入れる |
| 中 | 珍しいが可能な設定誤り | 負のタイムアウトが予期しない意味を持つ |
| 低 | 意図的な誤用が必要 | 不明瞭なパラメータの組み合わせ |
リファレンス
カテゴリ別:
- 暗号化API:
references/crypto-apis.mdを参照 - 設定パターン:
references/config-patterns.mdを参照 - 認証・セッション:
references/auth-patterns.mdを参照 - 実世界のケーススタディ:
references/case-studies.mdを参照(OpenSSL、GMPなど)
言語別(暗号化固有ではない一般的なフットガン):
| 言語 | ガイド |
|---|---|
| C/C++ | references/lang-c.md |
| Go | references/lang-go.md |
| Rust | references/lang-rust.md |
| Swift | references/lang-swift.md |
| Java | references/lang-java.md |
| Kotlin | references/lang-kotlin.md |
| C# | references/lang-csharp.md |
| PHP | references/lang-php.md |
| JavaScript/TypeScript | references/lang-javascript.md |
| Python | references/lang-python.md |
| Ruby | references/lang-ruby.md |
references/language-specific.md も参照して、統合されたクイックリファレンスを確認してください。
品質チェックリスト
分析を終了する前に:
- すべてのゼロ/空/null エッジケースを調査
- デフォルトがセキュアであることを確認
- アルゴリズム・モード選択のフットガンをチェック
- セキュリティコンセプト間の型の混同をテスト
- 3つの敵対者タイプすべてを検討
- エラーパスがセキュリティをバイパスしないことを確認
- 設定検証をチェック
- コンストラクタパラメータが検証されている(デフォルトされていない)か確認 -
config-patterns.mdを参照
ライセンス: CC-BY-SA-4.0(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- trailofbits
- リポジトリ
- trailofbits/skills
- ライセンス
- CC-BY-SA-4.0
- 最終更新
- 不明
Source: https://github.com/trailofbits/skills / ライセンス: CC-BY-SA-4.0
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。