Vulnerability disclosure
Stored cross-site scripting in CERT.LV’s Graphoscope via upload filenames
Graphoscope (v2.6.1) – CERT.LV
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.
OffSeq
3 min read
Severity: MediumCVSS 6.1cert-lv/graphoscope#10
Key facts
- Class
- Stored cross-site scripting (CWE-79)
- Severity
- Medium
- CVSS
- 6.1
- Target
- Graphoscope
- Vendor
- CERT.LV
- Affected
- v2.6.1 (a2a794e) – /upload filename handling
- Fixed in
- cert-lv/graphoscope PR #10 (merged, commit 65bd04a)
- 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:N/UI:R/S:C/C:L/I:L/A:N
§ 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. Besides interactive search, users can upload a list of indicators for batch processing; the server queries every connected source and returns a processed report.
OffSeq found that the name of the uploaded file travelled from the upload request back into the page without being validated or encoded, so a crafted filename became stored script in the uploader's Graphoscope session.
§ 02. Root cause
The /upload handler took header.Filename – the filename= value of the multipart Content-Disposition header, entirely client-controlled – and stored it in MongoDB (users.uploads.in). The same string was then sent back to the uploader's own sessions over WebSocket in the uploaded, upload-processed and upload-lists messages, and the server also embedded it in notification text.
On the client, assets/js/notifications.js and assets/js/user-actions.js wrote those values into the page with innerHTML. Any markup in the filename was therefore parsed as HTML:
§ 03. Impact
The filename is reflected only to the account that uploaded it, so the attacker does not upload the file themselves – they get an analyst to. That is the platform's normal workflow: analysts upload indicator lists shared by partners and other teams. A list delivered with a crafted name runs script in the analyst's session as soon as they upload it, and again whenever their profile's upload list renders. The attacker needs no Graphoscope account; Linux and macOS accept <, > and quotes in filenames, so the name survives delivery.
On a platform built to aggregate an organisation's intelligence sources, script running in an analyst's session can read query results, indicator lists and anything else the interface shows that user, and act in the interface on their behalf. Session cookies are HttpOnly and SameSite=Strict, so the script cannot read the session cookie, and no other site can trigger the upload.
§ 04. The fix
OffSeq contributed a source-side fix in upload.go. The handler now applies filepath.Base() to the submitted name and accepts it only if it matches a strict allow-list:
A non-matching name is rejected before anything is written to the upload queue or MongoDB, using the same response path as the handler's other errors. Ordinary names such as indicators.txt or IOCs - 2026-05.csv upload unchanged.
Because nothing dangerous reaches the stored value, no front-end change was needed to close the vector. The same check also blocks path components and NUL or control characters in names. Replacing the remaining innerHTML sinks with textContent was recommended as separate defence-in-depth work. CERT.LV merged the change as pull request #10.
§ 05. Disclosure timeline
- 2026-05-14OffSeq reports the stored XSS to CERT.LV and submits a fix upstream (PR #10)
- 2026-10-20Fix reviewed and merged by the CERT.LV maintainers
References
- Upstream fix: cert-lv/graphoscope commit 65bd04a (opens in a new tab) (https://github.com/cert-lv/graphoscope/commit/65bd04af79d56b0643d6c31f970e90a16885f80d)
- Pull request: cert-lv/graphoscope #10 (opens in a new tab) (https://github.com/cert-lv/graphoscope/pull/10)
- Graphoscope source repository (CERT.LV) (opens in a new tab) (https://github.com/cert-lv/graphoscope)
- CWE-79: Cross-site Scripting (opens in a new tab) (https://cwe.mitre.org/data/definitions/79.html)
- OWASP – Cross Site Scripting Prevention Cheat Sheet (opens in a new tab) (https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
Credit
Discovered, reported, and fixed by Nils Putniņš (OffSeq Cybersecurity).
More results
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
Server crash in CERT.LV’s Graphoscope when a user disconnects during an upload
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.
Vulnerability disclosure20263 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
