Skip to content

Commit 681d3bc

Browse files
docs: audit remote-only liveness evidence
1 parent f2b8a5a commit 681d3bc

6 files changed

Lines changed: 179 additions & 6 deletions

File tree

docs/paper/ef_severity_analysis.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ records. All seven records containing both vocabulary classes were also
158158
reviewed: only one directly evidenced a single-input failure, but it was fixed
159159
before mainnet, and zero established High. See
160160
[`liveness_candidate_audit.md`](liveness_candidate_audit.md).
161+
The three remote-term-only rows were also reviewed; none connects a single
162+
remote input to an availability failure. In total, 15 targeted liveness rows
163+
(14 distinct artifacts) have been source-reviewed with zero confirmed High.
161164

162165
## Generated evidence
163166

@@ -173,3 +176,4 @@ before mainnet, and zero established High. See
173176
- [`tables/liveness_candidate_triage.csv`](tables/liveness_candidate_triage.csv)
174177
- [`tables/liveness_test_label_audit.csv`](tables/liveness_test_label_audit.csv)
175178
- [`tables/liveness_both_terms_audit.csv`](tables/liveness_both_terms_audit.csv)
179+
- [`tables/liveness_remote_only_audit.csv`](tables/liveness_remote_only_audit.csv)

docs/paper/liveness_candidate_audit.md

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,39 @@ selecting records whose source text contains both vocabulary classes did not
129129
produce any confirmed High labels. Keyword co-occurrence improves review
130130
priority, but does not replace trigger, deployment, or threshold validation.
131131

132-
## 6. Paper contribution
132+
## 6. Audit of the three remote-term-only records
133+
134+
The three rows with remote-trigger vocabulary but no availability vocabulary
135+
were reviewed next.
136+
137+
| Record | Remote evidence | Availability evidence | Result |
138+
|---|---|---|---|
139+
| Geth `GetBlockHeaders` overflow | Crafted `Skip` request is explicit | No crash, panic, exhaustion, or unavailability stated | Remote protocol logic defect, not demonstrated DoS |
140+
| Lighthouse PeerDAS persistence race | No attacker control stated | Data columns fail to persist | Predeployment internal race |
141+
| Lighthouse gossip amplification | Remote gossip messages are explicit | Amplification after a repeated >256-message cycle; no crash | Multi-message resource amplification, pre-mainnet |
142+
143+
The Geth record demonstrates why “remote” alone is insufficient: one crafted
144+
request reaches defective arithmetic, but the source and regression tests show
145+
incorrect traversal handling rather than an availability failure.
146+
147+
The gossip record merged on 2020-01-31, before Beacon Chain mainnet, explicitly
148+
discusses non-malicious validators, and requires a repeated cycle of more than
149+
256 unique messages. The LLM rationale changes this into a remote attacker
150+
crashing the client, which is not supported by the source.
151+
152+
Results:
153+
154+
- attacker-controlled input evidenced: 1/3;
155+
- remote input evidenced: 2/3;
156+
- single-input availability failure evidenced: 0/3;
157+
- confirmed exact High: 0/3.
158+
159+
Across the three completed targeted strata—five `label=test` rows, seven
160+
both-term rows, and three remote-only rows—15 candidate rows representing 14
161+
distinct artifacts have now been source-reviewed. None establishes exact High.
162+
This remains a deliberately selected audit, not an unbiased precision estimate.
163+
164+
## 7. Paper contribution
133165

134166
> In 89 estimated liveness-DoS High rows, source text mentions availability in
135167
> 67 cases but a remote trigger in only ten, and only seven mention both.
@@ -144,14 +176,12 @@ priority, but does not replace trigger, deployment, or threshold validation.
144176
This is not a precision estimate for all 89 rows because the first audited
145177
stratum was deliberately selected for suspicious protocol labels.
146178

147-
## 7. Next audit strata
179+
## 8. Next audit strata
148180

149181
The remaining queue should be reviewed in this order:
150182

151-
1. the three remote-term-only records, where the claimed availability outcome
152-
needs verification;
153-
2. the 19 records containing neither term class;
154-
3. the 60 availability-term-only records, stratified by client, blast radius,
183+
1. the 19 records containing neither term class;
184+
2. the 60 availability-term-only records, stratified by client, blast radius,
155185
and deployed/predeployment state.
156186

157187
## Generated evidence
@@ -160,3 +190,4 @@ The remaining queue should be reviewed in this order:
160190
- [`tables/liveness_candidate_triage.csv`](tables/liveness_candidate_triage.csv)
161191
- [`tables/liveness_test_label_audit.csv`](tables/liveness_test_label_audit.csv)
162192
- [`tables/liveness_both_terms_audit.csv`](tables/liveness_both_terms_audit.csv)
193+
- [`tables/liveness_remote_only_audit.csv`](tables/liveness_remote_only_audit.csv)

