Vulnerability disclosure
Server crash in CERT.LV’s Graphoscope when a user disconnects during an upload
Graphoscope (v2.6.1) – CERT.LV
OffSeq found a denial-of-service flaw in Graphoscope, the open-source platform CERT.LV publishes for querying many independent data sources from one interface and showing their relations as a graph. A user who uploaded an indicator list and closed the connection before processing finished made the server dereference a nil WebSocket and crash, signing out every user. Any self-registered account could trigger it reliably. OffSeq reported the issue to CERT.LV and contributed the fix, which CERT.LV merged.
OffSeq
3 min read
Severity: MediumCVSS 6.5cert-lv/graphoscope#9
Key facts
- Class
- NULL pointer dereference via a teardown race (CWE-476, CWE-362)
- Severity
- Medium
- CVSS
- 6.5
- Target
- Graphoscope
- Vendor
- CERT.LV
- Affected
- v2.6.1 (a2a794e) – WebSocket send after /upload
- Fixed in
- cert-lv/graphoscope PR #9 (merged, commit 946ff7c)
- Status
- Fixed upstream
- Role
- Reporter and fix author
CVSS base score
/ 10Medium
Every score is built from eight plain questions about how an attack works and what it costs you.
How hard it is to exploit
What the attacker can do
Select a metric to see what it means
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
§ 01. Overview
Graphoscope is CERT.LV's open-source analysis platform. Analysts query many independent data sources – passive DNS, client databases, leaked-credential sets and others – from one web interface and see the results as a graph of related entities. A user can upload a list of indicators for batch processing; the server works through it in the background and notifies the user over WebSocket when the report is ready.
OffSeq found that this notification could crash the entire server. If the user disconnected before processing finished, the background job wrote to a WebSocket that had already been torn down, and the resulting panic terminated the Graphoscope process.
§ 02. Root cause
uploadHandler starts the processing in a goroutine (upload.go:253). When it finishes, processUploads calls a.send("upload-processed", …) (upload.go:413). Account.send guarded only against a.Session == nil – but when the client disconnects, the deferred teardown in listen() leaves the session in place and clears only the connection:
websocket.go: the session survives, its connection does not.With a.Session non-nil and a.Session.Websocket nil, the guard passed and WriteMessage dereferenced a nil pointer. The teardown also cleared the field without holding WebsocketMutex, so a nil check in send() alone would still have raced with it. The goroutine had no recover(), so the panic was not contained:
§ 03. Impact
One upload followed by a closed connection takes the whole service down, and every signed-in user loses their session. The crash does not depend on winning a narrow timing window: closing the connection at any point before processing finishes is enough, so the trigger works every time.
Graphoscope allows self-registration through /signup, so the attacker needs nothing beyond an account they create themselves. Repeating the request keeps the platform unavailable for as long as the attacker continues.
§ 04. The fix
OffSeq contributed a fix confined to websocket.go:
send()returns early when the session is nil, before reading any of its fields – the previous error path dereferenceda.Session.IPin a log line;send()re-checksa.Session.Websocketfor nil while holdingWebsocketMutex, which is where the teardown writes it;- the teardown in
listen()takes the same mutex aroundClose()and the nil assignment, so a writer never observes a half-closed connection.
On retest the same reproduction left the service running: the log showed the client closing the connection and the processed file being added to the downloads list, and /signin kept answering 200. Three related hardening items were raised as follow-ups – a lock around the shared online map, a top-level recover() in goroutines started from request handlers, and request-context cancellation for in-flight processing. CERT.LV merged the change as pull request #9.
§ 05. Disclosure timeline
- 2026-05-14OffSeq reports the WebSocket nil-dereference crash to CERT.LV and submits a fix upstream (PR #9)
- 2026-10-20Fix reviewed and merged by the CERT.LV maintainers
References
- Upstream fix: cert-lv/graphoscope commit 946ff7c (opens in a new tab) (https://github.com/cert-lv/graphoscope/commit/946ff7c6d833d2c40b8d6a866af67cf0312fff97)
- Pull request: cert-lv/graphoscope #9 (opens in a new tab) (https://github.com/cert-lv/graphoscope/pull/9)
- Graphoscope source repository (CERT.LV) (opens in a new tab) (https://github.com/cert-lv/graphoscope)
- CWE-476: NULL Pointer Dereference (opens in a new tab) (https://cwe.mitre.org/data/definitions/476.html)
- CWE-362: Race Condition (opens in a new tab) (https://cwe.mitre.org/data/definitions/362.html)
Credit
Discovered, reported, and fixed by Nils Putniņš (OffSeq Cybersecurity).
More results
Stored cross-site scripting in CERT.LV’s Graphoscope via upload filenames
OffSeq found a stored cross-site scripting flaw in Graphoscope, the open-source platform CERT.LV publishes for querying many independent data sources from one interface and showing their relations as a graph. The name of an uploaded file was stored unchanged and rendered with innerHTML, so an indicator file with a crafted name ran script in the session of the analyst who uploaded it. OffSeq reported the issue to CERT.LV and contributed the fix, which CERT.LV merged.
Vulnerability disclosure20263 min read
Cross-user report access in CERT.LV’s Graphoscope
OffSeq found a horizontal authorisation bypass in Graphoscope, the open-source platform CERT.LV publishes for querying many independent data sources from one interface and showing their relations as a graph. The report download endpoint checked that a user was signed in but not that the requested report was theirs, so any analyst could read another analyst's uploaded indicators and query results. OffSeq reported the issue to CERT.LV and contributed the fix, which CERT.LV merged.
Vulnerability disclosure20262 min read
Remote code execution in the OZOLS ERP via an abandoned update domain
CVE-2026-22306 is a critical remote-code-execution flaw OffSeq found in the OZOLS ERP system. Its automatic update channel fetched and ran program code from its2.lv – a domain the vendor had allowed to lapse, yet still hardcoded in every shipped client – over cleartext HTTP with no signature, hash or certificate check. A whois lookup showed the domain free to register, so anyone who took it could run code as the SQL Server service account on customer databases and, through OZOLS's own update-propagation table, on every workstation. OffSeq registered the abandoned domain defensively to prevent a malicious takeover.
Vulnerability disclosure20267 min read
