trailmark

trailmark

熱門

建立並查詢多語言原始碼與二進位碼的程式碼圖譜,用於安全分析。包含預分析階段:爆炸半徑、污點傳播、權限邊界、進入點列舉、代理/未解析呼叫追蹤、型別/參考查詢、結構遍歷、圖譜差異比對、稽核擴充、透過 `.trailmark/links.toml` 宣告的跨語言/FFI/外部連結,以及 SQL schema 圖譜。適用於分析呼叫路徑、繪製攻擊面、找出複雜度熱點、列舉進入點、追蹤污點傳播、衡量爆炸半徑、匯入 SARIF/weAudit/二進位碼發現、跨語言或 RPC 邊界連結原始碼圖譜,或建立用於稽核優先排序的程式碼圖譜。使用前請先檢查 Trailmark API 的版本相容性;若目標語言未知或為多語言專案,建議使用 `trailmark.parse.detect_languages()` 或 `--language auto`。

6336星標
545分支
更新於 2026/7/30
SKILL.md
readonlyread-only
name
trailmark
description

建立並查詢多語言原始碼與二進位碼的程式碼圖譜,用於安全分析。包含預分析階段:爆炸半徑、污點傳播、權限邊界、進入點列舉、代理/未解析呼叫追蹤、型別/參考查詢、結構遍歷、圖譜差異比對、稽核擴充、透過 `.trailmark/links.toml` 宣告的跨語言/FFI/外部連結,以及 SQL schema 圖譜。適用於分析呼叫路徑、繪製攻擊面、找出複雜度熱點、列舉進入點、追蹤污點傳播、衡量爆炸半徑、匯入 SARIF/weAudit/二進位碼發現、跨語言或 RPC 邊界連結原始碼圖譜,或建立用於稽核優先排序的程式碼圖譜。使用前請先檢查 Trailmark API 的版本相容性;若目標語言未知或為多語言專案,建議使用 `trailmark.parse.detect_languages()` 或 `--language auto`。

Trailmark

將原始碼解析為有向圖,包含函式、類別、呼叫與語意中繼資料,用於安全分析。

使用時機

  • 繪製從使用者輸入到敏感函式的呼叫路徑
  • 找出複雜度熱點以進行稽核優先排序
  • 識別攻擊面與進入點
  • 理解不熟悉程式碼庫中的呼叫關係
  • 跨多語言專案進行安全審查或稽核準備
  • 為程式碼單元加入 LLM 推論的註解(假設、前置條件)
  • 匯入外部二進位分析圖譜,連結原始碼與二進位視圖
  • 查詢傳遞切片、進入點路徑、子圖邊緣或型別參考
  • 為單一可疑函式或候選發現產生圖譜證據
  • 在突變測試(genotoxic 技能)或繪圖前進行預分析

不應使用的情況

  • 單一檔案腳本,呼叫圖譜無附加價值(直接讀取檔案)
  • 非從程式碼衍生的架構圖(使用 diagramming-code 技能或手繪)
  • 突變測試分類(使用 genotoxic 技能,其內部會呼叫 trailmark)
  • 執行期行為分析(trailmark 是靜態分析,非動態)

應拒絕的合理化藉口

合理化藉口 錯誤原因 應採取行動
「我手動讀原始碼就好」 手動閱讀會遺漏呼叫路徑、爆炸半徑與污點資料 安裝 trailmark 並使用 API
「快速查詢不需要預分析」 爆炸半徑、污點與權限資料僅在 preanalysis() 後可用 在交給其他技能前,務必執行 engine.preanalysis()
「圖譜太大,我取樣就好」 取樣會遺漏跨模組的攻擊路徑 建立完整圖譜,使用子圖查詢聚焦
「不確定的邊緣不重要」 動態分派正是型別混淆錯誤藏身之處 在安全聲明中考慮 uncertain 邊緣
「單語言分析就夠了」 多語言儲存庫在 FFI 邊界常有錯誤聚集 對每個元件使用正確的 --language 旗標
「複雜度熱點是唯一值得檢查的」 低複雜度但位於受污染路徑上的函式是高價值目標 結合複雜度、污點與爆炸半徑資料
「文件提到某個版本限制的方法,所以到處都能用」 許多環境仍安裝 Trailmark 0.2.x 使用前檢查安裝版本或探測功能可用性

安裝

強制要求: 如果 uv run trailmark 失敗(找不到命令、匯入錯誤、ModuleNotFoundError),請先安裝 trailmark:

