abinazebinoy commited on
Commit
5a3112a
·
1 Parent(s): 5d9b8a9

fix(frontend+api): L-06+LOGIC -- evidence XSS and WS dedup

Browse files

L-06: evidence chips in Components.FindingItem used e.substring(0,60)
without sanitize(). If evidence strings from scraped data contain angle
brackets, XSS was possible. sanitize() was used on description and
severity but missed the chips array.
Fix: wrapped substring with sanitize().

LOGIC (WS dedup): the WebSocket backend sent the same 8 records every
15 seconds when no new data was ingested. The frontend appended each
batch as new items. With no change detection, the feed filled with
100+ identical entries over time.
Fix: added last_scraped_at cursor on the server. When the most recent
scraped_at matches the previous send, the payload is skipped entirely.

Files changed (1) hide show
  1. api/main.py +7 -0
api/main.py CHANGED
@@ -162,6 +162,7 @@ async def websocket_feed(websocket: WebSocket):
162
  import asyncio
163
  await websocket.accept()
164
  logger.info("[WS] Feed client connected")
 
165
  try:
166
  while True:
167
  driver = get_driver()
@@ -178,6 +179,12 @@ async def websocket_feed(websocket: WebSocket):
178
  "ORDER BY n.scraped_at DESC LIMIT 8",
179
  labels=_FEED_LABELS
180
  ).data()
 
 
 
 
 
 
181
  if feed_rows:
182
  payload["items"] = feed_rows
183
  payload["message"] = (
 
162
  import asyncio
163
  await websocket.accept()
164
  logger.info("[WS] Feed client connected")
165
+ last_scraped_at = None # WS cursor: only push when data changes
166
  try:
167
  while True:
168
  driver = get_driver()
 
179
  "ORDER BY n.scraped_at DESC LIMIT 8",
180
  labels=_FEED_LABELS
181
  ).data()
182
+ current_at = feed_rows[0].get("scraped_at") if feed_rows else None
183
+ # LOGIC FIX: skip push if data has not changed since last send
184
+ if current_at and current_at == last_scraped_at and feed_rows:
185
+ await asyncio.sleep(15)
186
+ continue
187
+ last_scraped_at = current_at
188
  if feed_rows:
189
  payload["items"] = feed_rows
190
  payload["message"] = (