You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: close 5 findings from Oracle audit wave 4 (2 security P0 + 3 correctness)
Three parallel read-only Oracles (search/recall; tagger core + token caching;
CLI + config security). Cores verified safe (composite tag identity, FIFO owner
derivation, tagger cache invalidation, strip/replay purity; unified single-embedding,
git-commit execFile safety, no sqlite-vec; runtime config secret boundary + SSRF
guard + atomic raw-merge). 5 source-confirmed fixes; cache/embedding-identity items
banked (D2 reinforced, D10-D14).
SECURITY P0 (the malicious-repo boundary — CLI side bypassed the runtime's hardening):
- Pi doctor embedding probe expanded project-config {env:}/{file:} tokens
(doctor-pi.ts). A repo's .pi/magic-context.jsonc could resolve
{env:ANTHROPIC_API_KEY} and we'd send it to a repo-chosen endpoint. Now read
project config with isProjectConfig:true (tokens stay literal), strip unsafe
project fields, and drop the inherited user api_key on endpoint redirect —
mirroring the runtime loader.
- Pi doctor/issue redaction was weaker than OpenCode (diagnostics-pi.ts): a log
line with github_pat_/ghp_/AKIA/hf_/JWT/Slack tokens was NOT redacted and could
land in a public `doctor --issue` report; the raw "Last plugin log line" was
printed unsanitized. Now delegate to the shared comprehensive redactor (kept the
original looser sk-/Bearer/key= patterns as a SUPERSET so short tokens still
redact), and sanitizeDiagnosticText the last-log-line print.
CORRECTNESS:
- message-index single-message double-insert (message-index.ts). indexSingleMessage
used a DEFERRED transaction; FTS5 has no UNIQUE, so two processes handling the
same terminal message.updated could both pass the already-indexed check and
double-insert. Switched to BEGIN IMMEDIATE so the in-lock re-check serializes —
mirrors indexMessagesAfterOrdinal.
- search ordinal cutoff applied after LIMIT (search.ts). runMessageFtsQuery
fetched LIMIT*3 rows then filtered messageOrdinal>cutoff in JS, so when the
top-ranked rows are all live-tail, older eligible hits below the limit are never
seen and explicit ctx_search could return nothing. Added a cutoff-aware SQL
statement (predicate before LIMIT); hot-path auto-search (cutoff=null) unchanged.
- config array-element recovery collapsed to all-defaults (prune-config-leaf.ts).
An invalid array leaf (e.g. system_prompt_injection.skip_signatures[0]) made
pruneNestedConfigLeaf return null → recovery dropped the WHOLE config to defaults,
losing valid siblings. Now prune the nearest owning field (→ its default) when
the path descends into a non-object. +2 tests.
Gate: plugin 2176/0, Pi 471/0, CLI 179/0, tsc+biome clean all.
"SELECT message_ordinal AS messageOrdinal, message_id AS messageId, role, content FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ? AND CAST(message_ordinal AS INTEGER) <= ? ORDER BY bm25(message_history_fts), CAST(message_ordinal AS INTEGER) ASC LIMIT ?",
0 commit comments