uv pip install trailmark

不要退而求其次使用「手動驗證」、「手動分析」或手動閱讀原始碼來取代執行 trailmark。此工具必須安裝並以程式方式使用。若安裝失敗,請向使用者回報錯誤,而非默默切換到手動程式碼閱讀。

版本閘道

Trailmark 0.4.0 擴展了圖譜模型與查詢表面,0.5.0 新增了 SQL 解析器、儲存庫連結設定與更豐富的進入點中繼資料。在使用標記為 v0.4+v0.5+ 的功能前,請檢查安裝版本:

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

以數值方式(非詞彙方式)比較回報的版本。0.4.0 或更新版本表示完整的 v0.4 表面可用。版本命令本身在 0.2.2 加入,因此失敗表示安裝的是 0.2.2 之前的版本或完全未安裝 trailmark — 請用 trailmark analyze --help 區分。以程式方式使用時,請用 hasattr() 探測並提供備援方案,而非假設 v0.4 專屬方法存在:

if hasattr(engine, "subgraph_edges"):
    edges = engine.subgraph_edges("tainted")
else:
    # v0.2 備援:過濾 engine.to_json() 中兩端點皆在 engine.subgraph("tainted") 的邊緣
    edges = []

v0.2 安全基準: CLI analyzediffentrypointsaugment--language autoQueryEngine.from_directory()callers_of()callees_of()paths_between()ancestors_of()reachable_from()entrypoint_paths_to()complexity_hotspots()attack_surface()summary()to_json()preanalysis()annotate()annotations_of()nodes_with_annotation()clear_annotations()findings()subgraph()subgraph_names()diff_against()augment_sarif()augment_weaudit()

0.2.2 新增: CLI --version 旗標與 version 子命令。

0.3.x 新增: trailmark.parse 模組,包含模組層級的 detect_languages()supported_languages()detect_languages() 本身可透過 from trailmark.query.api import detect_languages 在 v0.2 安全使用(0.3+ 中保留為棄用別名);supported_languages() 在 0.2.x 中無對應功能。

v0.4+ 功能: 原生 diagram 子命令;擴展的解析器覆蓋範圍;未解析呼叫的代理節點;節點來源;透過 augment_binary() 的二進位圖譜擴充;connect_subgraphs()subgraph_edges()generic_parameters();與 type_references()

v0.5+ 功能: sql 解析器(PostgreSQL 導向的 schema、資料表、檢視、函式、程序、相依性);節點種類 schematableviewprocedure.trailmark/links.toml 儲存庫連結設定(見下方儲存庫連結),包含 proxy.external:<symbol> 節點用於宣告的外部端點;儲存庫連結、未解析呼叫代理與 type_uses 邊緣現在會在單語言目錄解析時具體化(0.4 僅在多語言解析時發出);Solidity 進入點從解析器中繼資料偵測(排除介面;solidity_visibilitysolidity_mutabilitysolidity_overridesolidity_container_kindsolidity_overridden_by 節點屬性);attack_surface() 條目在節點有屬性時攜帶 attributes 鍵;TypeScript 解析以 new ConcreteClass() 賦值的接收者;C# 檔案範圍命名空間。

v0.5.0 未新增任何 QueryEngine 方法,因此 hasattr(engine, ...) 無法偵測。請根據回報的版本來閘控 v0.5 功能,或以結構方式探測:

from trailmark.models.nodes import NodeKind

has_v05 = "SCHEMA" in NodeKind.__members__  # sql 種類為 0.5+

快速開始

# 自動偵測並合併目錄樹下所有支援的語言
uv run trailmark analyze --language auto --summary {targetDir}

# 明確指定語言(單一語言或以逗號分隔的清單)
uv run trailmark analyze --language rust {targetDir}
uv run trailmark analyze --language python,rust {targetDir}

# 複雜度熱點
uv run trailmark analyze --language auto --complexity 10 {targetDir}

# 進入點清單與結構差異(v0.2 安全)
uv run trailmark entrypoints --language auto {targetDir}
uv run trailmark diff --repo {repoDir} main HEAD --json

# 版本回報(0.2.2+)
uv run trailmark --version

# v0.4+:原生 diagram 命令
uv run trailmark diagram -t {targetDir} -T call-graph -f main --depth 2

程式化 API

