f7fc15b17c
Includes: - cli.py path fix (parents[1]) for config/catalog resolution - Library cleanup feature design docs (TODO.md, mockup) - Audit + bug-queue markdowns from May 2026 reliability pass - .gitignore expanded for transient artifacts
122 lines
8.6 KiB
Markdown
122 lines
8.6 KiB
Markdown
# 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.
|