docs/paper/tables/liveness_candidate_summary.csv

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ test_label_confirmed_high,0,5,none establish the EF >33% threshold,0.0
1515
both_terms_audited,7,89,all rows containing both availability and remote-trigger terms,7.865
1616
both_terms_single_input_failure_evidenced,1,7,one source directly states a handcrafted transaction triggers panic,14.286
1717
both_terms_confirmed_high,0,7,none establish deployed >33% impact at the fix date,0.0
18+
remote_only_audited,3,89,all rows containing remote-trigger but no availability vocabulary,3.371
19+
remote_only_single_input_failure_evidenced,0,3,none connect one remote input to an availability failure,0.0
20+
remote_only_confirmed_high,0,3,none establish the EF >33% threshold,0.0
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
id,source_platform,title,source_url,severity_estimated,severity_analysis_label,audit_verdict,availability_evidence,attacker_controlled_input_evidenced,remote_input_evidenced,single_input_failure_evidenced,deployment_context,confirmed_high,audit_reason,blast_radius,authority_tier,root_cause,attack_path,label
2+
lighthouse:networking:PR#832,lighthouse,Prevent duplicate gossipsub loops/message amplification,https://github.com/sigp/lighthouse/pull/832,High,tier-uncertain,pre_mainnet_multi_message_amplification_no_crash,resource_amplification,False,True,False,pre_mainnet,False,"The source describes duplicate gossip loops after more than 256 unique messages and explicitly discusses non-malicious validators. It does not report a crash, requires a repeated multi-message cycle, and merged on 2020-01-31 before Beacon Chain mainnet.",client_specific,B_corroborated,missing_input_validation,malicious_attestation,beacon-chain:attestation
3+
6fad56ffd2f16be8,lighthouse,Fix data columns not persisting for PeerDAS due to a `getBlobs` race condition (#6756),https://github.com/sigp/lighthouse/commit/dd7591f7123dfe072631c0deb0abc1b78cc82733,High,tier-uncertain,predeployment_internal_race_no_remote_attack,functional_failure,False,False,False,predeployment,False,"The source establishes a PeerDAS getBlobs race that prevents data-column persistence. It does not identify attacker control, one-message failure, or a deployed network impact; the commit dates to 2025-01-15.",client_specific,B_corroborated,integer_overflow_underflow,crafted_state,data-availability-sampling
4+
e84e13f52af9dacd,geth,eth/protocols/eth: Fix overflows in `GetBlockHeaders`,https://github.com/ethereum/go-ethereum/pull/31522,High,tier-uncertain,remote_protocol_logic_defect_no_availability_outcome,no_failure,True,True,False,deployed_code,False,"The source explicitly identifies crafted GetBlockHeaders Skip values and fixes overflow/underflow traversal. It does not report crash, panic, resource exhaustion, or node unavailability from the single request.",client_specific,B_corroborated,integer_overflow_underflow,malformed_input,p2p

scripts/audit_liveness_candidates.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,43 @@
136136
),
137137
}
138138

139+
REMOTE_ONLY_DECISIONS = {
140+
"e84e13f52af9dacd": (
141+
"remote_protocol_logic_defect_no_availability_outcome",
142+
"no_failure",
143+
True,
144+
True,
145+
False,
146+
"deployed_code",
147+
"The source explicitly identifies crafted GetBlockHeaders Skip values and fixes "
148+
"overflow/underflow traversal. It does not report crash, panic, resource "
149+
"exhaustion, or node unavailability from the single request.",
150+
),
151+
"6fad56ffd2f16be8": (
152+
"predeployment_internal_race_no_remote_attack",
153+
"functional_failure",
154+
False,
155+
False,
156+
False,
157+
"predeployment",
158+
"The source establishes a PeerDAS getBlobs race that prevents data-column "
159+
"persistence. It does not identify attacker control, one-message failure, or a "
160+
"deployed network impact; the commit dates to 2025-01-15.",
161+
),
162+
"lighthouse:networking:PR#832": (
163+
"pre_mainnet_multi_message_amplification_no_crash",
164+
"resource_amplification",
165+
False,
166+
True,
167+
False,
168+
"pre_mainnet",
169+
"The source describes duplicate gossip loops after more than 256 unique messages "
170+
"and explicitly discusses non-malicious validators. It does not report a crash, "
171+
"requires a repeated multi-message cycle, and merged on 2020-01-31 before "
172+
"Beacon Chain mainnet.",
173+
),
174+
}
175+
139176

140177
def pct(count: int, denominator: int) -> float:
141178
return round(100 * count / denominator, 3) if denominator else 0.0
@@ -329,6 +366,64 @@ def main() -> int:
329366
args.output_dir / "liveness_both_terms_audit.csv", index=False
330367
)
331368

