Document
Contributing to OAK
Thanks for considering a contribution. OAK grows through pull requests from the community of on-chain investigators, detection engineers, security researchers, and protocol teams who work directly with these adversarial patterns. This document describes how to submit and what to expect.
Scope of contributions
We accept PRs in any of the following categories:
| Category | What it looks like |
|---|---|
| New Technique | A new file under techniques/ with a proposed OAK-Tn.NNN identifier. |
| Tactic refinement | Edits to an existing tactics/Tn-*.md improving description, scope, or relationships. |
| Technique improvement | Detection-signal additions, mitigation additions, new real-world example references, citation additions. |
| New Mitigation | A new file under mitigations/ with a proposed OAK-MNN identifier. Mitigations are reusable defences mapping many-to-many to Techniques. |
| New Software | A new file under software/ with a proposed OAK-SNN identifier. Tools, kits, and malware families used by Threat Actors. |
| New Threat Actor / Group | A new file under actors/ with a proposed OAK-Gnn identifier. Tracked operators and operator-cohort families with explicit attribution-strength language. |
| New Data Source | A new file under data-sources/ with a proposed OAK-DS-NN identifier. Telemetry-input identifiers used across the framework. |
| Reference-implementation mapping | A new row under "Reference implementations" pointing to your tool's coverage of an existing Technique or Mitigation. |
| Real-world example | A new file under examples/ documenting a publicly known incident, mapped to one or more Techniques. |
| Citation | A new entry in citations.bib (with stable DOI / arXiv ID where possible). |
| Tooling | Improvements to tools/ validators, exporters, or coverage-map generators. |
| Relationship-graph edge | A new entry exposed via tools/oak.json (mitigates / uses / detects / targets edge between existing axis entries). |
The test every contribution must pass
Could a defender act on this in five minutes? From an incident or Technique page, a reader must get:
- what happened and at which step;
- the control that would have stopped it, and how to check their own system for it;
- the addresses to watch.
The rules below (root-cause evidence, end-to-end timeline, full addresses, fund flow, mitigations stating what, how and why) exist to make that true and checkable. A contribution that adds information but no usable payload is not done.
Root-cause evidence on worked examples
Every worked example dated 2026-10 or later must carry a ## Root-cause evidence section saying which source establishes the mechanism behind its primary Technique, and how settled that is. It is exported to oak.json as root_cause_evidence and validated by tools/check_root_cause.py (part of npm run check).
## Root-cause evidence
- **Technique:** OAK-T10.001
- **Source:** <https://...>; <https://...>
- **Source type:** operator | government | security-firm | independent-researcher | news
- **Confidence:** confirmed | corroborated | reported | disputed
- **Evidence:** what the source says that establishes the mechanism.
confirmed needs the operator's own post-mortem or a government source that states the mechanism. corroborated needs two independent sources. One security firm's alert relayed by several outlets is reported, not corroborated. Use disputed when credible sources conflict, and say how. A same-day third-party analysis is never confirmed: OAK's KelpDAO and THORChain misclassifications both came from treating one as settled.
Timeline, key addresses and fund flow on worked examples
Every single-incident example (file name YYYY-MM-…) carries a ## Timeline (UTC) table that runs end to end:
- Entry or flaw — how the attacker got in, or what was broken and since when.
- Preparation — funding (for example Tornado withdrawals), deployments, rehearsals, approvals left open.
- Execution — the exploit transactions.
- Where the funds went — swaps, bridges, mixers, CEX deposits, the holding address. If the funds did not leave, say so: frozen, returned, or not moved as of a given date.
- Response — pause, freeze, statement, fix, refunds.
## Timeline (UTC)
| When | What happened | OAK |
|---|---|---|
| 2026-10-29 20:20:59 | [`0xad99…full hash`](https://etherscan.io/tx/0x…) carries 50 EIP-7702 authorizations signed by Binance 14 | **T13.004** |
| 2026-10-29 21:01:35 | Tether freezes the receiver | response |
Key addresses:
- Attacker EOA — [`0x…full address`](https://etherscan.io/address/0x…)
Rules (tools/check_timeline.py, part of npm run check):
- Each row's OAK cell is a Technique declared in OAK Techniques observed:, or
response, or—. The root-cause Technique appears on the step where that mechanism happens. - Addresses and transaction hashes are written in full and linked to the chain's explorer, never shortened. They are public, and they are how a reader checks the work and links one incident to another. If a source publishes only a shortened form, keep it as given and write "(full address not published)".
- List every address the sources give, by role, under Key addresses: attacker EOA, attack contract, vulnerable or victim contract, receiving and holding wallets, mixer or bridge deposits.
- A stage that is not public stays in the table as undisclosed. Do not leave it out, and do not fill it in.
- Say what the source verified against what it relayed (for example "verified on-chain by X; other chains from Y"). When the funds are still moving, add a dated Where the funds are snapshot and a What is not known yet list.
examples/2026-10-binance-devops-laptop-service-container-hot-wallet-drain.mdis the reference.
The rules are hard failures from 2026-09 on, and for any example with no timeline at all. Older tables that break a rule are reported as legacy until the backfill in ROADMAP.md clears them.
Fund flow on worked examples
The timeline says what happened. The ## Fund flow block makes the money machine-readable: the site draws it as a graph with a table of full, linked addresses and transactions, oak.json exports it as fund_flow, and tools/build_address_index.py joins it across incidents. Validated by tools/check_flow.py (in npm run check). It is required for examples dated 2026-11 or later. Earlier examples get it as they are traced.
## Fund flow
```oak-flow
as_of: 2026-10-30T11:40Z
nodes:
- {id: rcv, chain: ethereum, address: 0x…40 hex, role: attacker-receiver, label: "Receiver"}
- {id: tc, chain: ethereum, role: mixer, label: "Tornado Cash"}
edges:
- {from: rcv, to: tc, asset: ETH, amount: 100, tx: 0x…64 hex, time: 2026-10-30T05:14:35Z, technique: T7.001, verified: oak}
- {from: rcv, to: tc, asset: ETH, amount: 50, verified: source, source: citekey}
```
- Roles:
attacker-eoa,attack-contract,attacker-receiver,attacker-holding,victim,victim-hot-wallet,vulnerable-contract,mixer,bridge,cex-deposit,dex,lending,issuer-freeze,returned,burn,intermediary,unknown. verified: oakmeans OAK checked the hop on-chain itself, andtxis required.verified: sourcerelays a cited source, andsourcemust be a citekey from Public references. This is the "verified by us vs. relayed" line from good forensic write-ups, in machine-readable form.- Addresses and transactions are written in full. A pooled endpoint with no single address (for example "64 Uniswap pools" or "Tether freeze") may omit
address. - Aggregated edges carry
tx(the first),tx_countandtime_last.
Mitigations: what, how, why — tied to a real case
A mitigation that names no incident is a slogan. Every mitigation bullet in a Technique's ## Mitigations, and every ## How it applies in a mitigation file, answers three questions:
- What to do: one concrete control, not a category. Write "the signer refuses
0x05authorization payloads for custodial keys", not "improve wallet security". - How: where it sits and who enforces it, so it holds when the obvious component is compromised. For example: "in the HSM policy, not in the service that requests signatures".
- Why: the real incident it would have stopped, the step it breaks, and a link to the example. For example: "Binance 2026-10-29: the 50 authorizations signed by Binance 14 → no delegated code → no 167,464 ETH sweep".
Also state the limits: what the control does not stop, as M49 and M50 do. When a source makes a recommendation (Ondology's custodian list, a post-mortem's "lessons"), cite it. When the "would have stopped" is OAK's own reasoning from the mechanism, say so.
On a Technique page, start the section with ### What would have stopped the <year> cases, where every bullet links an example, then keep the general guidance below it. examples/2026-10-binance-devops-laptop-service-container-hot-wallet-drain.md, techniques/T13.004-*, techniques/T15.003-*, mitigations/OAK-M49-* and mitigations/OAK-M50-* are the reference.
tools/check_mitigations.py (in npm run check) enforces the checkable part:
- Mitigation files from OAK-M49 on must link an example under
## How it applies. - A Technique that is the root cause of an example dated 2026-11 or later must have at least one case-tied mitigation.
- Every bullet under "What would have stopped" must link an example.
The ~200 older generic sections are listed by --legacy for backfill.
Per-Technique template (defender's-eye-view)
OAK is a detection and defense framework, not an offensive playbook. Every Technique page is written from the perspective of what a defender, investigator, or risk team observes — not as instructions for performing an action. Use this template:
# OAK-Tn.NNN — <Technique Name>
## Description
2–3 paragraphs in defender language: what this category of adversarial behavior
looks like in the wild, why it matters to risk teams, and where in the kill
chain it sits.
## Observed indicators
What an analyst sees when this Technique has been used. Bullet list of
on-chain or off-chain artifacts that are externally visible after the fact.
- Indicator 1 — what the artifact is, where it appears, why it correlates
with this Technique, known false-positive scenarios.
- ...
## Detection signals
Concrete signals a detector or analyst can act on, ordered by reliability.
Each signal should be specific enough that a contributor can implement it.
- Signal 1 — what to look for, source data, threshold or rule notes,
expected precision/recall trade-offs, false-positive notes.
- ...
## Real-world examples
Link to public, verifiable incidents only. Use forensic write-ups, post-mortem
reports, or on-chain transaction links. Do not link to live attacker
infrastructure.
- [Token / contract] — chain — date — loss (if public) — link to public
forensic write-up or post-mortem.
- ...
## Reference implementations
Detection coverage of this Technique in known tools. Honest about partial
coverage and gaps.
- MG `mg-detectors-rs` — Dxx (link)
- GoPlus — partial via `<api_field>`
- RugCheck — partial / N/A
- ...
## Mitigations
What defenders can do to reduce exposure. Two audiences:
- **For traders / risk teams / investigators:** ...
- **For protocols / launchpads / venues:** ...
## Citations
Numeric or BibTeX-key list pointing into `citations.bib`.
## Discussion
Open questions, known edge cases, observed evasion variants. This is the
"living" section — issues and PRs land here first.
Writing-style rules
- Lead with what defenders see. Description and Observed indicators come before any mention of mechanism.
- No how-to. Do not include attacker tutorials, working exploit code, or step-by-step execution recipes. OAK documents observable patterns, not procedures.
- Cite or omit. Every claim about prevalence, scale, or real-world incidents must cite a public source in
citations.bibor link a public forensic write-up. Anecdote without citation gets removed in review. - Be honest about gaps. If your Reference-implementation row is partial or untested, mark it that way. OAK's credibility depends on honest coverage claims.
- No live attacker infrastructure. Do not link to active drainer kits, live mixer front-ends, or recoverable C2. Cite the forensic write-up instead.
Per-Mitigation template
# OAK-MNN — <Mitigation Name>
## Description
2–3 paragraphs: what the mitigation is, the underlying defensive principle, why it works.
## How it applies
Per-Technique bullets — one bullet per mapped OAK-Tn.NNN with 1–2 sentences on the mitigation mechanism in that technique's context.
## Limitations
What this does NOT cover; where it fails; combinatorial gaps with other mitigations.
## Reference implementations
Vendor-side / open-source / formal-method tools. Honest "no production tooling yet" if none.
## Citations
- `[BIBKEY]` — short note
A mitigation is not a Technique-page mitigation bullet; it is a reusable cross-Technique surface that vendors and risk teams reference when scoping coverage. Use the test "would this mitigation address ≥3 Techniques across ≥2 audience classes?" — if not, the work probably belongs in a Technique-page Mitigations section, not a new OAK-MNN entry.
Per-Software template
# OAK-SNN — <Name>
## Description
2–3 paragraphs: what the tool/kit/family is, infection vector or operating model, role in the OAK-relevant attack chain.
## Observed examples
Per-incident references; link to existing `examples/` files where they apply.
## Detection / attribution signals
What defenders look for. NO specific file hashes — refer to live CTI feeds and named-vendor reporting instead.
## Citations
- `[BIBKEY]` — note
## Discussion
Lineage (predecessors / successors), market-share evolution, naming-overlap caveats, takedown / disruption history.
Software entries cover named tools and malware families; the operator group that uses them lives at OAK-Gnn actor entries. The Group/Software split keeps reusable tooling distinct from the operators that use it.
Per-Group (Threat Actor) template
# OAK-Gnn — <Group Name>
## Description
2–3 paragraphs.
## Targeting profile
- target type 1
- target type 2
## Observed Techniques
- OAK-Tn.NNN — short note
## Observed Examples
- examples/<incident>.md — short note
## Citations
- `[BIBKEY]` — note
## Discussion
Operator-profile evolution, TTPs over time, attribution caveats, cluster-boundary distinctions vs neighbouring OAK-G entries.
Attribution-strength discipline. OAK distinguishes three attribution levels: confirmed (multiple credible national-government or law-enforcement bodies have publicly attributed the activity — FBI press release, OFAC SDN, DOJ indictment, or multi-government joint advisory); inferred-strong (major industry forensic providers have published consistent attributions with technical evidence — wallet-cluster analysis, malware fingerprints, tactical fingerprints); inferred-weak (speculation or single-source attribution; OAK does not publish single-source attributions). Be honest about which level applies and revise upward only when evidence supports it.
Submission flow
- Open an issue first for any new Technique or Tactic-level change. Use the
proposal:label. The maintainers may comment on scope, ID assignment, or de-duplication before you spend effort drafting. - Branch from
main, write your contribution following the template, run the local checks below, and open a PR. - PR title format:
[OAK-Tn.NNN] <short>for Technique work,[OAK-MNN] <short>for Mitigation work,[OAK-SNN] <short>for Software work,[OAK-Gnn] <short>for Threat Actor work,[OAK-DS-NN] <short>for Data Source work,[tactic Tn] <short>for Tactic work,[examples] <short>for incident write-ups,[tools] <short>for code. - Sign your work. Add
Signed-off-by: Your Name <email>to your commit (git commit -s). This certifies the Developer Certificate of Origin.
Local checks before opening a PR
# markdown lint (matches the CI workflow)
npx markdownlint-cli2 "**/*.md"
# link check (slow; optional)
lychee --no-progress './**/*.md'
# citation-format validation + cross-reference check
python3 tools/check_citations.py
# forward references + worked-example structural completeness:
# every OAK-T*, OAK-G*, OAK-M*, OAK-S* mention resolves; every example has
# Loss / Techniques / Attribution / Summary / Public references sections.
python3 tools/check_linkage.py
# reverse anchors + bidirectional consistency:
# actor `## Observed Examples` and technique `## Real-world examples`
# sections must list every example that attributes / references them;
# mitigation `**Maps to Techniques:**` and software `**Used by Groups:**`
# metadata must resolve. The corpus has known legacy debt; new contributions
# must not add to it.
python3 tools/check_backlinks.py
# generate paste-ready bullets when populating actor or technique anchors:
python3 tools/suggest_backlinks.py --actor OAK-Gnn --only-missing
python3 tools/suggest_backlinks.py --technique OAK-Tn.nnn --only-missing
# inspect the corpus (year x Tactic, year-month, per-Technique density):
python3 tools/build_coverage_matrix.py --per-technique --monthly
# topline stats snapshot (counts, attribution distribution, gap surface):
python3 tools/build_stats.py
# regenerate the machine-readable export and commit the result if it changed
python3 tools/export_json.py
git diff --quiet -- tools/oak.json || git add tools/oak.json
Review SLA
Maintainers commit to a first response within 7 calendar days of PR open. Substantive Technique reviews may take longer if peer-review is needed. If you have not heard back in 14 days, please ping @iZonex in a comment.
Identifier assignment
- Tactic IDs (
OAK-T1…OAK-T14) are stable for v0.x; new top-level Tactics will only be added at v1.0+ after community consultation. - Technique IDs (
OAK-Tn.NNN), Mitigation IDs (OAK-MNN), Software IDs (OAK-SNN), Threat Actor IDs (OAK-Gnn), and Data Source IDs (OAK-DS-NN) are assigned by maintainers at PR-open time, based on the proposed scope and the next free numeric slot. - Once published, IDs are never reused. Deprecated entries are marked
Maturity: deprecated(Techniques) orActive: dormant / inactive(Software, Groups) and remain in the repository with a pointer to the superseding entry.
Licensing your contribution
By opening a pull request, you agree to the terms below. There is no form to sign — the act of submitting is the agreement, in the manner of the Developer Certificate of Origin.
You certify that:
- The contribution is your original work, or you have the right to submit it under the licences below.
- You understand the contribution is public, is recorded permanently, and may be redistributed under these terms.
You grant:
- For knowledge content (
tactics/,techniques/,examples/,actors/,mitigations/,software/,data-sources/,citations.bib): a licence under CC BY-SA 4.0, matchingLICENSE-content— and, in addition, a perpetual, worldwide, non-exclusive, royalty-free, irrevocable right for the OAK maintainers to use, reproduce, adapt, publish, translate, and distribute the contribution under any licence terms, including proprietary and commercial terms. - For code (
tools/,scripts/,src/,.github/): a licence under MIT, matchingLICENSE-code. - For detection specs (
specs/): a licence under the terms declared in that file'slicense:field.
Why the additional grant in (3) exists — stated plainly, because you deserve the reason:
CC BY-SA's ShareAlike condition means that a work built on ShareAlike content must itself be ShareAlike. That is the right default for the corpus and it is not changing: OAK stays free under CC BY-SA, permanently and irrevocably. But it also means that without the additional grant, no derivative work — a book, a course, a printed edition, a translation carrying a publisher's terms — could ever incorporate a contributor's text, because a publisher cannot accept ShareAlike obligations on a commercial edition.
The grant keeps that door open. It does not close any door for you: you keep your copyright, you keep every right you had, and your contribution remains available to everyone under CC BY-SA exactly as before. What it adds is the ability for the maintainers to carry the corpus into venues that CC BY-SA alone cannot reach.
If you are not able to make the grant in (3) — because your employer holds the copyright, or for any other reason — say so in the PR. It is not a blocker. We will discuss it rather than silently accept a contribution under terms you cannot give.
Code of conduct
Be excellent. Disagreements happen — keep them about the content. Maintainers will close threads that get personal.
Maintainer contact
Initial maintainer: Dmytro Chystiakov (@iZonex).
For sensitive disclosures or non-public real-world examples, please reach out off-list before opening a public PR.