ADR 0035 — DUT Inspection Effectiveness Validation¶
- Status: Proposed (2026-05-13) — materialization tracked across SPAN-7c, SPAN-8, and SPAN-9 waves
- Date: 2026-05-13
- Deciders: TLSStress.Art project
- Targets: v3.9.x — v4.x
- Patent claim families:
- Extends #16 (SPAN tiered ingest + cross-correlator — ADR 0024 + 0034)
- Proposes new claim family for TLS Decryption Posture Validation via certificate-issuer differential analysis (target: provisional 2026-Q3)
- Proposes new claim family for Fast-Path Detection in TLS-Inspecting Middleboxes via differential per-packet latency analysis combined with mid-session canary signature injection (target: provisional 2026-Q3)
- Builds on: ADR 0024 (SPAN.Art line-rate capture), ADR 0034 (3-way fusion correlator)
Context¶
SPAN-3 (v3.7) + SPAN-7 (v3.8, ADR 0034) ship a 3-source cross-correlator that pairs wire metadata, NGFW syslog, and NetFlow/IPFIX into per-flow verdicts. That answers "did the DUT log what it observed?" with eight verdicts including the smoking-gun dut_silent.
But customer interviews reveal five questions our pipeline still cannot answer:
- Long-flow correlation — a NetFlow active-timer emits records every 60s through an 8h SSH session; today's
NetFlowWindow=5mindeclaresmiss_flowbefore the flow actually ends. False positives at scale. - Deny rule effectiveness — the DUT writes
action=denyto syslog AND the flow transfers 50MB. Today this ismisclassified, which is ambiguous between "deny killed mid-handshake (~2KB)" and "deny was silently bypassed (50MB transferred)". Auditors need the distinction. - Decryption coverage — what percentage of TLS flows is the DUT actually decrypting? Customer paid for "100% TLS inspection" but a bypass rule, a wildcard exception, or a configuration error may have created a hole the DUT itself doesn't surface.
- Decryption engine health — fail-open silencioso, buffer overflow under load, certificate engine failures, NPU offload errors — all of which make the DUT say it's inspecting while inspecting nothing. Spirent and Keysight measure decryption performance under load; they don't measure decryption coverage.
- Fast-path / flow offload — the most expensive blind spot. Many NGFW vendors (Fortinet, Check Point, Sophos, Cisco FTD with Flow Offload, Juniper Express Path) ship features that decrypt+inspect only the initial N packets of a flow, then hand the rest to hardware fast-path that bypasses deep inspection. Customers paid $500K-2M for full inspection and get inspection of the first ~5% of bytes per session, with the DUT's own logs reporting "everything was inspected".
These are all manifestations of one umbrella property: DUT inspection effectiveness — does the DUT actually do what it claims to do, throughout the flow lifetime, for the volume of traffic it processes? This ADR captures the design for validating that property across six pillars.
Decision¶
Adopt a six-pillar approach to DUT inspection effectiveness validation:
| # | Pillar | Wave | Effort | Patent claim |
|---|---|---|---|---|
| 1 | Flow lifecycle correlator | SPAN-7c | ~8 h | extends #16 |
| 2 | deny_ineffective verdict |
SPAN-7b+ | ~1 h | extends #16 |
| 3 | Decryption posture indicators | SPAN-8 (5 PRs) | ~24 h | new family (Decryption Posture) |
| 4 | Cert-based decryption detection | SPAN-8a | ~10 h | new family (Decryption Posture) |
| 5 | Fast-path / flow offload detection | SPAN-9 (5 PRs) | ~35 h | new family (Fast-Path Detection) |
| 6 | Inspection Effectiveness Score | SPAN-9d | ~6 h | extends Fast-Path family |
Total: ~84 h spread across ~10-15 sessions. Pillars 1+2 close out the SPAN-7 wave; pillars 3+4 open the SPAN-8 wave; pillars 5+6 open the SPAN-9 wave.
Pillar 1 — Flow lifecycle correlator (SPAN-7c)¶
Problem statement¶
NetFlow/syslog events arrive at different points in a flow's lifetime:
| Signal | Start | Mid | End |
|---|---|---|---|
| Wire (SPAN) | ✅ ClientHello | (encrypted payload, opaque) | TCP FIN/RST |
| Syslog Cisco FTD/ASA | %ASA-6-302013 Built TCP |
— | %ASA-6-302014 Teardown |
| NetFlow active-timer | flow-start record | records every 60s | flow-end (inactive-timer +15s) |
| NetFlow inactive-only | — | — | only at end |
A 30-min file upload produces a built record at t=0, 30 active-timer NetFlow records at t∈[60s, 1800s], and a teardown record at t=1800s. SPAN-7's NetFlowWindow=5min collapses this into 6 distinct partial verdicts instead of one full-lifecycle verdict.
Solution¶
Replace the snapshot-style pendingFlow with a lifecycle state machine:
type FlowLifecycle struct {
Key string
// Wire side — typically one handshake per session, but
// session resumption / renegotiation may add more.
Handshakes []types.MetadataEvent
// Syslog — explicit start/end events from %ASA / equivalents.
BuiltAt *time.Time
BuiltRec *types.SyslogRecord
TornDownAt *time.Time
TornDownRec *types.SyslogRecord
// NetFlow — multiple records expected over the flow lifetime.
NetFlows []types.NetFlowRecord
// State machine
State FlowState
OpenedAt time.Time // engine-clock first signal arrival
LastSignalAt time.Time // for stale detection
}
type FlowState string
const (
FlowStateActive FlowState = "active" // gathering signals, flow alive
FlowStateAwaitingClose FlowState = "awaiting_close" // teardown detected, waiting for final NetFlow
FlowStateClosedCorrelated FlowState = "closed" // verdict emitted, flow GC'd
FlowStateClosedPartial FlowState = "closed_partial" // expired with missing signals
)
Verdict timing¶
Two verdict classes:
- Interim verdict — emitted while flow active; carries
interim: truefield. Operator sees real-time signal but understands it can be revised. - Final verdict — emitted when flow definitively closes. Authoritative; enters Annex.
A flow is considered closed when any of:
- Syslog teardown record observed
- NetFlow record with
flow_endpopulated ANDflow_end < now - safety_margin - No signal for the flow in >
max_silence_window(default 10 min) - Wire FIN/RST observed (requires SPAN-2 to emit a
FlowCloseEvent— new event type, scope SPAN-7c)
Schema impact¶
ValidationReport gains:
type ValidationReport struct {
// ... existing fields ...
// SPAN-7c additions
LifecyclePhase LifecyclePhase `json:"lifecycle_phase,omitempty"` // active | closed | closed_partial
Interim bool `json:"interim,omitempty"` // true if revisable
FlowDuration time.Duration `json:"flow_duration_ns,omitempty"` // BuiltAt → TornDownAt
SignalEventCount int `json:"signal_event_count,omitempty"` // total signals seen for this flow
}
Backward compatibility¶
Configurable via --lifecycle-mode=(snapshot|stateful). Default snapshot for v3.7/v3.8 zero-diff upgrade; operators opt in to stateful when they need long-flow accuracy.
Pillar 2 — deny_ineffective verdict (SPAN-7b+)¶
Problem statement¶
Today's misclassified verdict fires when DUT logs deny but wire shows TLS ClientHello. This is ambiguous:
- (a) DUT denied a flow but logged after seeing the handshake (technically correct, late log) — ~1-2 KB transferred
- (b) DUT logged deny but the flow completed successfully — 50 MB transferred — compliance failure
Auditors need (a) and (b) distinguished. They sound the same in the Annex today.
Solution¶
New verdict deny_ineffective, sub-class of misclassified, fires when:
syslog.action ∈ {deny, drop, block}
AND wire shows ClientHello (TLS metadata present)
AND evidence of substantial transfer:
EITHER NetFlow available with bytes_total > 5_000
OR wire shows N≥3 application-data packets after ClientHello (SPAN-9a will give us per-packet evidence)
The 5 KB threshold is calibrated to "completed handshake + first application-data packet" — anything below is "deny killed mid-handshake" (still misclassified, less severe).
Rule entry¶
Added to pkg/span-correlator/internal/correlator/internal_check.go as rule #5:
{
name: "deny_ineffective",
check: ruleDenyIneffective,
}
func ruleDenyIneffective(s *types.SyslogRecord, m *types.MetadataEvent, n *types.NetFlowRecord) (bool, string) {
if !isDeny(s) || !isTLS(m) { return false, "" }
bytesEvidence := uint64(0)
if n != nil { bytesEvidence = n.BytesTotal() }
if bytesEvidence < 5_000 { return false, "" }
return true, fmt.Sprintf(
"DUT logged action=%q but NetFlow confirms %d bytes transferred — deny rule INEFFECTIVE",
s.Action, bytesEvidence)
}
Verdict applies in modes that include both wire AND NetFlow (i.e. wire_netflow, fusion_3way). In wire_syslog mode without NetFlow input, falls back to misclassified.
Annex impact¶
New section in dut-annex when count > 0:
⚠️ Compliance failures detected¶
The DUT logged deny/drop/block for the following flows, but NetFlow evidence confirms substantial data transfer completed: | Rank | Flow | Bytes transferred | Vendor | Action logged |
This is a stand-alone compliance reporting surface — sells separately to compliance/audit roles.
Pillar 3 — Decryption posture indicators (SPAN-8)¶
Problem statement¶
Customer paid for "100% TLS inspection" but cannot answer:
- What % of TLS flows is actually being decrypted?
- Which SNIs / IPs / applications are bypassing decryption?
- Did decryption coverage drop today vs yesterday (fail-open detection)?
- Did decryption coverage drop under load (engine saturation)?
- Are there specific cert/cipher patterns the DUT consistently can't decrypt (engine bug)?
Spirent/Keysight measure decryption performance under contrived load. They don't measure decryption coverage in production-like conditions. Whitespace.
Solution¶
New module pkg/decryption-posture that consumes MetadataEvent records (enriched with cert info by Pillar 4) and emits four classes of indicator:
3a. Coverage gauge¶
type CoverageSample struct {
SampledAt time.Time `json:"sampled_at"`
WindowSeconds int `json:"window_seconds"`
TotalTLSFlows int `json:"total_tls_flows"`
DecryptedFlows int `json:"decrypted_flows"`
BypassedFlows int `json:"bypassed_flows"`
UnknownFlows int `json:"unknown_flows"` // cert info missing
CoveragePercentage float64 `json:"coverage_percentage"`
}
Sampled per N-second window (default 60s). Time-series exposed via Prometheus + Dashboard.
3b. Bypass list¶
Live ranking of SNIs / Destination IPs / inferred-applications that are bypassing decryption.
type BypassEntry struct {
Identifier string // SNI or DstIP or app-id-style label
IdentifierType string // "sni" | "dst_ip" | "application"
BypassCount int
LastSeen time.Time
Reason BypassReason // explicit_policy | unknown_ca | tls13_ech | unsupported_cipher | tampering_detected | other
}
Top-N (default 50). Dashboard surface lets operator click "Add to decryption policy" — exports a vendor-specific config snippet (Cisco FTD ACL, PAN decryption policy rule, FGT SSL inspection profile entry) that the operator pastes into their DUT to fix the gap.
3c. Fail-open detection (anomaly)¶
Statistical baseline of coverage_percentage over a learning window (default 7 days). Alert when:
- Coverage drops > 2σ below baseline for > 5 min
- Coverage drops abruptly (>10 pp in <60 s)
- Bypass-list churn rate spikes (new SNIs entering bypass-list at unusual rate)
Each is an independent Prometheus alert rule plus a Dashboard "fail-open" banner.
3d. Engine-health correlated indicators¶
When SNMP / IPMI / vendor-API metrics are available (via existing module integrations), correlate:
- Coverage drop ↔ DUT CPU > 90 % → likely buffer overflow / engine saturation
- Coverage drop ↔ DUT memory > 90 % → likely cert-cache eviction
- Coverage drop ↔ specific cipher patterns (e.g. all TLS 1.3 ECDHE-X25519 bypass) → likely engine-side support gap
These correlations are emitted as HealthCorrelationEvent records — annexed to the report and surfaced on Dashboard.
Pillar 4 — Cert-based decryption detection (SPAN-8a)¶
Problem statement¶
How do we know whether a TLS flow was decrypted? Certificate issuer evidence.
| Scenario | Cert in ServerHello (from client's POV) |
|---|---|
| Bypass (DUT does not decrypt) | Server's real CA (DigiCert, Let's Encrypt, ...) |
| MITM (DUT decrypts) | DUT's CA (NGFW corporate root, manually distributed as trusted) |
Today SPAN-2 (span-tls-extractor) parses ClientHello only. It does not extract ServerHello cert info. We need to.
Solution¶
Extend pkg/span-tls-extractor to parse:
- ServerHello — negotiated cipher_suite, negotiated TLS version, session_id, NewSessionTicket detection
- Certificate handshake message — first cert in chain (server's leaf):
- Subject CN + SAN list
- Issuer CN + O
- SHA-256 fingerprint
- NotBefore + NotAfter
- Public key algorithm
Schema additions to TLSHandshakeMetadata:
type TLSHandshakeMetadata struct {
// ... existing v3.7 fields ...
// SPAN-8a additions
NegotiatedCipherSuite string `json:"negotiated_cipher_suite,omitempty"`
NegotiatedTLSVersion string `json:"negotiated_tls_version,omitempty"`
CertSubjectCN string `json:"cert_subject_cn,omitempty"`
CertSubjectSAN []string `json:"cert_subject_san,omitempty"`
CertIssuerCN string `json:"cert_issuer_cn,omitempty"`
CertIssuerO string `json:"cert_issuer_o,omitempty"`
CertFingerprintSHA256 string `json:"cert_fingerprint_sha256,omitempty"`
CertNotBefore time.Time `json:"cert_not_before,omitempty"`
CertNotAfter time.Time `json:"cert_not_after,omitempty"`
CertPublicKeyAlgorithm string `json:"cert_public_key_algorithm,omitempty"`
}
Decryption classification¶
Operator configures the DUT CA fingerprint registry in the Dashboard:
dut_ca_fingerprints:
- vendor: cisco-ftd
fingerprint_sha256: "ab12..."
description: "Lab NGFW corporate CA"
- vendor: cisco-ftd
fingerprint_sha256: "cd34..."
description: "Production NGFW intermediate CA"
pkg/decryption-posture classifies each MetadataEvent cert:
| Cert fingerprint matches | Classification |
|---|---|
| Known DUT CA | decrypted |
| Known public CA (Mozilla CA bundle) | bypassed |
| Neither | unknown (logged for operator review — could be self-signed, internal CA, attack) |
Dual-tap support (SPAN-8d follow-up)¶
Single-tap (internal segment, client↔DUT) is sufficient for the decryption classification above — we see DUT cert vs Server cert directly in the ServerHello.
Dual-tap (client↔DUT AND DUT↔server) adds: - Differential view — confirm the DUT is actually negotiating different sessions on both sides - Latency analysis (foundation for Pillar 5)
Dual-tap is optional for Pillars 3+4; required for Pillar 5's latency-based fast-path detection.
Pillar 5 — Fast-path / flow offload detection (SPAN-9)¶
Problem statement (the crown jewel)¶
Many NGFW vendors implement "fast-path" features that:
- Decrypt + deep-inspect the first N packets / first KB of a TLS flow
- Classify the flow (app-id, threat-category, policy decision)
- Hand the rest of the flow to hardware fast-path (NPU/ASIC/FPGA) which forwards without deep inspection
The DUT's own logs report "TLS classification: app-X" and the customer believes 100 % of bytes were inspected. In reality, only the first ~5 % was. Malicious payloads positioned later in the flow pass through invisibly.
Vendor implementations (status as of 2026-Q2):
| Vendor | Feature | Default? | Variant |
|---|---|---|---|
| Cisco FTD/ASA | Flow Offload (Snort to hardware) | OFF (but common in prod) | A |
| Fortinet FortiGate | NP/SP offload (FortiASIC) | ON | A |
| Check Point | SecureXL + Templates | ON | A |
| Palo Alto | App-ID early classification | ON (with continued inspection) | weak A |
| Juniper SRX | Express Path / Services Offload | OFF | A |
| Sophos XG | FastPath | ON | A→B hybrid |
| Forcepoint NGFW | Flow inspection optimization | ON | B (rare) |
Two variants:
- Variant A — "decryption MITM, inspection offload": DUT keeps the MITM keys throughout the session (cert evidence still shows DUT CA), but the deep inspection engine (Snort, App-ID, IPS) is disabled for that flow after threshold N. Most common.
- Variant B — "full bypass after handshake": DUT decrypts + inspects the handshake, then abandons MITM. From packet N+1 onwards the flow is end-to-end client↔server (cert switches from DUT to Server). Less common but exists.
Solution: three detection strategies, used in combination¶
5a. Cert evolution detection (passive, catches variant B only)¶
Within the same FiveTuple key, observe ServerHello cert sequence:
Handshake #1 (t=0): ServerHello cert = DUT CA → MITM active
Handshake #2 (t > 0): ServerHello cert = Server CA → MITM abandoned
The second handshake could be a TLS renegotiation, session resumption, or session reset. Either way, the cert-issuer transition from DUT-CA to Server-CA is the signal.
Effort: small (~3 h) once Pillar 4's cert parsing is in place.
5b. Differential latency histogram (passive, catches variants A + B; needs dual-tap)¶
Most robust strategy. Requires SPAN taps before AND after the DUT with sub-millisecond timestamping (PTP-synchronized or kernel-bypass capture).
For each flow, compute per-packet latency through the DUT: latency_pkt_k = T_external_k − T_internal_k. Plot the per-flow latency distribution.
| Inspection mode | Latency distribution shape |
|---|---|
| Full deep inspection throughout | unimodal, high mean (e.g. 200-800 µs) |
| Fast-path active from packet N | bimodal: first N pkts at high latency, packets N+1+ at low latency (e.g. 20 µs) |
Bimodality detection via Gaussian Mixture Model (2 components) fit on the per-flow histogram. Threshold N is the inflection point (the "knee" between the two Gaussians). The ratio of low-latency to high-latency means is the fast-path acceleration factor.
Emit FastPathDetected event per flow:
type FastPathDetected struct {
Tuple types.FiveTuple
DetectedAt time.Time
ThresholdPacketIndex int // first packet of low-latency mode
HighLatencyMeanNs int64 // typical deep-inspection latency
LowLatencyMeanNs int64 // typical fast-path latency
AccelerationFactor float64 // high/low
Confidence float64 // GMM goodness-of-fit score
}
Effort: high (~12 h). Requires dual-tap infrastructure.
5c. Active canary injection (active, catches variants A + B; most conclusive)¶
Test-time strategy. During a controlled test, the Playwright/k6 agent runs a "canary playbook":
canary_playbook:
session: tls-1.3
destination: target-persona
packets:
- offset: 0
payload: benign_pattern_seed
- offset: 1..10
payload: random_benign
- offset: 50
payload: eicar_signature_over_tls # canary #1
- offset: 200
payload: snort_test_rule_pattern # canary #2
- offset: 1000
payload: known_ips_signature # canary #3
- offset: 5000
payload: known_ips_signature # canary #4
For each canary, observe whether the DUT generates an alert/log/block. The first canary that fails to trigger is the inferred fast-path threshold.
Report:
Fast-path threshold detected: between packets 200 and 1000
DUT inspected canaries at offsets: 0, 50, 200
DUT failed to inspect canaries at offsets: 1000, 5000
Confidence: HIGH (3 of 4 expected detections present)
Effort: medium (~8 h). Reuses existing Playwright/k6 agent infra + SPAN-3's syslog correlation.
5d. Statistical baseline (heuristic, low confidence)¶
Track DUT alert rate per byte transferred across many flows in production. Flows where alert rate drops sharply mid-session (relative to early-flow baseline) suggest fast-path engagement. Weak signal individually; useful in aggregate as a Grafana panel against the FLOW.Art TSDB.
Effort: low in code (~2 h SPAN-3 instrumentation); medium in dashboarding (~6 h Grafana).
Strategy combination¶
| Strategy | Variant A | Variant B | Active? | Effort |
|---|---|---|---|---|
| Cert evolution | ❌ | ✅ | passive | small |
| Latency histogram | ✅ | ✅ | passive (dual-tap) | high |
| Canary injection | ✅ | ✅ | active | medium |
| Statistical baseline | weak | weak | passive | low |
Ship the first three as a coherent wave (SPAN-9a, SPAN-9b, SPAN-9c). Strategy 5d is deferred to a Grafana follow-up.
Pillar 6 — Inspection Effectiveness Score (SPAN-9d)¶
Single aggregate metric for operator + executive consumption: an Inspection Effectiveness Score (IES) in [0, 100]:
IES = decryption_coverage_pct
× (1 − fast_path_bypass_ratio)
× deny_effectiveness_factor
× lifecycle_completeness_factor
| Factor | Source | Range |
|---|---|---|
decryption_coverage_pct |
Pillar 3 — gauged % of TLS flows decrypted | [0, 1] |
fast_path_bypass_ratio |
Pillar 5 — bytes after threshold / total bytes (averaged across flows where fast-path detected) | [0, 1] |
deny_effectiveness_factor |
Pillar 2 — 1 − (deny_ineffective_count / total_deny_logged) |
[0, 1] |
lifecycle_completeness_factor |
Pillar 1 — 1 − (closed_partial_count / total_flows) |
[0, 1] |
Surfaced as:
- A primary Dashboard gauge (huge, color-coded green/yellow/red)
- The lead KPI in the Annex header
- The headline number in the executive summary report
- A Prometheus gauge tlsstress_dut_inspection_effectiveness_score
Headline pitch (sample marketing)¶
"Customer X's Fortinet 7060F: claimed 100 % TLS inspection. Measured IES: 34 %. Diagnosis: - 89 % decryption coverage (11 % of TLS flows bypassed — see policy gaps below) - 71 % fast-path bypass ratio (NPU offload aggressive — average flow inspected only on first 1.2 KB out of 12 MB) - 8 % of
deny-logged flows transferred > 5 KB of data - 4 % of flows closed without complete telemetry correlation"
That paragraph closes deals. The whole stack exists to be able to print it.
Architecture overview¶
Module / responsibility map after all six pillars ship:
pkg/span-collector (existing, v3.7 — libpcap T1 ingress)
↓ PacketBatch
pkg/span-tls-extractor (existing v3.7 + SPAN-8a extension: ServerHello + Cert parsing)
↓ MetadataEvent (enriched)
pkg/span-correlator (existing v3.7 + v3.8 + SPAN-7b deny_ineffective + SPAN-7c lifecycle)
↓ ValidationReport (interim + final)
├→ pkg/dut-annex (Annex renderer, mode-aware)
├→ pkg/decryption-posture (NEW — Pillar 3, coverage + bypass-list + fail-open)
└→ pkg/flow-art (NEW NetFlow sink + downstream TSDB)
↑ NetFlow records (Pillar 1 lifecycle aware)
pkg/dut-latency-analyzer (NEW — Pillar 5b, dual-tap latency histogram)
↓ FastPathDetected events
pkg/canary-injector (NEW — Pillar 5c, test-time playbook engine)
↓ canary detection results
pkg/inspection-effectiveness (NEW — Pillar 6, IES aggregator + Dashboard tile)
Module boundaries deliberately respected¶
span-correlatorstays focused on cross-correlation. It does not classify decryption posture or detect fast-path — those are downstream consumers.decryption-postureis a stand-alone module so customers without SPAN-2/SPAN-3 (perhaps using third-party flow collectors) can still consume just this pillar if they pipeMetadataEvent-shaped JSON in.dut-latency-analyzeris dual-tap-only; gracefully degrades to "unsupported" when only one tap is configured.canary-injectoris test-time only; not deployed in production correlator path.
Rollout¶
Recommended sequence balancing patent priority, commercial demonstration value, and engineering risk:
| Order | Wave | Purpose | Effort |
|---|---|---|---|
| 1 | SPAN-7b (planned) + Pillar 2 deny_ineffective |
Close SPAN-7 wave + ship one new compliance verdict (small win) | 5 + 1 h |
| 2 | SPAN-7c (Pillar 1 lifecycle) | Stops false positives in long flows — prerequisite for production | 8 h |
| 3 | SPAN-7a (Dashboard SourceSelector — planned) | UX for v3.8 features | 4 h |
| 4 | SPAN-8a (Pillar 4 cert parsing) | Foundation for Pillars 3 + 5a | 10 h |
| 5 | SPAN-9c (Pillar 5c canary injection) | Most commercially demonstrable smoking gun; binary result | 8 h |
| 6 | SPAN-9e provisional patent draft (Fast-Path + Canary) | Lock priority date | 4 h |
| 7 | SPAN-8b-d (Pillar 3 — coverage + bypass-list + fail-open) | Decryption posture indicators | 14 h |
| 8 | SPAN-8e provisional patent draft (Decryption Posture) | Lock priority date | 4 h |
| 9 | SPAN-9a + 9b (Pillar 5a cert evolution + 5b latency analyzer) | Complete the fast-path detection trio | 15 h |
| 10 | SPAN-9d (Pillar 6 IES aggregator + Dashboard tile) | Crown jewel UX | 6 h |
Total: ~79 h spread across ~12-15 sessions.
Critical path: SPAN-7c is the prerequisite for clean production behavior. Without it, every long flow in production yields false positives. Ship that before any v3.9 release.
Patent strategy: file provisional for Fast-Path family before Pillar 5b ships publicly (priority date matters). Same for Decryption Posture family before Pillar 3.
Consequences¶
Pros¶
- Six pillars together convert SPAN.Art from "DUT log validator" to "NGFW Effectiveness Validator" — a 5-10× pricier product category
- Three distinct patent families (extends #16 + Decryption Posture + Fast-Path Detection) — defensible IP moat
- Each pillar is independently shippable and demonstrable
- Pillar 5c (canary injection) produces binary, instantly-explainable results — perfect for proof-of-value engagements
- Pillar 6 IES gives the headline number that closes deals
- Pillar 2 (
deny_ineffective) creates a stand-alone compliance reporting surface — sells to audit/compliance roles separately
Cons / risks¶
- Total wave is large (~79 h) — risk of mid-stream pivot if customer signal contradicts assumptions; mitigate by shipping smallest-most-demonstrable first (Pillar 2 + Pillar 5c)
- Pillar 5b (latency histogram) requires dual-tap infrastructure customers may not have — clearly mark as "requires dual-tap" and offer Pillar 5c (canary) as the always-available alternative
- Pillar 4 (cert parsing) opens cryptographic-protocol-parsing attack surface — must use stdlib parsers, no third-party deps, fuzz tests required
- Patent FTO scans are non-trivial — IDS/IPS evasion and middlebox-inspection are dense patent spaces. Budget for legal review.
- Pillar 5c (canary injection) using EICAR or Snort test signatures in production is forbidden — must be opt-in test-time only, with operator confirmation in Dashboard
Compatibility¶
- All pillars are additive — no v3.7 / v3.8 deployments regress
- New
ValidationReportfields are optional (omitempty) - Pillar 1's stateful lifecycle mode is opt-in (default snapshot)
- Pillar 3 is a separate module (no impact on existing pipeline)
- Pillar 5 is dual-tap-aware (single-tap deployments simply skip 5b)
Patent angle¶
Existing #16 family (extends)¶
ADR 0035 sharpens claim #16:
- Per-flow lifecycle correlation with asymmetric per-signal timing windows (Pillar 1)
deny_ineffectiveverdict via NetFlow-volume + syslog-action differential (Pillar 2)- Bidirectional inspection effectiveness validation under operator-configurable source set (Pillars 3-6 reinforce 0034's adaptive-multi-source element)
Proposed new family: Decryption Posture Validation¶
Independent claim: A method for validating TLS decryption coverage of a network middlebox via passive observation of certificate-issuer evidence in ServerHello messages, comprising: - Registry of trusted decryption-device CA fingerprints - Per-flow classification (decrypted / bypassed / unknown) by matching observed cert against registry - Aggregation into time-series coverage metrics - Anomaly detection for fail-open events via baseline deviation - Correlation of coverage with device health telemetry
Differentiation from prior art: - Spirent/Keysight measure decryption performance (PPS/throughput) — not coverage - Vendor-supplied tools (Cisco Secure Workload, PAN Cortex) report intent — not measured evidence - Academic prior art (CCS, NDSS) focuses on attack-side TLS-MITM detection — adversarial framing, different scope
Proposed new family: Fast-Path Detection in TLS-Inspecting Middleboxes¶
Independent claim: A method for detecting hardware-accelerated bypass of deep-inspection in TLS-inspecting middleboxes, comprising: - Dual-tap packet capture with sub-millisecond timestamping before and after the middlebox - Per-flow latency histogram construction - Bimodality detection via Gaussian Mixture Model fit - Threshold-packet identification from inter-mode inflection point - Acceleration-factor calculation from mode latency ratio
Dependent claim: further comprising mid-session injection of detection-canary payloads with known IDS/IPS signatures at controlled packet offsets, observation of middlebox alert/log generation per canary, and correlation of canary detection failures with passive latency-based bimodality signals.
Differentiation from prior art: - "Fast-path" is documented terminology among NGFW vendors (lay-of-the-land) - Combination of (latency analysis + canary injection) is non-obvious - Existing IDS evasion research focuses on attacker-side techniques to bypass IDS; this is the inverse — defender-side technique to discover that the IDS is bypassing itself - Existing middlebox correctness checkers (LinkSmith, Mochi, etc.) focus on protocol compliance, not inspection effectiveness
FTO scan required for both new families before drafting: - Espacenet + USPTO + Google Patents search on: "TLS inspection coverage", "middlebox decryption verification", "deep inspection bypass detection", "network device fast-path detection" - Estimated 4-6 h legal/IP work for scan + claim drafting - Run in parallel with engineering work; results don't block code but inform claim scope
Open questions for future ADRs¶
- CA fingerprint registry distribution — manually managed today; should DUT auto-discovery probe DUT API to retrieve cert? (defer to v4.x)
- Canary signature library — start with EICAR-over-TLS + Snort test rules + ETPro samples; eventually need a curated signature library with weekly updates (paid feed or own curation?)
- Dual-tap infrastructure recommendations — what NIC + driver + clock-sync stack do we recommend customers deploy for Pillar 5b? Mellanox ConnectX-6 + PTP4L + DPDK-style timestamping is the gold standard; document this in
docs/SPAN_DUAL_TAP_GUIDE.md(separate doc PR) - Privacy implications of cert observation — observing customer TLS metadata may have GDPR/LGPD implications even when decrypted content stays inside the network. Review with legal before shipping Pillar 4 publicly.
- Performance under high coverage compute — Pillar 5b's GMM fitting per flow at 10 Gbps could saturate CPU. Plan a load test before claiming production-ready.
References¶
- ADR 0024 — SPAN.Art line-rate capture (parent of pillar 1)
- ADR 0034 — SPAN.Art 3-way fusion correlator (parent of pillars 1-2)
- Patent claim #16 family (extends)
- RFC 5246, RFC 8446 — TLS 1.2 / 1.3 (foundation for Pillar 4 cert parsing)
- RFC 7011 — IPFIX (foundation for Pillar 1 NetFlow timing model)
- Cisco FTD documentation: "Flow Offload" (vendor literature for Pillar 5 detection target)
- Fortinet NSE 7 / NP/SP offload literature
- Check Point SecureXL administration guide
- Snort 3 IPS rule reference (Pillar 5c canary library seeds)
- Mozilla CA bundle (Pillar 4 reference public CA list)
- NIST SP 800-52r2 — TLS server config baselines
- Memory companion:
discuss_dut_inspection_effectiveness_2026_05_13.md