Remote code execution in the OZOLS ERP via an abandoned update domain
OZOLS (OzolsSQL) for Windows
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.
Severity: CriticalCVSS10.0CVE-2026-223067 min read
§ 01. Overview
OZOLS is an ERP and accounting system used by Latvian businesses, built on Microsoft SQL Server with a Windows client. Like many long-lived line-of-business products, it updates itself automatically: a job on the customer's database server pulls new program files from the vendor's download host and rolls them out to every workstation.
OffSeq found that the update host — its2.lv — was a domain the vendor had let expire, while it was still hardcoded into every deployed client. The update channel ran over plain HTTP with no signature, hash or certificate validation, so whoever controlled the domain controlled the code that OZOLS downloaded and executed. A whois lookup confirmed the domain was free to register. That makes this a textbook supply-chain takeover: register one lapsed domain, and you have remote code execution as the SQL Server service account on every affected installation, spreading from there to all of its workstations. To keep a real attacker from doing exactly that, OffSeq registered its2.lv defensively while the disclosure was coordinated through CERT.LV. It is tracked as CVE-2026-22306.
§ 02. How the OZOLS update channel works
The update is driven from the customer's SQL Server. A persistent SQL Server Agent job, <db>_update (@subsystem = N'ActiveScripting'), together with serv_update.vbs, fetches files over cleartext HTTP using the MSDAIPP.DSO.1 WebDAV provider from a fixed path:
http://www2.its2.lv/Download/ozols/progs/It downloads, in order, Vers.txt, ozolssql.arh, ozols.arh and arj.exe. The only decision it makes is a numeric comparison: Vers.txt advertises a version, and if it is higher than the installed one, the update proceeds. There is no TLS, no code signature, no checksum and no WinVerifyTrust — nothing that ties the downloaded files to the vendor.
The downloaded arj.exe — an executable pulled from the same untrusted channel — is then run to unpack ozols.arh, via WScript.Shell.Run and/or master..xp_cmdshell. The unpacked archive is written into the SQL database's sprg table with an incremented version number (a TRUNCATE followed by an INSERT). At start-up, every OZOLS client compares its version against sprg, extracts ozols.arh from the table, unpacks it over its own program directory and restarts. Whatever code arrives through the update therefore reaches the database server first and then, automatically, the entire workstation fleet attached to that database.
§ 03. Root cause: an abandoned domain, still trusted
The vulnerability is not a subtle logic bug — it is trust placed in a name the vendor no longer owned. Every integrity control this update path needs is absent, and the one identifier that anchored it to the vendor had been given up:
| Control the update path requires | Status in OZOLS |
|---|---|
| Transport security (TLS) | none — cleartext HTTP over WebDAV |
| Authenticity of the source host | none — its2.lv was abandoned and free to register |
| Signed or hashed package | none — no signature, no checksum, no WinVerifyTrust |
| Trusted extractor | none — arj.exe is fetched from the same channel |
| Only check performed | numeric version comparison from Vers.txt |
A whois query against the .lv registry returned the domain's status as free:
whois -h whois.nic.lv its2.lv
# -> Status: freeBecause its2.lv was still the update source baked into shipped clients, whoever registered it would serve OZOLS's updates. Control of one expired domain is control of the code that runs on every customer's SQL Server and workstations.
§ 04. Proof of concept
The chain was demonstrated end to end in a controlled environment. So that a real attacker could not seize the domain during coordination, OffSeq registered its2.lv defensively (along with locta.lv and softex.lv, two more abandoned names from the same client).
A malicious update server was stood up over WebDAV/HTTP at the path the client requests, advertising a higher version and a harmless payload:
http://www2.its2.lv/Download/ozols/progs/OzolsSQL/
Vers.txt # line 1 = DbVers, line 2 = PrgVers (higher than the victim's)
ozols.arh # ARJ archive with the PoC payload (a harmless marker)
arj.exe # harmless wrapper for the demonstrationFor a non-destructive proof, arj.exe was replaced with a wrapper that only drops a marker file:
@echo off
echo PoC-OZOLS-%COMPUTERNAME%-%DATE% > C:\ozols_update_poc.txtRunning the update check on a test SQL instance — exactly what the <db>_update Agent job does — triggers the chain:
EXEC msdb.dbo.sp_start_job @job_name = N'<db>_update';The result confirmed both halves of the impact: C:\ozols_update_poc.txt appeared on the SQL Server, proving code execution in the service-account context; and the PoC ozols.arh landed in the sprg table with an incremented version, so at the next start-up every client extracted and ran it — confirming propagation to the workstations.
The defensively held domain also gave a passive census of real, unpatched installations, with no exploitation of any victim — production systems reached out to it on their own:
GET /Download/ozols/progs/OzolsSQL/Vers.txt (User-Agent: MSDAIPP / WebDAV) -> live, vulnerable SQL host
GET /misc/proglstxml.asp?skfid=164&fltr=@nSswId=<N> (User-Agent: MSXML3) -> live client; <N> = installation IDThe nSswId value identifies the specific customer organisation behind each request, which is useful for notifying affected parties.
§ 05. Impact and severity
The published metrics are CVSS 4.0 base 10.0 (Critical) (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H) and CVSS 3.1 base 10.0 (Critical) (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H). The attack is over the network, low-complexity, needs no privileges and no user interaction: the SQL Agent job polls the abandoned host on its own schedule, so an attacker holding the domain simply waits for each installation to fetch and run the payload.
The consequence is complete compromise. Code runs first as the SQL Server service account — full control of the accounting and ERP database — and then, through the sprg propagation, on every workstation that starts the client, which is why the CVSS scope is Changed and the subsequent-system impacts are High. This is a worm-like distribution mechanism turned against its owner: the very feature built to push updates fleet-wide becomes the attacker's delivery network.
§ 06. Remediation
The update channel has to re-establish authenticity end to end. The download host must resolve to a domain the vendor controls and be served over HTTPS with proper certificate validation; the downloaded package must be verified before it runs, by a code signature or a pinned hash, so a substituted archive is rejected; and the extraction utility must not be fetched from the update channel at all — a trusted, locally present tool should be used instead of downloading arj.exe. Removing the dependency on any third-party-registerable domain is the durable fix.
Ozols Grupa reported the issue remediated during coordination. Until an updated build is confirmed deployed, operators can contain it directly: disable or delete the <db>_update SQL Server Agent job and remove serv_update.vbs; block outbound access from database servers and workstations to its2.lv and www2.its2.lv (and restrict arbitrary outbound HTTP from those hosts); disable xp_cmdshell on affected SQL Server instances; run the SQL Server service under a least-privilege account; and inspect the sprg table for unexpected version increments or archive contents.
§ 07. Disclosure and outcome
The vulnerability was reported to CERT.LV through Latvia's national coordinated-vulnerability-disclosure platform on 30 June 2026, triaged and forwarded to the responsible party on 6 July, with the vendor added to the coordination case on 16 July. CVE-2026-22306 was reserved on 30 July 2026, at which point the vendor reported the issue remediated. Throughout, OffSeq held the abandoned its2.lv domain to keep it out of malicious hands. The disclosure is coordinated by CERT.LV.
The discovery is credited to Nils Putniņš (OffSeq Cybersecurity).
§ 08. Disclosure timeline
- 2026-06-30OffSeq reports the abandoned-domain RCE to CERT.LV through the national coordinated-disclosure platform
- 2026-07-06CERT.LV triages the report and forwards it to the responsible party
- 2026-07-16The vendor, Ozols Grupa, is added to the coordination case
- 2026-07-30CVE-2026-22306 reserved; the vendor reports the issue remediated
