Contents
1. Executive summary
CatchPulse v10.9.3 and v10.10.0 allow a standard local user to disable the product's application whitelisting enforcement layer without administrator rights or user interaction.
The issue is caused by two independent weaknesses that combine into a complete bypass. First, the kernel minifilter exposes \SAAppWhitelistingPort with a NULL discretionary access control list (DACL), allowing any local process to connect. Second, the command dispatcher accepts cmd=6 for ExpiryDate updates without checking that the caller is privileged. A caller can therefore send a past ExpiryDate and cause the service/driver path to enter a non-blocking, trust-all mode.
Why this is important
Application whitelisting is intended to be a system-wide control that prevents unknown or untrusted code from running. This vulnerability removes that control rather than bypassing a single policy decision. It was confirmed using a standard user account and can be triggered through Microsoft-signed tooling, making it relevant even in locked-down environments where PowerShell or custom executables are restricted.
- Confirmed with CatchPulse v10.9.3 on Windows Server 2025 using a licensed install; other editions and versions have not yet been confirmed.
- Confirmed end-to-end: previously blocked unsigned test binaries executed after the ExpiryDate write.
- The bypass survives service-level recovery attempts; a reboot/reload of the kernel component is required to restore enforcement.
- With a forged past ExpiryDate left in the registry, offline systems can repeatedly re-enter the bypass state after reboot.
- A structurally similar missing privilege check exists in
cmd=12, which should be fixed at the same time.
2. Vulnerability overview
| Item | Details |
|---|---|
| Affected binary | saappctl.sys - installed SHA-256 40267B24877519DDF41E4CB2566521CD497336FBE8BA64E55E5E9AEDF802EDD8 |
| Component type | FSFilter ContentScreener kernel minifilter, altitude 262510 |
| Affected interface | \SAAppWhitelistingPort |
| Affected versions | CatchPulse v10.9.3 and v10.10.0. |
| Test environment | Windows Server 2025 with a licensed CatchPulse install. |
| Suggested weakness classification | CWE-862 - Missing Authorization; related access-control issue: CWE-284 - Improper Access Control. |
| Primary vulnerable command | cmd=6 - ExpiryDate write |
| Related vulnerable command | cmd=12 - HKLM\...\SAAppCtl\Db\InitialWhitelistSpeed write |
| Attacker requirements | Local standard user. No administrator privileges and no UI interaction required. |
| Observed result | Application whitelisting enters non-blocking/trust-all mode; previously blocked executables run without prompt. |
| Persistence characteristic | Survives failed service restart and can re-activate after reboot if forged registry value remains, especially on offline systems. |
Confirmed exploit chain: connect to unrestricted port -> send cmd=6 with past ExpiryDate -> registry write succeeds -> service logs license-expired state -> enforcement enters trust-all/non-blocking mode -> blocked executable runs.
2.1 CVSS v3.1 score and derivation
The vulnerability is scored as CVSS v3.1 (8.4 High). It disables the product's core security enforcement layer rather than merely bypassing one individual policy decision.
| Metric | Value | Rationale |
|---|---|---|
| Attack Vector | AV:L - Local | The attacker needs local execution on the affected Windows machine. This is not independently network-exploitable. |
| Attack Complexity | AC:L - Low | The path does not require a race condition, special timing, memory corruption, or unusual system state. A standard user can connect to the exposed filter port and send one accepted message. |
| Privileges Required | PR:L - Low | The attacker does not need administrator rights. A normal local user account is sufficient. |
| User Interaction | UI:N - None | No administrator or victim user needs to click, approve, or interact with anything after the attacker runs the request. |
| Scope | S:C - Changed | The vulnerable component is CatchPulse's privileged enforcement path, but the effect extends to the wider protected system by removing application-whitelisting enforcement. |
| Confidentiality | C:N - None | The finding does not directly demonstrate disclosure of files, credentials, or private data. |
| Integrity | I:H - High | The attacker can run executables that CatchPulse previously blocked, defeating the system's application-control policy. |
| Availability | A:H - High | The application-whitelisting protection layer can be placed into a non-blocking/trust-all state and remain disabled until reboot or longer if the forged expiry state persists. |
Full vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:N/I:H/A:H
3. Evidence and screenshots
The screenshots below show the vulnerability moving from baseline enforcement, to successful unprivileged command execution, to observed bypass. Figure captions identify what each screenshot proves and why it matters.
IsAdmin=False, FilterSendMessage HRESULT=0x00000000, kernel outBuf status 0x00000000, and registry confirmation.4. Root cause analysis
4.1 NULL DACL on \SAAppWhitelistingPort
During driver initialization, ports are created through a helper where one argument controls whether the admin-only default security descriptor is retained. For \SAAppWhitelistingPort, the observed setting causes the helper to replace the DACL with NULL. A NULL DACL means any local process can connect to the port regardless of privilege.
| Port name | a9 | Effective access control |
|---|---|---|
\SAAppCtlPort | 1 | Admin-only |
\SAAppCtlCommandPort | 1 | Admin-only |
\SAAppWhitelistingPort | 0 | NULL DACL - unrestricted |
\SAAppCtlNotifierPort | 0 | NULL DACL - unrestricted |
4.2 Missing privilege check on cmd=6
The dispatcher protects several privileged commands by calling a token-checking gate, but cmd=6 is not routed through that gate. The only observed validation is that three date fields satisfy the arithmetic identity start + duration == end. That condition is trivial to satisfy using past license dates, after which the handler writes the supplied value to HKLM\SYSTEM\CurrentControlSet\Services\SAPlus\ExpiryDate.
Related issue: cmd=12 has the same structural defect: it is dispatched without the same privilege gate and writes to a machine-wide registry location. Although the observed cmd=12 target is a scan-speed tuning value rather than the enforcement-critical ExpiryDate, it should be fixed together with cmd=6 to address the underlying authorization flaw.
5. Impact assessment
5.1 Security impact
- Integrity impact is high: previously denied executables can run after the bypass.
- Availability of the security control is high impact: the core whitelisting function is disabled rather than only misclassifying one file.
- Confidentiality impact is not directly demonstrated, but successful execution of untrusted code can become an enabling step for later data access by malware or a malicious local actor.
- No administrator rights are required. The vulnerability crosses the expected boundary between ordinary local user and product policy control.
- The exploit path can run through Microsoft-signed
MSBuild.exe, reducing the effectiveness of policies that only block PowerShell or unsigned/custom executables.
5.2 Persistence and recovery impact
The bypass was not fully reversible by sending a valid future ExpiryDate and attempting to restart the service. The service is NOT_STOPPABLE, and the kernel driver state remains loaded after the restore attempt. The observed operational consequence is that a reboot or equivalent driver reload is required to restore enforcement.
If the forged ExpiryDate remains in the registry, enforcement can re-enter the trust-all state within minutes of reboot. On cloud-connected systems, the vendor cloud check-in was observed restoring the correct ExpiryDate after approximately 58 minutes. On offline or air-gapped systems, the bypass may persist indefinitely until the registry value is corrected and the driver state is reset.
Defender risk
A defender who only corrects the registry value may believe protection has been restored while the kernel enforcement state remains non-blocking. Recovery guidance should explicitly require registry correction plus reboot/driver reload and validation that a previously blocked canary executable is blocked again.
6. Proof-of-concept validation summary
The proof of concept was validated during coordinated disclosure. Proof-of-concept code was provided privately and is intentionally not being released publicly.
6.1 PowerShell ISE validation
Validation used a known-blocked canary executable, test_bypass.exe, from a standard-user context.
- Before validation,
test_bypass.exewas blocked by CatchPulse as expected. - The validation was performed from a standard-user context.
- The script connected to
\SAAppWhitelistingPortand receivedHRESULT 0x00000000with kernel outBuf status0x00000000. - After validation, the same
test_bypass.exeexecuted without being blocked. - The observed behavior confirms an end-to-end application-whitelisting enforcement bypass from a standard user context.
7. Remediation recommendations
7.1 Apply admin-only DACL to \SAAppWhitelistingPort
Change the a9 argument for \SAAppWhitelistingPort from 0 to 1 in the DriverEntry port-creation path so the default admin-only security descriptor is retained. Apply the same hardening to \SAAppCtlNotifierPort unless unrestricted access is explicitly required and safe by design.
7.2 Add explicit privilege checks to cmd=6 and cmd=12
The dispatcher should apply the same privilege gate used by commands 2, 3, 10, and 14 before allowing cmd=6 or cmd=12 to write machine-wide state. The command handler should fail closed if the caller is not SYSTEM, LocalService, NetworkService, an administrator, or another explicitly authorized principal.
7.3 Recovery and detection guidance
- Monitor unexpected writes to
HKLM\SYSTEM\CurrentControlSet\Services\SAPlus\ExpiryDate, especially writes resulting in past dates or all-zero values. - Monitor service logs for
License is expired/trust allevents occurring shortly after boot or outside legitimate license transitions. - Treat registry-only correction as insufficient. Recovery should include correcting the registry value, rebooting/reloading the driver, and validating that a known-blocked canary executable is blocked again.
- Review allow-rules for
MSBuild.exeand similar LOLBAS executables as a temporary risk-reduction step, but do not rely on policy restrictions as the primary fix.
8. Timeline
| Date | Event |
|---|---|
| 2026-06-23 | Vulnerability reported. |
| 2026-08-06 | Public disclosure. |