mcpField
T
trailmark-structural

trailmark-structural

github.com/trailofbitsセキュリティ7.9k4.0k 回インストール今日更新
リポジトリ

trailmark-structural について

trailmark-structuralは、Trailmarkでコードをセキュリティ面から構造分析するスキルです。4つの事前分析をすべて実行し、Trailmarkのバージョンごとの機能差にも対応します。

主な機能

  1. 01Trailmarkコードグラフの構築
  2. 024つの事前分析の実行
  3. 03ホットスポットと汚染データの抽出
  4. 04影響範囲と特権境界の確認
  5. 05サブグラフとプロキシノードの出力

活用シーン

  1. 01セキュリティ監査向けコード箇所の優先付け
  2. 02対象範囲の構造データ分析
  3. 03未解決呼び出しとサブグラフ関係の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trailofbits/skills --skill trailmark-structural

インストール後、Claude Code で/trailmark-structuralを入力して読み込まれたか確認します。

同梱ファイルagents/openai.yamlassets/trail-of-bits-mark.svg

詳細

Trailmark の構造解析

Trailmark グラフを構築し、engine.preanalysis()を実行して、4 つすべての事前解析パスを計算します。コアワークフローは v0.2 に対応しています。v0.4 固有の詳細は、メソッドが利用可能か確認した後にのみ含めます。また、新しいビルドでは同じ出力が拡張されます(0.5.0+ では攻撃対象領域のエントリーにattributesキーが追加され、.trailmark/links.tomlからproxy.external:*ノードが追加されます)。ワークフローに変更はありません。

使用する場合

  • Vivisect Phase 1 で完全な構造データ(ホットスポット、テイント、影響範囲、権限境界)が必要な場合
  • 特定のターゲット範囲について、詳細な事前解析パスが必要な場合
  • 監査の優先順位付けに使う複雑度データとテイントデータを生成する場合
  • Trailmark 0.4.0+ がインストールされている環境で、プロキシ/未解決の呼び出し数、サブグラフのエッジ、型参照の概要を調べる場合

使用しない場合

  • 簡単な概要だけが必要な場合(代わりにtrailmark-summaryを使用してください)
  • アドホックなコードグラフクエリを実行する場合(メインのtrailmarkスキルを直接使用してください)
  • ターゲットが小さな単一ファイルで、構造解析に価値がない場合

退けるべき合理化

合理化それが誤りである理由必須の対応
「概要分析で十分です」概要ではテイント、影響範囲、権限境界のデータが省かれます詳細なデータが必要な場合は、完全な構造解析を実行します
「1 つのパスで十分です」各パスは相互に参照するため、影響範囲を調べずにテイントだけを見ると重要なノードを見落とします4 つすべてのパスを実行します
「ツールがインストールされていないので、手作業で分析します」手作業の分析では、ツールが検出できるものを見落とします「trailmark is not installed」と報告して終了します
「パスの出力が空なら、パスの実行に失敗しています」コードベースによっては、一部のパスでデータが生成されないことがあります(例:権限境界がない場合)出力全体をそのまま返します
「v0.4 のフィールドは常にあります」ユーザーが Trailmark 0.2.x をまだインストールしている場合がありますv0.4 固有のメソッドを呼び出す前にhasattr()で確認します

使用方法

ターゲットディレクトリはargsパラメーターで渡します。

実行

ステップ 1:trailmark が利用可能か確認します。

trailmark analyze --help 2>/dev/null || \
  uv run trailmark analyze --help 2>/dev/null

どちらのコマンドも動作しない場合は、「trailmark is not installed」と報告して終了します。pip install、uv pip install、git clone、またはインストールコマンドを実行してはいけません。trailmark はユーザー自身がインストールする必要があります。

必要に応じて、バージョンを記録します。

trailmark --version 2>/dev/null || uv run trailmark --version 2>/dev/null || true

このコマンドが見つからなくても失敗とせず、以下の API 機能チェックを使用します。

ステップ 2:Trailmark の解析 API で言語を検出します。

python3 - "{args}" <<'PY'
import json
import sys

try:
    from trailmark.parse import detect_languages  # canonical location since 0.3.x
except ModuleNotFoundError:
    # v0.2.x predates trailmark.parse; the same function lives in query.api
    from trailmark.query.api import detect_languages

print(json.dumps(detect_languages(sys.argv[1])))
PY

インポートに失敗した場合は、同じスニペットをuv run --with trailmark python - "{args}"で再実行します。結果が[]の場合は、「Trailmark found no supported languages under target」と報告して終了します。

ステップ 3:QueryEngineを使用して完全な構造解析を実行します。

このスニペットをpython3で実行します。インポートに失敗した場合は、同じスニペットをuv run --with trailmark python - "{args}"で再実行します。

python3 - "{args}" <<'PY'
import json
import sys

try:
    from trailmark.parse import detect_languages  # canonical location since 0.3.x
except ModuleNotFoundError:
    # v0.2.x predates trailmark.parse; the same function lives in query.api
    from trailmark.query.api import detect_languages

from trailmark.query.api import QueryEngine

target = sys.argv[1]
languages = detect_languages(target)
engine = QueryEngine.from_directory(target, language="auto")
preanalysis = engine.preanalysis()

def summarize_subgraph(name: str, limit: int = 25) -> dict[str, object]:
    nodes = engine.subgraph(name)
    summary = {
        "count": len(nodes),
        "sample_ids": [node["id"] for node in nodes[:limit]],
    }
    if hasattr(engine, "subgraph_edges"):
        summary["edge_count"] = len(engine.subgraph_edges(name))
    return summary

graph = json.loads(engine.to_json())
nodes = graph.get("nodes", {})
proxy_nodes = [
    node_id for node_id, node in nodes.items()
    if node.get("kind") == "proxy" or node.get("origin") == "proxy"
]

payload = {
    "languages": languages,
    "summary": engine.summary(),
    "preanalysis": preanalysis,
    "attack_surface": engine.attack_surface()[:25],
    "hotspots": engine.complexity_hotspots(10)[:25],
    "proxy_nodes": proxy_nodes[:25],
    "subgraphs": {
        name: summarize_subgraph(name)
        for name in engine.subgraph_names()
    },
}

if hasattr(engine, "type_references"):
    payload["type_reference_samples"] = {
        node_id: engine.type_references(node_id)[:10]
        for node_id in list(nodes)[:25]
    }

print(json.dumps(payload, indent=2))
PY

ステップ 4:出力を確認します。

出力には以下が含まれている必要があります。

  • languages
  • summary
  • preanalysis
  • hotspots(空の場合もあります)
  • proxy_nodes(v0.2.x、または未解決の呼び出しがない場合は空です。0.5.0+ では、.trailmark/links.tomlで宣言されたproxy.external:*エントリーが含まれる場合があります)
  • 件数とサンプル ID を含むsubgraphs

Trailmark 0.5.0+ では、attack_surfaceのエントリーにattributesオブジェクト(例:solidity_visibility、solidity_overridden_by)が含まれる場合があります。変更せずにそのまま渡してください。後続のコンシューマーは、エントリーポイントの優先順位付けにこれを使用します。

コードベースによっては、一部のサブグラフのノード数がゼロになることがあります(これは正常です)。JSON ペイロード全体をそのまま返してください。

コメント