# trailmark.parse 是 0.3+ 模組;在 0.2.x 上請從 trailmark.query.api 匯入 detect_languages
# (supported_languages 在 0.2.x 中無對應功能)
from trailmark.parse import detect_languages, supported_languages
from trailmark.query.api import QueryEngine

# 詢問已安裝的 Trailmark 建置支援哪些語言
supported_languages()
detect_languages("{targetDir}")

# 對未知或多語言目錄樹建議使用 auto;必要時使用明確清單
engine = QueryEngine.from_directory("{targetDir}", language="auto")
engine = QueryEngine.from_directory("{targetDir}", language="python,rust")

engine.callers_of("function_name")
engine.callees_of("function_name")
engine.paths_between("entry_func", "db_query")
engine.complexity_hotspots(threshold=10)
engine.attack_surface()
engine.summary()
engine.to_json()

# 傳遞切片與進入點路徑查詢(v0.2 安全)
engine.ancestors_of("sensitive_sink")
engine.reachable_from("entry_func")
engine.entrypoint_paths_to("sensitive_sink")

# v0.4+:連接具名子圖
if hasattr(engine, "connect_subgraphs"):
    engine.connect_subgraphs("tainted", "privilege_boundary")

# 執行預分析(爆炸半徑、進入點、權限邊界、污點傳播)
result = engine.preanalysis()

# 查詢預分析建立的子圖
engine.subgraph_names()
engine.subgraph("tainted")
engine.subgraph("high_blast_radius")
engine.subgraph("privilege_boundary")
engine.subgraph("entrypoint_reachable")
if hasattr(engine, "subgraph_edges"):
    engine.subgraph_edges("tainted")

# 加入 LLM 推論的註解
from trailmark.models import AnnotationKind

engine.annotate("function_name", AnnotationKind.ASSUMPTION,
                "input is URL-encoded", source="llm")

# 查詢註解(包含預分析結果)
engine.annotations_of("function_name")
engine.annotations_of("function_name",
                       kind=AnnotationKind.BLAST_RADIUS)
engine.annotations_of("function_name",
                       kind=AnnotationKind.TAINT_PROPAGATION)
engine.nodes_with_annotation(AnnotationKind.FINDING)
engine.clear_annotations("function_name", kind=AnnotationKind.ASSUMPTION)

# v0.4+:泛型/型別參考與二進位擴充 API
if hasattr(engine, "generic_parameters"):
    engine.generic_parameters("GenericTypeOrFunction")
if hasattr(engine, "type_references"):
    engine.type_references("function_name")
if hasattr(engine, "augment_binary"):
    engine.augment_binary("binary_graph.json")

預分析階段

在交給 genotoxic 或 diagramming-code 技能前,務必執行 engine.preanalysis() 預分析透過四個階段豐富圖譜:

  1. 爆炸半徑估計 — 計算每個函式的下游與上游節點數量,識別關鍵的高複雜度後代
  2. 進入點列舉 — 依信任層級對應進入點,計算可達節點集合
  3. 權限邊界偵測 — 找出信任層級變化的呼叫邊緣(不受信任 -> 受信任)
  4. 污點傳播 — 標記所有從不受信任進入點可達的節點

結果以註解與具名子圖的形式儲存在圖譜上。

詳細文件請參閱 references/preanalysis-passes.md

語言選擇

請勿在下游工作流程中硬編碼過時的語言表格。請詢問已安裝的 Trailmark 建置支援哪些語言:

from trailmark.parse import detect_languages, supported_languages

supported_languages()
detect_languages("{targetDir}")

CLI 模式:

# 自動偵測並合併
uv run trailmark analyze --language auto {targetDir}

# 針對已知的多語言目標使用明確清單
uv run trailmark analyze --language python,rust {targetDir}

截至 Trailmark 0.5.0,解析器名稱包含:pythonjavascripttypescriptphprubyccppc_sharpjavagorustsoliditycairocircomhaskellerlangmasmswiftobjckotlindartmovetactfuncswayregoprotothriftgraphqlsql(0.5.0 新增;PostgreSQL 導向,.sql 檔案)。請將此清單視為文件而非事實來源;在依賴某個解析器前,請呼叫已安裝建置的 supported_languages()

儲存庫連結(v0.5+)

解析器無法看見跨語言呼叫(FFI、RPC、IPC、合約呼叫)或進入外部系統的邊緣。請在分析根目錄的 .trailmark/links.toml 中宣告它們,Trailmark 會在每次解析時具體化這些邊緣 — 這是一個穩定的公開設定介面:

