§6 Knowledge Units — The Pattern Registry
Layer §5 of the Debt Collector Stack
Author: Shrikant Bhosale (@debtcollector21)
6.1 What It Is
The Knowledge Unit (KU) engine is a pattern registry that stores, matches, and generalizes vulnerability patterns. It serves as the bridge between the VMF scanner’s raw findings and the AttackGraph’s formal chain model.
A KU is not a CVE entry. It is a mathematical abstraction of a vulnerability class — a geometric description of what the vulnerability looks like in terms of preconditions, postconditions, and the information debt that enables it.
6.2 Architecture
┌──────────────────────────────────────────────────────────────┐
│ KU Library │
│ Built-in (27 KUs) │ Auto-registered (from scans) │
│ ┌────────────────┐ │ ┌────────────────┐ │
│ │ Security CPP │ │ │ [Vendor] Scanner │ │
│ │ CS Foundations │ │ │ Binder Scanner │ │
│ │ Scope Theory │ │ │ [Vendor] │ │
│ └────────────────┘ │ └────────────────┘ │
└──────────────────────────┬───────────────────────────────────-┘
↓
┌──────────────────────────────────────────────┐
│ Match Engine │
│ Input: VMF Finding Dict │
│ Process: Fuzzy word overlap + geometry │
│ + failure mode matching │
│ Output: Matched KU list + similarity │
└──────────────────┬───────────────────────────-┘
↓
┌──────────────────────────────────────────────┐
│ NKU Capture (Negative KUs) │
│ For findings that DON'T match any KU │
│ → Novel pattern detected │
│ → Auto-registered for future matching │
└──────────────────────────────────────────────┘
6.3 Knowledge Unit Definition
Every KU is a dataclass with the following fields:
@dataclass
class KnowledgeUnit:
id: str # e.g., "KU-CPP-001"
name: str # e.g., "Raw Pointer Across Boundary"
domain: KUDomain # security_cpp, cs_foundations, scope_theory, etc.
patterns: list[str] # VMF pattern IDs this KU covers
cwe: list[int] # CWE identifiers (e.g., [822, 823])
preconditions: set[str] # What must be true for this to trigger
postconditions: set[str] # What becomes possible after exploitation
severity: str # critical, high, medium, low, info
description: str # Human-readable explanation
remediation: str # How to fix
references: list[str] # CVE IDs, papers, blog posts
curvature_baseline: float # Expected κ if confirmed (0-1)
examples: list[str] # Source code examples
6.4 The Five Core KU Domains
6.4.1 Security C++ (13 KUs)
| ID | Name | Preconditions | Postconditions | CWE |
|---|---|---|---|---|
| KU-CPP-001 | Raw Pointer Across Boundary | controlled_input, serialized_data, reinterpret_cast |
type_confusion, arbitrary_read |
822, 823 |
| KU-CPP-002 | Null Dereference | controlled_null, unchecked_alloc |
crash, dos |
476 |
| KU-CPP-003 | OOB Array Access | controlled_index, no_bounds_check |
heap_overflow, stack_overflow |
122, 787 |
| KU-CPP-004 | Two-Phase API TOCTOU | shared_state, check_then_use, no_revalidation |
privilege_escalation, state_corruption |
367 |
| KU-CPP-005 | Untrusted memcpy | controlled_src, controlled_len, no_size_check |
heap_overflow, stack_overflow |
120 |
| KU-CPP-006 | Use After Free | free_keep_ref, ref_reuse |
arbitrary_read, type_confusion |
416 |
| KU-CPP-007 | Double Free | free_no_reset, multiple_paths |
heap_corruption |
415 |
| KU-CPP-008 | Format String | user_format, printf_no_fmt |
arbitrary_read, info_leak |
134 |
| KU-CPP-009 | Integer Overflow | unchecked_arithmetic, size_computation |
heap_overflow, buffer_overflow |
190 |
| KU-CPP-010 | DCHECK-only Bounds | debug_only_check, release_no_check |
oob_access, heap_overflow |
1295 |
| KU-CPP-011 | Nullptr Element Validator | object_array, type_check_no_null |
null_deref, type_confusion |
822 |
| KU-CPP-012 | Capacity/Size Confusion | set_size_no_capacity, write_beyond_capacity |
heap_overflow, out_of_bounds |
122 |
| KU-CPP-013 | Error Debt (Information) | unhandled_exception, unchecked_return |
state_corruption, bypassed_validation |
754 |
6.4.2 Go (8 KUs)
| ID | Name | Preconditions | Postconditions |
|---|---|---|---|
| KU-GO-001 | Unsafe Pointer | unsafe_package, pointer_arithmetic |
type_confusion, arbitrary_read |
| KU-GO-002 | Nil Dereference | nil_assignment, no_nil_check |
crash, dos |
| KU-GO-003 | Slice OOB | controlled_index, no_bounds_check |
heap_overflow, panic |
| KU-GO-004 | Goroutine Leak | unbounded_goroutine, no_wait_group |
memory_exhaustion |
| KU-GO-005 | Deferred Panic | panic_in_defer, no_recover |
crash, dos |
| KU-GO-006 | Channel Deadlock | unbuffered_channel, mismatched_send_recv |
dos, hang |
| KU-GO-007 | Race Condition | shared_mutex, concurrent_write |
state_corruption |
| KU-GO-008 | SQL Injection | string_concat_query, no_parameterize |
data_leak, sqli |
6.4.3 Rust (7 KUs)
| ID | Name | Preconditions | Postconditions |
|---|---|---|---|
| KU-RS-001 | Unsafe Block | unsafe_block, raw_pointer |
type_confusion, arbitrary_read |
| KU-RS-002 | Unchecked Unwrap | option_unwrap, result_unwrap, no_match |
panic, dos |
| KU-RS-003 | Ref Cycle | rc_clone, ref_cycle, no_weak |
memory_leak |
| KU-RS-004 | Transmute | transmute_call, type_mismatch |
type_confusion |
| KU-RS-005 | FFI Unsafe | extern_fn, unsafe_ffi, no_validate |
arbitrary_code |
| KU-RS-006 | Lifetime Confusion | lifetime_annotation, unsafe_lifetime |
use_after_free |
| KU-RS-007 | Send/Sync Violation | unsafe_send_sync, shared_mutation |
race_condition |
6.4.4 Java (7 KUs)
| ID | Name | Preconditions | Postconditions |
|---|---|---|---|
| KU-JV-001 | Deserialization RCE | object_input_stream, serializable, no_filter |
arbitrary_code |
| KU-JV-002 | SQL Injection | string_concat_query, no_prepared |
data_leak |
| KU-JV-003 | XSS | user_input_html, no_escape |
xss_execution |
| KU-JV-004 | Insecure Crypto | static_key, weak_algorithm, ecb_mode |
data_leak |
| KU-JV-005 | Android IPC Export | exported_component, no_permission |
intent_injection |
| KU-JV-006 | Root Detection Bypass | runtime_exec, file_check, no_obfuscation |
bypass |
| KU-JV-007 | Unchecked Close | close_in_finally, no_try_with_resources |
resource_leak |
6.4.5 Solidity (5 KUs)
| ID | Name | Preconditions | Postconditions |
|---|---|---|---|
| KU-SOL-001 | Reentrancy | external_call, state_after_call |
drain_funds |
| KU-SOL-002 | tx.origin Auth | tx_origin_check |
phishing_auth_bypass |
| KU-SOL-003 | Delegatecall Injection | delegatecall, controlled_target |
arbitrary_logic |
| KU-SOL-004 | Unchecked Call | call_return_ignored |
silent_failure |
| KU-SOL-005 | Timestamp Manipulation | block_timestamp_dependency |
frontrunning |
6.5 The Match Engine
Match engine implements three matching strategies:
6.5.1 Fuzzy Word Overlap
def fuzzy_match(finding: dict, ku: KnowledgeUnit) -> float:
"""
Match by word overlap between finding description and KU patterns.
Score = |intersection| / sqrt(|finding_words| × |ku_words|)
Range: [0, 1]
"""
finding_words = set(tokenize(finding.get("description", "")))
ku_words = set()
for pattern in ku.patterns:
ku_words.update(tokenize(pattern))
overlap = finding_words & ku_words
return len(overlap) / (sqrt(len(finding_words)) * sqrt(len(ku_words)))
6.5.2 Geometry Match
def geometry_match(finding: dict, ku: KnowledgeUnit) -> float:
"""
Match by geometric properties.
Each KU has a geometry signature:
- Does the finding involve serialization? (KU-CPP-001)
- Does it involve an allocation? (KU-CPP-006)
- Is there a type confusion element? (KU-CPP-011)
Score = matched_properties / ku_properties
"""
finding_props = extract_geometry_properties(finding)
ku_props = set(ku.preconditions) | set(ku.postconditions)
matched = sum(1 for prop in ku_props if prop in finding_props)
return matched / max(1, len(ku_props))
6.5.3 Failure Mode Match
def failure_mode_match(finding: dict, ku: KnowledgeUnit) -> float:
"""
Match by failure mode (ASAN crash type, error pattern).
Each KU maps to specific failure modes:
- KU-CPP-003 (OOB): heap-buffer-overflow, stack-buffer-overflow
- KU-CPP-006 (UAF): use-after-free
- KU-CPP-011 (nullptr validator): null_deref
Score: 1.0 if crash type is in expected failures, else 0.0
"""
crash_type = finding.get("metadata", {}).get("crash_type")
if not crash_type:
return 0.0
expected = KU_FAILURE_MODE_MAP.get(ku.id, set())
return 1.0 if crash_type in expected else 0.0
6.5.4 Combined Score
def match(finding: dict, ku: KnowledgeUnit) -> float:
"""
Weighted combination of all three strategies.
Weights reflect empirical reliability:
- Failure mode match is most reliable (ASAN doesn't lie)
- Geometry match is next (pre/post conditions are structural)
- Fuzzy word overlap is least reliable (description may be noisy)
"""
fm = failure_mode_match(finding, ku) * 0.5
gm = geometry_match(finding, ku) * 0.3
fw = fuzzy_match(finding, ku) * 0.2
return fm + gm + fw
6.6 NKU Capture — Negative Knowledge Units
When a finding does not match any existing KU, an NKU is created:
@dataclass
class NegativeKnowledgeUnit:
id: str
pattern_name: str
domain: KUDomain
severity: str
description: str
geometry_signature: set[str]
failure_modes: set[str]
source: str # file:line of first instance
instances: int
NKUs are the learning mechanism of the KU engine. Every NKU represents:
1. A gap in the VMF scanner’s pattern coverage
2. A vulnerability class that was not previously catalogued
3. An opportunity to improve the scanner
When an NKU reaches instances >= 3 (same pattern in 3 different codebases), it is automatically promoted to a full KU and added to the library.
6.7 Pre/Post Condition Chaining
Each KU’s preconditions and postconditions enable chain building:
def can_chain(ku_a: KnowledgeUnit, ku_b: KnowledgeUnit) -> bool:
"""
Can KU_A and KU_B form a chain?
Yes if any postcondition of KU_A satisfies any precondition of KU_B.
"""
prerequisite_match = ku_a.postconditions & ku_b.preconditions
return len(prerequisite_match) > 0
Example chain:
KU-CPP-001 (Raw Pointer Across Boundary)
postconditions: {type_confusion, arbitrary_read}
→ satisfies precondition of:
KU-CPP-011 (Nullptr Element Validator)
preconditions: {object_array, type_check_no_null, type_confusion}
→ chain: read primitive → null deref → write primitive
This is the same chain that underpins the A01/A02 AOSP finding (CVSS 8.8).
6.8 Validation
| Metric | Value |
|---|---|
| Total KUs | 40 (27 built-in + 13 auto-registered) |
| Total NKUs | 0 (all novel findings so far matched existing KUs) |
| Match accuracy (known) | 100% (43/43 on [Vendor] Wasm) |
| Chain composition success | 100% (35 KUs form valid pre/post chains) |
| Cross-language chaining | 3 chains (C++ → Java via JNI, C++ → Go via cgo) |
6.9 CLI Usage
# List all KUs
vmf ku library
# Show specific KU
vmf ku library --id KU-CPP-001
# Extract KUs from VMF scan results
vmf ku extract findings.json
# Verify a finding against KU library
vmf ku verify finding.json
# Match a new finding
vmf ku match finding.json
# Show NKU capture log
vmf ku nku
# Export KU library
vmf ku export --format json
vmf ku export --format markdown