Security rules · inferred from your code · deterministic · bring your own model

Find where your code breaks its own security rules.

A linter ships rules someone wrote, for the weaknesses someone already enumerated. doloop infers the guard your own codebase pairs with each risky operation, from its own consistency, and flags the change that drops it. The same reading re-derived the Heartbleed bug from OpenSSL's own bounds-checking, with no rule written in advance.

Inferred, not configured

A scanner with a fixed ruleset fires the same checks on every codebase, whether or not your code agrees with them. doloop does the opposite. It reads how your codebase already protects itself: for each risky operation, the guard that the surrounding code pairs with it, learned from the rate at which they appear together. Then it flags the one change that performs the operation without the guard the rest of the code keeps. Both the risky operation and the guard are inferred from your code, never hardcoded. Below the inference floor, where your code keeps no consistent guard, nothing is inferred and nothing fires.

It speaks only where your code set the rule

The same shape means different things in different codebases, and a security tool that ignores that is a tool you end up muting. A value used to index a buffer is a real risk in C, where an unchecked index reads past the end of memory, and a non-issue in Python, where a bad index raises rather than overreads. doloop reads which house it is in:

A function indexes a buffer with a parameter, no bounds check
→ in a codebase that bounds-checks its buffer reads (OpenSSL): doloop FLAGS it, because the house keeps the rule and this change broke it
→ in a codebase that never bounds-checks its subscripts (Python): doloop is silent, because there is no rule here to break

That is the Heartbleed catch, generalized. OpenSSL bounds-checks before its buffer reads, so the one access that does not is a real violation of the house's own discipline. Python is memory-safe and never bounds-checks its subscripts, so the same shape owes silence. The tool calibrates to the codebase, which is the thing a fixed ruleset cannot do, and the reason it does not cry wolf.

Editable, deployable, verifiable

Why security is the sharpest case

A value is often two things at once: a trusted size in one reading and attacker-controlled input in another, and the vulnerability lives in the gap between the two. The codebase guards it almost everywhere; the bug is the one place it does not. Reading a codebase as the set of conventions it keeps, and flagging the place a change breaks one, is exactly the shape of finding that gap. Heartbleed is the canonical instance, and it fell out of OpenSSL's own consistency.

Stated plainly, so it can be trusted:

It is the inferred complement to a linter, not a replacement. It catches the project-specific guard a rule library has no line for. It checks for the absence of a guard the codebase keeps; it does not certify the code is secure, and below the floor it owes silence.

On a codebase that already holds its security conventions tightly, it surfaces little. The validated reading has near-zero recall on hardened code, because there are few gaps left to find. Its value is on the codebase that keeps a guard almost everywhere and drops it in one place.

Today it runs as an advisory reading in the gate, alongside the convention checks. It flags, with the line and the inferred rule; promoting a rule to block on your codebase is the next step, measured on your own accept-and-reject history so the block rate is yours, not a generic threshold.

See it on your code

We are taking on a small number of teams who want a deterministic security reading that calibrates to their own codebase. You get a free, instrumented run: the guards your code already keeps, and the places a change would drop one. Your source never leaves your machine. Bring your own model.