[[link]]
source = "backend:submit"
target = "contract:Verifier.verify"
kind = "calls"                 # 任何 EdgeKind;預設為 calls
confidence = "certain"         # certain | inferred | uncertain;預設為 inferred
description = "JSON-RPC eth_call"

[[link]]
source = "backend:notify"
target = "payments-webhook"
target_external = true         # 必要,因為 target 未解析

端點參考可以是精確的節點 ID 或唯一名稱/後綴。驗證失敗時會關閉:模糊的參考、未知的內部端點、無效的列舉值與格式錯誤的 TOML 會引發 ValueError,而非默默弱化圖譜。source_external = true / target_external = true 允許未解析的端點,透過建立 proxy.external:<symbol> 節點來實現。設定的邊緣會攜帶 configured_by = .trailmark/links.toml 屬性,以便與解析器衍生的邊緣區分。

當稽核跨越合理化表格警告的 FFI/RPC 邊界時使用此功能:先宣告邊界邊緣,然後路徑與污點查詢就能像其他呼叫邊緣一樣跨越它們。

圖譜模型

節點種類: functionmethodclassmodulestructinterfacetraitenumnamespacecontractlibrarytemplatev0.4+ 也將未解析的參考具體化為 proxy 節點;v0.5+ 為 SQL 圖譜新增 schematableviewprocedure

節點來源: v0.4+ 節點可能攜帶來源 sourceproxybinarysynthetic。v0.2 匯出可能省略來源。

邊緣種類: callsinheritsimplementscontainsimportsv0.4+ 新增 resolves_totype_usesspecializescorresponds_to

邊緣信心度: certain(直接呼叫、self.method())、inferred(對非 self 物件的屬性存取)、uncertain(動態分派)

每個程式碼單元

  • 帶有型別的參數、回傳型別、例外型別
  • 循環複雜度與分支中繼資料
  • 文件字串
  • 註解:assumptionpreconditionpostconditioninvariantblast_radiusprivilege_boundarytaint_propagationfindingaudit_note(最後兩個由 augment_sarif / augment_weaudit 設定)

每個邊緣

  • 來源/目標節點 ID、邊緣種類、信心度層級

專案層級

  • 相依性(匯入的套件)
  • 帶有信任層級與資產價值的進入點
  • 具名子圖(由預分析填入)

關鍵概念

宣告的合約 vs. 有效輸入域: Trailmark 區分函式宣告接受的內容與透過呼叫路徑實際可達的內容。不匹配處正是漏洞藏身之處:

  • 拓寬:未受限制的資料到達假設已驗證的函式
  • 巧合安全:無驗證,但今日僅有安全的呼叫者

邊緣信心度: 動態分派會產生 uncertain 邊緣。在做出安全聲明時請考慮信心度。

代理節點(v0.4+): 未解析的呼叫會保留為節點,例如 proxy.unresolved:<symbol>。請勿將其視為原始碼函式;使用它們來識別解析缺口、動態分派、外部 API 或二進位連結候選。v0.5+ 也會為在 .trailmark/links.toml 中宣告為外部的端點發出 proxy.external:<symbol> 節點。

可達性不等於污點: entrypoint_paths_to() 與污點子圖回答不同的問題。路徑查詢回報呼叫圖譜的可達性;預分析污點將從不受信任進入點可達的節點標記為粗略訊號。Trailmark 不執行程序間污點分析 — 請勿將任一者呈現為攻擊者控制的資料到達接收器的證據。

二進位擴充(v0.4+): engine.augment_binary() 匯入外部二進位分析圖譜 JSON 檔案。Trailmark 在可能時將其連接到原始碼節點;它本身不會反組譯二進位檔。

子圖: 由預分析產生的具名節點 ID 集合。使用 engine.subgraph("name") 查詢。在 engine.preanalysis() 後可用。

查詢模式

常見的安全分析模式請參閱 references/query-patterns.md

預分析階段文件請參閱 references/preanalysis-passes.md

當使用者有一個具體的候選發現、SARIF 結果、weAudit 註解、可疑函式或報告摘錄,且需要可交接的可達性與爆炸半徑證據套件時,請使用 trailmark-finding-triage

當已知一個種子問題,且使用者需要圖譜衍生的變體候選用於 variant-analysis、Semgrep、CodeQL 或手動審查時,請使用 trailmark-variant-neighborhood