
trailmark
熱門建立並查詢多語言原始碼與二進位碼的程式碼圖譜,用於安全分析。包含預分析階段:爆炸半徑、污點傳播、權限邊界、進入點列舉、代理/未解析呼叫追蹤、型別/參考查詢、結構遍歷、圖譜差異比對、稽核擴充、透過 `.trailmark/links.toml` 宣告的跨語言/FFI/外部連結,以及 SQL schema 圖譜。適用於分析呼叫路徑、繪製攻擊面、找出複雜度熱點、列舉進入點、追蹤污點傳播、衡量爆炸半徑、匯入 SARIF/weAudit/二進位碼發現、跨語言或 RPC 邊界連結原始碼圖譜,或建立用於稽核優先排序的程式碼圖譜。使用前請先檢查 Trailmark API 的版本相容性;若目標語言未知或為多語言專案,建議使用 `trailmark.parse.detect_languages()` 或 `--language auto`。
建立並查詢多語言原始碼與二進位碼的程式碼圖譜,用於安全分析。包含預分析階段:爆炸半徑、污點傳播、權限邊界、進入點列舉、代理/未解析呼叫追蹤、型別/參考查詢、結構遍歷、圖譜差異比對、稽核擴充、透過 `.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 analyze、diff、entrypoints、augment 與 --language auto;QueryEngine.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、資料表、檢視、函式、程序、相依性);節點種類 schema、table、view、procedure;.trailmark/links.toml 儲存庫連結設定(見下方儲存庫連結),包含 proxy.external:<symbol> 節點用於宣告的外部端點;儲存庫連結、未解析呼叫代理與 type_uses 邊緣現在會在單語言目錄解析時具體化(0.4 僅在多語言解析時發出);Solidity 進入點從解析器中繼資料偵測(排除介面;solidity_visibility、solidity_mutability、solidity_override、solidity_container_kind 與 solidity_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()。 預分析透過四個階段豐富圖譜:
- 爆炸半徑估計 — 計算每個函式的下游與上游節點數量,識別關鍵的高複雜度後代
- 進入點列舉 — 依信任層級對應進入點,計算可達節點集合
- 權限邊界偵測 — 找出信任層級變化的呼叫邊緣(不受信任 -> 受信任)
- 污點傳播 — 標記所有從不受信任進入點可達的節點
結果以註解與具名子圖的形式儲存在圖譜上。
詳細文件請參閱 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,解析器名稱包含:python、javascript、typescript、php、ruby、c、cpp、c_sharp、java、go、rust、solidity、cairo、circom、haskell、erlang、masm、swift、objc、kotlin、dart、move、tact、func、sway、rego、proto、thrift、graphql 與 sql(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 邊界時使用此功能:先宣告邊界邊緣,然後路徑與污點查詢就能像其他呼叫邊緣一樣跨越它們。
圖譜模型
節點種類: function、method、class、module、struct、interface、trait、enum、namespace、contract、library、template;v0.4+ 也將未解析的參考具體化為 proxy 節點;v0.5+ 為 SQL 圖譜新增 schema、table、view 與 procedure。
節點來源: v0.4+ 節點可能攜帶來源 source、proxy、binary 或 synthetic。v0.2 匯出可能省略來源。
邊緣種類: calls、inherits、implements、contains、imports;v0.4+ 新增 resolves_to、type_uses、specializes 與 corresponds_to。
邊緣信心度: certain(直接呼叫、self.method())、inferred(對非 self 物件的屬性存取)、uncertain(動態分派)
每個程式碼單元
- 帶有型別的參數、回傳型別、例外型別
- 循環複雜度與分支中繼資料
- 文件字串
- 註解:
assumption、precondition、postcondition、invariant、blast_radius、privilege_boundary、taint_propagation、finding、audit_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。





