Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions cmd/corpus-crawl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ const (
var keywords = []string{
"censor", "circumvent", "blocking", "blocklist", "allowlist", "whitelist",
"throttl", "shutdown", "deep packet inspection", "protocol obfuscat",
"great firewall", "iran", "russia", "china", "chinese", "belarus",
"great firewall", "geedge", "iran", "russia", "china", "chinese", "belarus",
"kazakh", "myanmar", "turkmen", "saudi", "egypt", "north kore",
"pakistan", "turkey", "turkish", "vietnam", "indonesia", "ethiopia",
"venezuela", "syria", "uzbek", "tajik", "azerbaijan", "afghanistan",
Expand Down Expand Up @@ -359,20 +359,19 @@ func runWith(ctx context.Context, opts runOptions) (res *runResult, err error) {
if source == "usenix-sec" || source == "all" {
// USENIX Security uses a 2-digit-year URL slug. Each year has
// up to 2 cycles (Cycle 1, Cycle 2) plus an aggregated
// technical-sessions page. We try both cycles for the current
// and previous year — broken cycles 404 and we skip cleanly.
// technical-sessions page. Include the final program because later
// papers may never appear on a cycle page (and some cycles 404).
thisYear := time.Now().Year()
for _, y := range []int{thisYear, thisYear - 1} {
yy := y % 100
for _, cycle := range []string{"cycle1-accepted-papers", "cycle2-accepted-papers"} {
url := fmt.Sprintf("https://www.usenix.org/conference/usenixsecurity%02d/%s", yy, cycle)
for _, url := range usenixSecurityURLs(y) {
us, err := fetchUSENIXSecurity(ctx, url, y)
if err != nil {
log.Printf("fetch USENIX Sec %d %s: %v (continuing)", y, cycle, err)
recordFetchErr(fmt.Sprintf("usenix-sec-%d-%s", y, cycle), err)
log.Printf("fetch USENIX Sec %d %s: %v (continuing)", y, url, err)
recordFetchErr(fmt.Sprintf("usenix-sec-%d-%s", y, url), err)
continue
}
log.Printf("fetched %d from USENIX Security '%02d %s", len(us), yy, cycle)
log.Printf("fetched %d from USENIX Security '%02d %s", len(us), yy, url)
cands = append(cands, us...)
}
}
Expand Down Expand Up @@ -1660,13 +1659,20 @@ func fetchPETSymposiumProceedings(ctx context.Context, venuePrefix, url string,
// we use this just to find section starts and slice the body manually.
var usenixHeadingRE = regexp.MustCompile(`(?m)^## \[([^\]]+)\]\(([^)]+)\)`)

func usenixSecurityURLs(year int) []string {
base := fmt.Sprintf("https://www.usenix.org/conference/usenixsecurity%02d/", year%100)
return []string{base + "technical-sessions", base + "cycle1-accepted-papers", base + "cycle2-accepted-papers"}
}

func fetchUSENIXSecurity(ctx context.Context, url string, year int) ([]candidate, error) {
md, err := wickFetch(ctx, url, "markdown")
if err != nil {
return nil, err
}
text := string(md)
return parseUSENIXSecurity(string(md), url, year)
}

func parseUSENIXSecurity(text, url string, year int) ([]candidate, error) {
// Find all paper section starts.
starts := usenixHeadingRE.FindAllStringSubmatchIndex(text, -1)
if len(starts) == 0 {
Expand Down
47 changes: 47 additions & 0 deletions cmd/corpus-crawl/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,50 @@ func TestSanitizeDropsNonTaxonomyTags(t *testing.T) {
t.Errorf("valid defense was dropped: %v", got.DefensesDiscussed)
}
}

func TestUSENIXFinalProgramCoverage(t *testing.T) {
const base = "https://www.usenix.org/conference/usenixsecurity26/"
urls := usenixSecurityURLs(2026)
found := false
for _, url := range urls {
if url == base+"technical-sessions" {
found = true
}
}
if !found {
t.Fatal("missing final program: cycle 2 can be unavailable")
}
const program = `## [Breaking the Boundaries: Analyzing QUIC Frame-Packet Interactions With QUIC-Attacker](/conference/usenixsecurity26/presentation/erinola)

Nurullah Erinola, Marcel Maehren, Marcus Brinkmann, and Jörg Schwenk, *Ruhr University Bochum*

We develop probes to explore how different QUIC server implementations handle the coalescence and fragmentation of payloads, covering both valid and invalid combinations of datagrams, packets, and frames.

## [Technical Analysis of the Geedge Networks Firewall Source Code Leak](/conference/usenixsecurity26/presentation/ablove)

Anna Ablove, *University of Michigan;* Johnnie Walker, *GFW Report*

In this paper, we analyze the source code from this leak, focusing on Geedge Networks' flagship product, the Tiangou Secure Gateway (TSG) firewall.
`
papers, err := parseUSENIXSecurity(program, base+"technical-sessions", 2026)
if err != nil {
t.Fatal(err)
}
if len(papers) != 2 {
t.Fatalf("parsed %d papers, want 2", len(papers))
}
for i, slug := range []string{"erinola", "ablove"} {
p := papers[i]
if p.URL != base+"presentation/"+slug || p.Year != 2026 || len(p.Authors) == 0 || p.Abstract == "" {
t.Errorf("incomplete record: %+v", p)
}
if !matchesKeywordsInText(p.Title) {
t.Errorf("title gate drops %q", p.Title)
}
}
existing := &existingCorpus{byID: map[string]bool{}, byTitle: map[string]bool{}, byURL: map[string]bool{}, byArxiv: map[string]bool{}}
existing.remember(papers[0])
if !existing.contains(papers[0]) {
t.Fatal("same paper on a cycle page must deduplicate")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
paper: 2026-erinola-quic-attacker
kind: evaluation
summary: In the tested versions, seven of 15 QUIC server libraries fail to process a ClientHello
split across two Initial packets coalesced into one UDP datagram. All seven correctly process the
corresponding case with the packets in separate datagrams, locating the compatibility difference
at datagram composition rather than fragmentation alone.
techniques:
- packet-injection
- http3-quic-block
censors:
- generic
defense_implications:
- Test generated QUIC fragmentation candidates across multiple endpoint implementations and datagram
compositions before field evaluation. Endpoint rejection must be distinguished from censor blocking.
section: §7.1, Table 3 (P2 and P3)
extracted_by: codex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
paper: 2026-erinola-quic-attacker
kind: evaluation
summary: QUIC-Attacker exposes control over packets, frames, streams, and cryptographic state for
systematic tests of conforming and malformed QUIC flows. The study tests 15 server libraries and
reports eight denial-of-service vulnerabilities; its catalogs restrict fragmentation to at most
two frames per data stream and do not exhaust all compositions.
techniques:
- packet-injection
- http3-quic-block
censors:
- generic
defense_implications:
- Use the published catalogs as a starting point for automated compatibility and security evaluation,
then expand combinations and client coverage. Passing the catalog is not proof of censorship resistance
or complete protocol correctness.
section: §5–§8, Tables 2–5
extracted_by: codex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
paper: 2026-erinola-quic-attacker
kind: evaluation
summary: The evaluated XQUIC and Kwik versions accept forbidden frame-packet combinations. XQUIC
can buffer application STREAM frames from Initial or Handshake packets and process them after the
handshake; the authors demonstrate application-data injection and stream-control truncation effects.
The paper notes that Kwik developers independently implemented frame-placement validation.
techniques:
- packet-injection
- http3-quic-block
censors:
- generic
defense_implications:
- Reject protocol candidates that weaken frame-placement validation or accept application data at
inappropriate encryption levels. Reproduce the tests against the exact library version selected
for deployment.
section: §7.2.1–§7.2.2, Table 4
extracted_by: codex
35 changes: 35 additions & 0 deletions corpus/papers/2026-erinola-quic-attacker.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
id: 2026-erinola-quic-attacker
title: 'Breaking the Boundaries: Analyzing QUIC Frame-Packet Interactions With QUIC-Attacker'
authors:
- Nurullah Erinola
- Marcel Maehren
- Marcus Brinkmann
- Jörg Schwenk
venue: USENIX Security
year: 2026
url: https://www.usenix.org/conference/usenixsecurity26/presentation/erinola
abstract: The authors introduce QUIC-Attacker and evaluate fragmentation, coalescence, frame placement,
and stream-state interactions across 15 QUIC server libraries. Their controlled experiments uncover
interoperability differences, eight denial-of-service vulnerabilities, and injection vulnerabilities
in Kwik and XQUIC. The framework supports fine-grained construction of both conforming and malformed
QUIC traffic.
censors:
- generic
techniques:
- packet-injection
- http3-quic-block
core: false
notes: 'Protocol-generation pipeline relevance: use the test catalogs and QUIC-Docker-Library to
evaluate endpoint compatibility and security when generating QUIC fragmentation or coalescence
strategies. This is an application of the research, not a censorship-evasion result reported by
the authors. The paper evaluates specific library versions in a controlled lab; do not assume current
releases remain vulnerable. Its limited frame combinations are not exhaustive. QUIC-Attacker is
implemented in TLS-Attacker: https://github.com/tls-attacker/TLS-Attacker ; deployment artifact:
https://github.com/tls-attacker/QUIC-Docker-Library .'
visibility: public
date_added: '2026-09-07'
added_by: codex
sources:
- manual:2026-conference-coverage-audit
- url:https://www.usenix.org/conference/usenixsecurity26/technical-sessions
- url:https://www.usenix.org/system/files/usenixsecurity26-erinola.pdf