369+
remote_only_rows = candidates[
370+
candidates["evidence_screen"].eq("remote_term_only")
371+
].copy()
372+
actual = set(remote_only_rows["id"])
373+
expected = set(REMOTE_ONLY_DECISIONS)
374+
if actual != expected:
375+
raise ValueError(
376+
f"Remote-only decisions mismatch; "
377+
f"missing={sorted(actual - expected)}, extra={sorted(expected - actual)}"
378+
)
379+
remote_only_rows["audit_verdict"] = remote_only_rows["id"].map(
380+
lambda row_id: REMOTE_ONLY_DECISIONS[row_id][0]
381+
)
382+
remote_only_rows["availability_evidence"] = remote_only_rows["id"].map(
383+
lambda row_id: REMOTE_ONLY_DECISIONS[row_id][1]
384+
)
385+
remote_only_rows["attacker_controlled_input_evidenced"] = remote_only_rows[
386+
"id"
387+
].map(lambda row_id: REMOTE_ONLY_DECISIONS[row_id][2])
388+
remote_only_rows["remote_input_evidenced"] = remote_only_rows["id"].map(
389+
lambda row_id: REMOTE_ONLY_DECISIONS[row_id][3]
390+
)
391+
remote_only_rows["single_input_failure_evidenced"] = remote_only_rows[
392+
"id"
393+
].map(lambda row_id: REMOTE_ONLY_DECISIONS[row_id][4])
394+
remote_only_rows["deployment_context"] = remote_only_rows["id"].map(
395+
lambda row_id: REMOTE_ONLY_DECISIONS[row_id][5]
396+
)
397+
remote_only_rows["audit_reason"] = remote_only_rows["id"].map(
398+
lambda row_id: REMOTE_ONLY_DECISIONS[row_id][6]
399+
)
400+
remote_only_rows["confirmed_high"] = False
401+
remote_only_rows[
402+
[
403+
"id",
404+
"source_platform",
405+
"title",
406+
"source_url",
407+
"severity_estimated",
408+
"severity_analysis_label",
409+
"audit_verdict",
410+
"availability_evidence",
411+
"attacker_controlled_input_evidenced",
412+
"remote_input_evidenced",
413+
"single_input_failure_evidenced",
414+
"deployment_context",
415+
"confirmed_high",
416+
"audit_reason",
417+
"blast_radius",
418+
"authority_tier",
419+
"root_cause",
420+
"attack_path",
421+
"label",
422+
]
423+
].sort_values(["audit_verdict", "id"]).to_csv(
424+
args.output_dir / "liveness_remote_only_audit.csv", index=False
425+
)
426+
332427
exact_duplicate_rows = int(candidates["exact_diff_duplicate"].sum())
333428
duplicate_groups = len(duplicate_fingerprints)
334429
distinct_artifacts = len(candidates) - (exact_duplicate_rows - duplicate_groups)
@@ -434,6 +529,24 @@ def main() -> int:
434529
len(both_rows),
435530
"none establish deployed >33% impact at the fix date",
436531
),
532+
(
533+
"remote_only_audited",
534+
len(remote_only_rows),
535+
len(candidates),
536+
"all rows containing remote-trigger but no availability vocabulary",
537+
),
538+
(
539+
"remote_only_single_input_failure_evidenced",
540+
int(remote_only_rows["single_input_failure_evidenced"].sum()),
541+
len(remote_only_rows),
542+
"none connect one remote input to an availability failure",
543+
),
544+
(
545+
"remote_only_confirmed_high",
546+
int(remote_only_rows["confirmed_high"].sum()),
547+
len(remote_only_rows),
548+
"none establish the EF >33% threshold",
549+
),
437550
]
438551
summary_frame = pd.DataFrame(
439552
summary, columns=["metric", "rows", "denominator", "definition"]

tests/test_security_dataset.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@
6060
LIVENESS_BOTH_TERMS_AUDIT = (
6161
ROOT / "docs" / "paper" / "tables" / "liveness_both_terms_audit.csv"
6262
)
63+
LIVENESS_REMOTE_ONLY_AUDIT = (
64+
ROOT / "docs" / "paper" / "tables" / "liveness_remote_only_audit.csv"
65+
)
6366

6467
BOILERPLATE = re.compile(r"critical update required|urgency guidelines|high-urgency", re.I)
6568
REQUIRED_COLS = {
@@ -372,3 +375,18 @@ def test_liveness_candidate_screen_and_first_audit_stratum():
372375
"deployed_code": 2,
373376
"deployment_unclear": 1,
374377
}
378+
379+
remote_only = pd.read_csv(LIVENESS_REMOTE_ONLY_AUDIT)
380+
assert len(remote_only) == 3
381+
assert int(remote_only["attacker_controlled_input_evidenced"].sum()) == 1
382+
assert int(remote_only["remote_input_evidenced"].sum()) == 2
383+
assert not remote_only["single_input_failure_evidenced"].any()
384+
assert not remote_only["confirmed_high"].any()
385+
assert remote_only["availability_evidence"].value_counts().to_dict() == {
386+
"no_failure": 1,
387+
"functional_failure": 1,
388+
"resource_amplification": 1,
389+
}
390+
391+
audited_ids = set(audit["id"]) | set(both["id"]) | set(remote_only["id"])
392+
assert len(audited_ids) == 15

0 commit comments

Comments
 (0)