Batch 6 (9): dolibarr, jitsi-videobridge, zed, tryton, suricata, strawberry, zulip, zesarux, zephyr Batch 7 (15): xonotic (4), xash3d (3), xenia, xtuple, zabbix (2), zathura, zebra, yabause, zephyr-0001 Batch 8 (15): woodpecker (2), wine (4), widelands (3), wesnoth (3), wekan (3) Mix of CWE-407 and CWE-312.
4 KiB
Zed Editor — CWE-407 Disclosure Brief
2026-04-13 · Patches available — awaiting upstream merge
Finding
Two O(n^2) defects in Zed across the LSP code action pipeline and extension manifest builder. Both patched. Patches ready for upstream review. The LSP defect fires on every format-on-save and code action invocation; the manifest defect fires at extension build time.
The Defects
zed-0001 (PATCHED — MEDIUM): crates/project/src/lsp_store.rs:2010,3356
// Vec::contains() — O(E) per edit in dedup loop
let mut lsp_edits = Vec::new();
for edit in op.edits {
match edit {
Edit::Plain(edit) => {
if !lsp_edits.contains(&edit) { // O(E) linear scan
lsp_edits.push(edit);
}
}
}
}
Two identical call sites in apply_code_actions_as_format and apply_code_action use Vec::contains() to deduplicate LSP edits. Each new edit triggers a linear scan of all previously accumulated edits. Total cost: O(E^2) where E = number of edits returned by a language server. Large refactors (rename across file, organize imports) can produce hundreds of edits.
zed-0002 (PATCHED — LOW): crates/extension/src/extension_builder.rs:585
// Vec::contains() — O(N) per entry in three manifest loops
if !manifest.languages.contains(&relative_language_dir) {
manifest.languages.push(relative_language_dir);
}
Three while loops accumulate entries into manifest.languages, manifest.themes, and manifest.icon_themes (all Vec), each checking Vec::contains before push. O(N^2) per category where N = number of language dirs / theme files / icon theme files.
Complexity Proof
zed-0001: At E=100 edits per code action:
- Defective: 1 + 2 + ... + 100 = 5,050 comparisons (struct equality checks)
- Fixed: 100 HashSet insertions
- 50x op reduction at E=100.
zed-0002: At N=20 language directories:
- Defective: 1 + 2 + ... + 20 = 210 comparisons
- Fixed: 20 HashSet lookups
- 20x op reduction at N=20. Lower practical impact (extension build time only).
Impact
Zed positions itself as a high-performance code editor. zed-0001 fires in the critical path of format-on-save and code action application, which developers trigger constantly during editing. Language servers like rust-analyzer, TypeScript, and gopls can return large edit batches during rename, organize imports, or bulk fix operations. At 200+ edits, the quadratic dedup adds measurable latency to what should feel instant.
zed-0002 only fires at extension build time and affects developers building Zed extensions. Lower severity but follows the same pattern.
The Fix
zed-0001: Add HashSet shadow set for O(1) dedup alongside the ordered Vec:
// Before
let mut lsp_edits = Vec::new();
if !lsp_edits.contains(&edit) { lsp_edits.push(edit); }
// After
let mut lsp_edits = Vec::new();
let mut seen_edits = HashSet::new();
if seen_edits.insert(edit.clone()) { lsp_edits.push(edit); }
zed-0002: Pre-build HashSet from existing manifest entries:
// Before
if !manifest.languages.contains(&relative_language_dir) {
// After
let existing_languages: HashSet<_> = manifest.languages.iter().cloned().collect();
if !existing_languages.contains(&relative_language_dir) {
Patch
Fixes available:
defects/zed/patch/zed-0001-lsp-edit-dedup-contains.patchdefects/zed/patch/zed-0002-extension-manifest-dedup.patch
Two-file patch across lsp_store.rs (two call sites) and extension_builder.rs (three loops). zed-0001: 50x speedup at E=100. zed-0002: 20x speedup at N=20.
What We Ask
Patches ready for review.
- Confirm receipt and assign a GitHub issue reference (zed-industries/zed).
- Assess severity — zed-0001 fires on every code action and format-on-save in the editor.
- Coordinate a disclosure date — we target 90 days from first contact.
- We will credit the Zed team in the public disclosure. Preferred acknowledgment format welcome.
Contact: see cover email. This brief is confidential until coordinated disclosure.