Oninit® Snooper — SQLI Protect Mode
Snooper is normally a passive observer. Protect Mode is an optional inline mode that validates application→server SQL Interface traffic before it reaches Informix, as a compensating control for CVE-2026-13361. A request that fails validation is never modified and never forwarded: the permitted actions are ALLOW and REJECT, never REPAIR.
Protect Mode arrives in the forthcoming v4.0 release, alongside TLS proxy comms. The current v3.0 download does not include it.
Read this first — Protect Mode is an intrusive change
Enabling Protect Mode changes what the snoop does to production traffic. In every other mode Snooper cannot affect the session it is watching, which is why it is safe to attach to a live system. Protect Mode removes that guarantee: it sits in the request path, holds traffic, and terminates connections. Plan and change-control it like any other inline network device — not switched on to “see what happens”.
| Impact | What actually changes |
|---|---|
| It becomes inline | The snoop stops being observe-only on the application→server path. A fault or a false positive now affects the application, where previously it could not. |
| It adds latency | Requests are held until fully received and validated. The zero-latency property — the reason Snooper is safe to leave attached — does not apply on this path. |
| It kills connections | A block does not reject one statement. It returns SQLCODE -999 and tears down both the client and upstream connections. Anything holding a transaction open loses it. |
| It fails closed | Protection also terminates when it cannot establish safety — an unrecognised token, lost parser state, a request that never completes. Legitimate but unusual traffic can trip these. |
| It buffers per connection | Each protected connection can hold up to 4 MiB in flight. Memory now scales with concurrent connections in a way it did not before. |
| It changes the write pattern | Forwarding moves from once per network read to once per request, so a burst of small requests costs more system calls than before. |
None of this argues against the feature. An unpatched CVE-2026-13361 is remote code execution as the oninit user, which is worse than any row in that table. The point is that the trade is real and should be made deliberately.
Deploy in detect mode first
Because a false positive kills a live connection rather than rejecting a single statement, the supported path to production is to measure before you enforce. Run --protect-detect first: it validates and logs exactly what --protect would have blocked, but forwards the request anyway and never terminates a connection. Watch the SECURITY_BLOCK log against your own traffic; once it is clean for your workload, promote to --protect. Detect mode still carries the latency and buffering costs above.
What it protects against
CVE-2026-13361 is a stack-based buffer overflow (CWE-121) in the Informix SQL Interface. Per the advisory, sq_sgkprepare does not adequately validate a client-controlled length against the capacity of its destination stack buffer, and an admitted client — one that has already authenticated — can exploit this for remote code execution in the security context of the oninit process. Affected versions are 14.10, 12.10.x and 15.0.
The advisory's own mitigation section prescribes exactly this control:
“Place an SQL Interface-aware intrusion prevention system in front of the listener. Reassemble complete requests and reject messages whose declared length exceeds the protocol maximum or does not match the actual payload length.” — “Acts as a virtual patch by preventing malformed length values from reaching sq_sgkprepare.”
Protect Mode implements both rules. Blocks arising from them are logged with rule=CVE-2026-13361; blocks arising from Snooper's own protocol hygiene are logged as rule=structural, so an operator triaging an event can tell the two apart at a glance.
What is unaffected
The impact is scoped deliberately. The server→application path keeps the original immediate-forward behaviour and is never held or validated, and with protection disabled Snooper is byte-for-byte the tool it always was. Existing monitoring deployments are unaffected.
Binary data is allowed — this validates framing, not content
A common worry with an inline filter is that it will reject legitimate binary payloads — bound parameters carrying raw bytes, BYTE / TEXT / BSON column data, embedded NULs. Protect Mode does not. It inspects the request's length and framing, never its content. There is no printable-character rule, no signature match, no byte-value restriction.
Here is a well-formed request whose statement payload is arbitrary binary — it contains a NUL, a high byte, and a control byte. The declared length (0x00000008) matches the eight bytes that follow:
00 02 token = SQ_PREPARE
00 00 bind_count
00 00 00 08 declared length = 8 bytes
00 01 02 FF FE 7F 80 0A payload (arbitrary bytes, incl. NUL / 0xFF / ctrl)
00 0C end of transmission
verdict: ALLOW — length is non-zero, within the configured maximum, and
matches the payload present. The eight payload bytes are
never examined.
The only things that cause a block are a length that is zero, a length above the configured maximum, or a length that does not match the bytes actually present. That last case is the shape CVE-2026-13361 exploits: it is a property of the length field, not of the data, which is why a content or signature filter would miss it and why the advisory calls for length validation.
The reject frame
When a request is blocked in enforce mode, the client does not simply see its connection drop. Snooper first sends back a well-formed Informix error response carrying SQLCODE -999, so a client that understands the SQL Interface reports a real error rather than an unexplained disconnect:
00 0D token = SQ_ERR
FC 19 sqlcode = -999 (int16; 0xFC19)
00 00 isam = 0
00 00 00 00 offset = 0 (u32 on a negotiated 9.0342+ session;
narrows to u16 pre-9.0342)
00 27 message length = 39
52 65 71 ... "Request blocked by Snooper SQLI Protect"
00 even-pad (message length is odd)
00 0C end of transmission
The message is fixed and generic on purpose. The internal reason for the block — which length check failed, what value was declared, how many bytes were present — is written to Snooper's own SECURITY_BLOCK log, never to the client. A blocked caller learns that it was blocked, not how validation works or what the limits are. After the frame is sent, both connections are torn down; delivery of the error never takes precedence over the block.
Current limitations and configuration
- A compensating control, not a fix. Protect Mode reduces exposure while you schedule the vendor update; it is not a replacement for IBM's fix (14.10.xC13W13 / 15.0.1.14). Apply the update when you can.
- The statement-length ceiling is operator-tunable. The protocol does not publish a single maximum — on a modern negotiated session, statements larger than 64 KiB can be legitimate. The ceiling is set with --protect-max-sql (default 1 MiB); size it to the largest statement your application legitimately issues, which detect mode will show you.
- Legacy servers. The length-field width follows the negotiated protocol. Against a genuinely pre-9.0342 server, set --sql-len-width u16; modern servers (all affected versions) need no change.
- TLS. Protection operates on the decrypted SQL Interface stream, so it behaves identically for plaintext and TLS transports.
Scope
Protect Mode validates SQL Interface protocol framing only. It is not a SQL injection detector, does not inspect or allowlist statement text, does not fingerprint queries, and does not analyse user privilege. Those are different problems and belong in a different feature.