Imported from cuhawk/tlxkull (
.claude/skills/chain-triage/SKILL.md). Install upstream withnpx skills add cuhawk/tlxkull --skill chain-triage. Copyright stays with the author.
chain-triage
Purpose
Decide what's worth deep-auditing. The static analyzer can produce hundreds of chains; only a few are worth Opus's time. Triage compresses the queue.
Inputs
targets/<name>/index/(fromjs-index).
Steps
- Call
js_get_chains(target_folder="targets/<name>/sources/", max_chains=200). - For each returned chain, compute a composite score:
Default weights live inscore = w_sev * sink_severity(sink_kind) + w_src * source_severity(source_kind) - w_path * log(1 + path_length) + w_fw * framework_match_bonus(chain, frameworks) - w_sanit * sanitizer_penalty(chain.path_has_sanitizer)bin/triage_weights.json; user can tune. - Write tiered output:
chains/hot.jsonl— top N where N = min(--max-hot, ceil(count*0.1)). Goes tocc-taint-adversarial/opus-deep-audit.chains/warm.jsonl— next M where M = min(--max-warm, remainder). Default --max-warm=80. Feedsautoresearch-loopand reaudit when hot returns no TP.chains/cold.jsonl— everything past hot+warm. Long-tail; rarely audited unless explicitly requested.chains/all.jsonl— every chain (legacy; consumers gradually migrate to tier files). Optional--hot-score-floor X: chains scoring below X are demoted from hot → warm even if the cap isn't full.
- Compute a quick distribution (
{sink_kind: count},{source_kind: count}) plus score percentiles (p99/p95/p90/p50) for the result block.
Sink severity defaults (high → low)
- DOM XSS sinks (
innerHTML,outerHTML,dangerouslySetInnerHTML,document.write,eval,setTimeout(string),Function(string)) - Open redirect sinks (
window.locationfamily,<a href>set) - Prototype pollution gadgets
- PostMessage sinks without origin checks
- URL parsing on user-controlled input feeding fetch()
Source severity defaults
window.name,document.referrer, URL fragment/querypostMessageevent data- Network responses where origin isn't strictly trusted
- Cookie / localStorage values
Outputs
targets/<name>/chains/all.jsonltargets/<name>/chains/hot.jsonltargets/<name>/chains/warm.jsonltargets/<name>/chains/cold.jsonltargets/<name>/chains/triage.json(includestiers+score_percentiles)- updated
status.json.phases.triage
Failure modes
- Empty chains list → most often means
js-indexdidn't recognize any sources. Re-check framework detection; consider loweringmin_chain_scorethreshold in TLX config.
Result block
"phases": { "triage": { "status": "done", "ts": "<iso>",
"total": N, "hot": M, "sink_dist": {...}, "source_dist": {...} } }