# Candidate Findings — Native host — audit-snapshot-2026-05-24T15-55Z.md Scope: rcjav-host.py + rcjav-host.bat + register-host.bat + install-host.ps1 Required-reading: AGENTS.md / mockup / CACHE_CONTRACT.md / bug-audit-plan.md Auditor: fresh Explore agent --- ## Candidate C-1 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:1216-1221 - Hunch: Path allowlist check is case-sensitive; if rclone remote names are case-insensitive, a path with different-case remote could bypass the security check. - Trace: _path_in_allowed_prefixes at line 1216 normalizes path slashes but not case. Line 1219 compares path_norm == prefix without .lower(). If extension passes CQ:JAV/file and allowlist has cq:JAV, the check fails. - Question for verifier: Are rclone remote names case-insensitive, and can a case-mismatch bypass the allowlist? - Suggested severity: M (potential security bypass if rclone treats remotes case-insensitively) - Contract refs needed: none ## Candidate C-2 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:306-316 - Hunch: ead_message() reads a 4-byte length prefix without validating max size; a sender could cause huge memory allocation. - Trace: Line 312 reads length as unsigned int; line 313 reads exactly that many bytes with no cap. If msg_len = 0xFFFFFFFF, attempts to allocate 4 GiB. - Question for verifier: Is there a practical max message size enforced by the browser before the host receives it? - Suggested severity: M (DoS via huge length prefix; host could crash) - Contract refs needed: none ## Candidate C-3 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:174-217 (post_discord_alert) - Hunch: Discord webhook URL validation at line 182 checks format but not reachability; blocking urllib.request.urlopen at line 209 with 5-second timeout could delay RPC response if webhook is unreachable. - Trace: Line 182 regex validates URL format. Line 209 calls urllib.request.urlopen with timeout=5. If URL is malformed or unreachable, the attempt blocks for up to 5 seconds. - Question for verifier: Are webhook alerts fired on the main message loop, potentially blocking RPC response? - Suggested severity: M (RPC delay if alerts fire synchronously on main loop) - Contract refs needed: none ## Candidate C-4 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:2235-2264 (handle_scan) - Hunch: handle_scan returns success before spawn thread completes, so if subprocess.Popen fails in _scan_worker, extension incorrectly sees "started": true. - Trace: Line 2260-2264 spawns thread with .start() and immediately returns {"ok": True, "started": True}. If Popen fails in _scan_worker (line 2092), exception is caught and logged but message loop already returned. - Question for verifier: If subprocess.Popen raises immediately, does extension see success but scan never started? - Suggested severity: M (misleading response; race condition on success status) - Contract refs needed: none ## Candidate C-5 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:2053-2227 (_scan_worker) - Hunch: Blocking for loop reading stderr (line 2101) with no timeout; if rc-jav hangs, progress updates freeze until 5-second deferred kill. - Trace: Line 2101 or raw in proc.stderr: blocks on each line. No timeout. If rc-jav stalls, loop blocks. Deferred kill fires after 5 seconds (line 2297-2302). - Question for verifier: Does stderr blocking cause observable 5-second stalls in progress updates if rc-jav hangs mid-output? - Suggested severity: M (observable delay; progress freezes up to 5 seconds) - Contract refs needed: none ## Candidate C-6 - File: D:\DEV\Extensions\Production\rclone-jav\host\install-host.ps1:47 - Hunch: Extension ID validation regex ^[a-p]{32}$ silently rejects invalid IDs without warning; user may not notice typos in manually-entered IDs. - Trace: Line 47 filters IDs by regex; if ID doesn't match, it's silently skipped. No warning printed. - Question for verifier: Should rejected IDs trigger a warning, or is silent skipping acceptable? - Suggested severity: L (silent failure; user might not notice ID was rejected) - Contract refs needed: none ## Candidate C-7 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:404-432 (run_rcjav) - Hunch: Hardcoded PYTHON = "python" without verifying it exists on PATH; error message is generic if python is not found. - Trace: Line 416 uses bare PYTHON string. Line 431 returns generic error str(e) if subprocess fails. - Question for verifier: If python is not on PATH, is the error message clear enough to diagnose? - Suggested severity: L (error is returned; message could be more specific) - Contract refs needed: none ## Candidate C-8 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:1100-1131 (_patch_cache_remove_paths) - Hunch: Orphaned .tmp files from failed cache writes are never cleaned up. - Trace: Line 1126-1128 writes temp and replaces. If replace fails at line 1128, OSError caught at line 1129, but .tmp file remains on disk. - Question for verifier: Is resource leak of orphaned .tmp files acceptable? - Suggested severity: L (resource leak; no data loss) - Contract refs needed: none ## Candidate C-9 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:323-356 (_shrink_response) - Hunch: Placeholder "TBD" in line 343 suggests unresolved work, but code later resolves it; confusing but not a functional bug. - Trace: Line 343 appends "structured TBD"; line 355 appends actual count. "TBD" is always replaced. - Question for verifier: Can "TBD" ever remain in the final truncated_reason? - Suggested severity: L (misleading message; no functional bug) - Contract refs needed: none ## Candidate C-10 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:2092-2110 - Hunch: Partial JSON lines from ungracefully terminated process are silently caught, potentially losing progress data. - Trace: Lines 2104-2112 parse SCAN_START JSON; exceptions caught and pass-ed. If process killed mid-line, JSON decoder fails silently. - Question for verifier: Can partial JSON lines from forced process termination cause stale progress to persist? - Suggested severity: L (error silently caught; scan restarts cleanly on next invocation) - Contract refs needed: none ## Candidate C-11 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:1259-1260 (handle_delete) - Hunch: Rclone paths not pre-validated; malformed paths reach rclone command and fail there instead of being rejected early. - Trace: Line 1258-1260 validates only local paths with Path.exists(). Rclone paths skip existence check. Allowlist check at line 1267 validates prefix only. - Question for verifier: Should rclone path format be pre-validated, or is deferring to rclone error handling acceptable? - Suggested severity: L (rclone rejects malformed paths; no silent failure) - Contract refs needed: none ## Candidate C-12 - File: D:\DEV\Extensions\Production\rclone-jav\host\rcjav-host.py:589-603 (_load_host_cache) - Hunch: In-process cache memoization uses resolved path as key, but if user changes rcjav_path mid-session, stale cache from different cache.json could be served. - Trace: Line 584 key = str(cache_path.resolve()) — key includes resolved path. If rcjav_path changes, cache_path changes and fresh entry loaded. But logic is subtle. - Question for verifier: Can two different cache.json files from different rcjav_path values collide in the memoization key? - Suggested severity: N (cache key includes resolved path; no obvious collision) - Contract refs needed: none --- ## VERIFIER NOTES (Phase 1 Moderate verification, stricter prompt with external/internal-input rule) - C-1 (case-sensitive allowlist) — REFUTED. Gate is fail-SAFE; case-mismatch rejects (no bypass). Usability gap noted but not a bug. - C-2 (unbounded msg length) — REFUTED. Chrome NM protocol caps extension-to-host at 64 MiB browser-side. Only Brave can write to host stdin. - C-3 (blocking Discord) — CONFIRMED M, high confidence. All 5 callsites on main thread; test bypasses rate limit. Promoted as M-1. - C-4 (handle_scan premature success) — CONFIRMED M, very high confidence. 1-2s race window. Promoted as M-2. - C-5 (stderr blocking) — PARTIAL → demoted M to L. 5s stale progress max, cancel works delayed, no data loss. Promoted as L-1. CHUNK 2 CALIBRATION: - Severe: 0 (none flagged) - Moderate rejection: 2/5 = 40% (pure refute), 1 demoted - Combined: 2/5 = 40% (stop condition >30% triggered) - Auditor weaknesses: (1) flagging fail-safe gates as if fail-open, (2) ignoring protocol-level caps from upstream layers - L candidates NOT verified per stop condition. Same auditor pattern likely affects L list. Revisit only if needed.