Deleting a sketch leaves its entire graph in Neo4j
Summary
DELETE /api/sketches/{id} returns 204 and removes the sketch from Postgres, but every Neo4j node carrying that sketch_id is left in place. The graph data of a "deleted" sketch survives indefinitely, invisible to the UI but fully present in the database.
Version
v1.2.12 (docker-compose.prod.yml, ghcr.io/reconurge/flowsint-api:1.2.12)
Reproduction
Create an investigation and a sketch.
Add a
domainnode and run an enricher that expands the graph.domain_to_subdomainson a domain with many subdomains makes the effect obvious — in my run it produced 22,248 subdomain nodes.Confirm the graph:
GET /api/sketches/{sketch_id}/graph→ 22,254 nodes.DELETE /api/sketches/{sketch_id}→204 No Content.Query Neo4j directly:
MATCH (n) WHERE n.sketch_id IS NOT NULL RETURN count(n);→
22254
Every node is still there, still tagged with the deleted sketch's id. The same holds for a small sketch — I first saw it with a 3-node sketch, where the delete left all 3.
Expected
Deleting a sketch should delete the graph belonging to it, or the API should document that it does not and offer a way to purge. At present the only route is manual:
MATCH (n {sketch_id:'<id>'}) WITH n LIMIT 5000 DETACH DELETE n RETURN count(n);(repeated until it returns 0 — a single unbatched DETACH DELETE on a large sketch is heavy).
Impact
Two concerns:
- Data retention. The docs describe Flowsint as local and privacy-first, which invites the reading that deleting an investigation disposes of its data. It does not. For anyone handling subject data under a retention policy, "delete" not deleting is a meaningful gap.
- Unbounded growth. Nothing reclaims these nodes, so a Neo4j instance accumulates the full graph of every sketch ever deleted. Subdomain enumeration produces tens of thousands of nodes per run, so this adds up quickly.
Note
Deleting the owning investigation (DELETE /api/investigations/{id}, also 204) does not clean them up either.
Source: reconurge/flowsint