community-pulse / security dashboard fail open: backend error or missing jq reports "0 attacks" instead of "unknown"
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
## Summary
The community **security** dashboard can display a reassuring "0 attacks / all clear" when it is actually erroring — a fail-open on a security-signaling surface. Found during a security review of v1.57.7.0.
### 1. `community-pulse` returns all-zeros (HTTP 200) on any error
`supabase/functions/community-pulse/index.ts:194-211`:
```ts
} catch {
return new Response(
JSON.stringify({
weekly_active: 0, change_pct: 0, top_skills: [], crashes: [], versions: [],
security: {
attacks_last_7_days: 0,
top_attack_domains: [],
top_attack_layers: [],
verdict_distribution: [],
},
}),
{ status: 200, ... }
);
}
```
Any internal failure (DB outage, malformed cache, query error) is masked as a healthy "0 attacks" response with HTTP 200 — indistinguishable from a genuine zero.
### 2. `gstack-security-dashboard` reports 0 when `jq` is missing
`bin/gstack-security-dashboard:51-64` — when `jq` is unavailable it falls back to a lossy `grep -o '"security":{[^}]*}'` that breaks on the nested arrays (`top_attack_domains`, etc.), and the documented behavior is to "degrade gracefully to '0 attacks'" (the machine-readable fallback emits `attacks_last_7_days: 0`). So a host without `jq` silently under-reports attacks as zero.
### 3. (related, latent) telemetry `error_message` is transmitted unredacted
`bin/gstack-telemetry-sync:83-84` strips only `_repo_slug`/`_branch` before upload, while `bin/gstack-telemetry-log:227` includes a raw `error_message` field in the synced record. The current edge function's `TelemetryEvent` interface (`supabase/functions/telemetry-ingest/index.ts:7-18`) omits `error_message` and persists only `error_class` (sliced to 100 chars) — so it isn't stored in the DB today — but the raw string still leaves the machine in the POST body and would be persisted if that field is ever added server-side. Free-text telemetry fields should run through the redaction engine before upload.
## Impact
A user glancing at the shield icon / dashboard sees "0 attacks" and concludes there's no prompt-injection activity, when the real state is "backend errored" or "`jq` not installed." For a security indicator, the safe default is "unknown / degraded," not "0 / clear." (This is the same fail-open pattern the project's own `9cc41b71` commit — "4 security guards failing open" — was correcting elsewhere.)
## Suggested fix
- `community-pulse`: on `catch`, return a non-200 status or include an explicit `{ "error": true }` / `{ "stale": true }` flag instead of all-zero aggregates.
- Dashboards: render "data unavailable" distinctly from "0 attacks"; when `jq` is missing, say so rather than reporting 0.
- Redact (or drop) `error_message` before it is written to the synced payload.
Contributor guide
Assessment
This issue has not been assessed yet.