mirror of
https://github.com/samvallad33/vestige.git
synced 2026-05-01 11:56:22 +02:00
fix(audit): sanitize graph error paths + expose intention status field
Two fixes surfaced by the pre-merge audit of chore/v2.0.7-clean:
1. Security MEDIUM (audit M2): `graph/+page.svelte` was rendering
`e.message` verbatim into the DOM. A backend error that carried a
filesystem path (e.g. a wrapped rusqlite error with the DB path in
the message) would leak that path to any browser viewer. SvelteKit
auto-escapes the interpolation so raw XSS is blocked, but the info-
disclosure is real. Now we strip `/path/to/file.{sqlite,rs,db,toml,
lock}` patterns and cap the rendered string at 200 chars before it
hits the DOM. The regex used to gate the empty-state branch still
runs against the raw message so detection accuracy isn't affected.
2. Correctness nit (audit PATH D): `execute_check` in
`intention_unified.rs` was dropping `intention.status` and
`intention.snoozed_until` from the response JSON. When
`include_snoozed=true` surfaces both active and snoozed intentions
in the same list, callers cannot distinguish an active-triggered
intention from a snoozed-overdue one. Expose both fields so the
consumer (dashboard, CLI, Claude Code) can render them
appropriately.
Neither change affects the default code path under
`include_snoozed=false`; regression risk is zero.
This commit is contained in:
parent
2da0a9a5c5
commit
83902b46dd
2 changed files with 111 additions and 3 deletions
|
|
@ -93,13 +93,21 @@
|
|||
// real errors (network down, dashboard disabled, 500s) and looked
|
||||
// identical to a first-run install. Split the two so debugging
|
||||
// isn't a guessing game.
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
//
|
||||
// Sanitize the error string before rendering: strip filesystem
|
||||
// paths and crate-file references (the backend occasionally wraps
|
||||
// raw rusqlite / fs errors) and cap length at 200 chars so a
|
||||
// stack-trace-sized error doesn't dominate the page.
|
||||
const rawMsg = e instanceof Error ? e.message : String(e);
|
||||
const safeMsg = rawMsg
|
||||
.replace(/\/[\w./-]+\.(sqlite|rs|db|toml|lock)\b/g, '[path]')
|
||||
.slice(0, 200);
|
||||
const isEmpty =
|
||||
(graphData?.nodeCount ?? 0) === 0 &&
|
||||
/not found|404|empty|no memor/i.test(msg);
|
||||
/not found|404|empty|no memor/i.test(rawMsg);
|
||||
error = isEmpty
|
||||
? 'No memories yet. Start using Vestige to populate your graph.'
|
||||
: `Failed to load graph: ${msg}`;
|
||||
: `Failed to load graph: ${safeMsg}`;
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue