Reg. No. 40203410806VAT LV40203410806

Theme

Book a consultationBook

01 / 10Vulnerability disclosure

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 requiresStatus in OZOLS
Transport security (TLS)none — cleartext HTTP over WebDAV
Authenticity of the source hostnone — its2.lv was abandoned and free to register
Signed or hashed packagenone — no signature, no checksum, no WinVerifyTrust
Trusted extractornone — arj.exe is fetched from the same channel
Only check performednumeric version comparison from Vers.txt
Table 1Every integrity control the update needs is missing, and the source host was no longer the vendor's.

A whois query against the .lv registry returned the domain's status as free:

whois -h whois.nic.lv its2.lv
# -> Status: free

Because 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 demonstration

For a non-destructive proof, arj.exe was replaced with a wrapper that only drops a marker file:

bat

@echo off
echo PoC-OZOLS-%COMPUTERNAME%-%DATE% > C:\ozols_update_poc.txt

Running the update check on a test SQL instance — exactly what the <db>_update Agent job does — triggers the chain:

sql

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 ID

The 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

  1. 2026-06-30OffSeq reports the abandoned-domain RCE to CERT.LV through the national coordinated-disclosure platform
  2. 2026-07-06CERT.LV triages the report and forwards it to the responsible party
  3. 2026-07-16The vendor, Ozols Grupa, is added to the coordination case
  4. 2026-07-30CVE-2026-22306 reserved; the vendor reports the issue remediated

Have similar exposure in your environment?