oak_techniques: [OAK-T11.004]
spec_id: oak-detection-T11.004
version: 0.1.0
maturity: stable
maintainer: "@iZonex"
license: Apache-2.0

scope: |
  Detect insufficient-entropy key generation — off-chain key-
  generation tools that seed CSPRNGs with materially less entropy
  than the curve floor (Profanity 32-bit-seed against 256-bit
  curve), reducing the effective private-key search space to a
  brute-forceable bound. Once a public disclosure lands, the
  affected address space is computable; cohort-tail extractions
  from un-rotated addresses continue for months. Excludes: T11.001
  (vendor UI compromise); T11.002 (wallet-binary distribution);
  T11.003 (in-use multisig modification); generic T9 contract
  exploits not bounded by key-generation entropy.

data_sources: [generation_tool_disclosure_feed,
               address_generation_fingerprint_index,
               affected_cohort_address_population,
               cohort_outflow_log,
               rotation_event_log,
               downstream_admin_authority_index]

detection_logic:
  description: |
    Three orthogonal paths matching the documented operational
    pattern. PATH A (post-disclosure cohort enumeration +
    extraction monitoring): once a generation-tool entropy-
    collapse disclosure lands, enumerate the affected address
    population by generation-fingerprint and monitor for
    extractions. PATH B (rotation-vs-extraction discipline
    metric): for the cohort population, the share of addresses
    that rotate vs extract within the post-disclosure window;
    persistent extraction tail flags un-rotated cohort members.
    PATH C (downstream admin-authority chase): cohort addresses
    that hold admin / deployer authority over downstream
    contracts produce contract-layer losses beyond the EOA
    balance — chase admin authority, not only direct balances.
  pseudocode: |
    # PATH A — post-disclosure cohort enumeration + extraction monitoring
    for each disclosure D in generation_tool_disclosure_feed:
      cohort ← affected_cohort_address_population.enumerate(D.tool_fingerprint)
      window ← [D.t, D.t + post_disclosure_window]
      for addr in cohort:
        outflows ← cohort_outflow_log.events(addr, window)
        if outflows ≠ ∅:
          emit(PATH_A, disclosure=D, address=addr,
               outflow_count=|outflows|, severity=critical)

    # PATH B — rotation-vs-extraction discipline
    for each disclosure D:
      cohort ← affected_cohort_address_population.enumerate(D.tool_fingerprint)
      window ← [D.t, D.t + cohort_tail_window]
      rotated ← {a for a in cohort if rotation_event_log.has_rotation(a, window)}
      extracted ← {a for a in cohort if cohort_outflow_log.is_drained(a, window)}
      un_rotated_extracted ← extracted − rotated
      if |un_rotated_extracted| ≥ tail_extraction_floor:
        emit(PATH_B, disclosure=D, un_rotated_extracted_count=|un_rotated_extracted|,
             severity=critical)

    # PATH C — downstream admin-authority chase
    for each disclosure D:
      cohort ← affected_cohort_address_population.enumerate(D.tool_fingerprint)
      for addr in cohort:
        admin_contracts ← downstream_admin_authority_index.lookup(addr)
        for c in admin_contracts:
          downstream_extraction ← contract_extraction_via_admin(c, addr,
                                                                  window = post_disclosure_window)
          if downstream_extraction ≠ None:
            emit(PATH_C, disclosure=D, address=addr,
                 admin_contract=c, downstream_extraction,
                 severity=critical)

parameters:
  post_disclosure_window:       { type: duration, default: 30d }
  cohort_tail_window:           { type: duration, default: 365d }
  tail_extraction_floor:        { type: integer,  default: 5 }

output_alert: [oak_technique, detection_path, severity, chain,
               disclosure, address, outflow_count, un_rotated_extracted_count,
               admin_contract, downstream_extraction, evidence]

test_fixtures:
  positive:
    - 2022-09-wintermute                             # canonical large-institutional anchor
    - 2022-09-wintermute-profanity-cohort            # canonical cohort-tail anchor
  negative:
    - "Address generated by a tool with vetted CSPRNG seeding (full curve-floor entropy)"
    - "Cohort-member address that rotated within the post-disclosure window with no admin authority residual"

false_positive_modes:
  - PATH A false positives where the post-disclosure outflow is a legitimate rotation transfer (require destination not be a fresh user-controlled address, and require destination match attacker-cluster fingerprint)
  - PATH B false positives during cohort-rotation campaigns by wallet vendors that move many addresses at once (annotate rotation-campaign window)
  - PATH C false positives for legitimate admin transfers via documented governance (cross-reference governance-event feed)

mitigations: [OAK-M01, OAK-M19, OAK-M22, OAK-M37]

reference_implementations:
  - { target: chainalysis-reactor,    chain: cross-chain, url: "" }
  - { target: trm-labs,               chain: cross-chain, url: "" }
  - { target: elliptic-investigator,  chain: cross-chain, url: "" }
  - { target: halborn-disclosures,    chain: cross-chain, url: "" }
  - { target: cert-cve-feed,          chain: cross-chain, url: "" }
