{
 "finding_id": "DF-2226",
 "status": "reproduced",
 "reproduced": 1,
 "impact": null,
 "confidence": "certain",
 "verdict": "REPRODUCED on the stock guest: prop_dictionary_internalize of <plist><dict><key></key><string>x</string></dict></plist> returns a live dictionary and prop_dictionary_get(dict, empty) fetches the object (empty keysym interned). Externalize round-trips <key></key> through the whole plist layer. Kernel-side internalize of untrusted XML has no in-tree caller reachable by an unprivileged user (devd consumes kernel-EXTERNALIZED props, not the reverse), so impact is hardening: any future kernel-side internalize of untrusted dictionaries panics INVARIANTS builds at prop_dictionary.c:248. sys/libprop is shared verbatim with the userland libprop, so the userland library accepts the same degenerate dictionaries.",
 "exploit_chain": "no escalation path: kernel-side internalize of untrusted XML has no in-tree caller reachable by unprivileged users (userland libprop accepts the degenerate dict today)",
 "evidence": "run.log: EMPTY key ACCEPTED + prop_dictionary_get(dict, empty) returns the live object; externalize emits <key></key>; VERDICT.md cites the assert at prop_dictionary.c:248",
 "kernel_refs": [
  "sys/libprop/prop_dictionary.c:1339",
  "sys/libprop/prop_dictionary.c:248",
  "sys/libprop/prop_dictionary.c:252"
 ],
 "poc_changes": "Initial draft used bare <dictionary> XML; DFly libprop internalize requires the <plist> wrapper - switched to plist form and the empty key reproduced immediately. Also captured the externalize round-trip (<key></key> emitted back) via a second probe.",
 "attempts": 2,
 "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
 "runtime_sec": 20,
 "guest_dirty": 0,
 "build_cmd": "cc -O -o prop_empty_key prop_empty_key.c -lprop",
 "run_cmd": "as unpriv user: ./prop_empty_key",
 "code_hash": "27219b40cde82b275fb90e2da3c1a63080069120153fe03920b9f2e31d9a7a11",
 "notes": "",
 "recommended_fix": "Reject empty keys at internalize time (goto bad) so the invariant holds at ingestion instead of asserting at externalize.",
 "fix_status": "not_testable",
 "fix_kernel_uname": null,
 "fix_baseline_reproduced": null,
 "fix_patched_reproduced": null,
 "fix_verdict": "fix.diff compile-validated in the batch combined kernel build (all 37 diffs of this batch applied to in-guest /usr/src; make -j6 nativekernel KERNCONF=X86_64_GENERIC, see batch build log referenced in VERDICT.md); no behavior A/B performed for this Info-tier item; behavior A/B intentionally skipped for Info tier",
 "fix_evidence": "batch combined kernel build log (see findings/poc/_batch41 note in VERDICT.md)"
}
