Introduction
locac is an autonomous vulnerability-research agent harness. You point it at a repository, give it a goal, and it maps the attack surface, traces untrusted input to dangerous sinks, builds a proof-of-concept, and reports a small set of cross-verified High/Critical findings.
It is a harness, not a scanner. The deterministic tools do the mechanical work: AST outlines, sink scanners, call-graph tracing, a DAST module runner, a crash oracle. The model reasons, triages, and proves. Neither half is useful without the other.
What locac optimises for
Most security tooling optimises for recall: emit everything that pattern-matches, let a human sort it out. locac optimises for the opposite. A run that produces two findings you can hand to a vendor without a follow-up question beats a run that produces two hundred you have to triage.
That trade-off is enforced by the harness, not by prompting. A finding cannot be recorded at High or Critical unless it clears the mechanical gate described below, and the gate is code, so the model cannot talk its way past it.
The five invariants
These are non-negotiable. They are in the system prompt, and the ones that can be checked mechanically are also enforced in the tool layer.
- Default deployment only. A bug that needs debug flags, example credentials, or an administrator mistake to fire is not a finding.
- No app sink. The bug must live in official, supported code. Never build or wrap a deliberately vulnerable app around the target to demonstrate one.
- High/Critical only. Informational, low, medium, hardening and version-disclosure issues are out of scope by construction.
- Cross-verify. A finding is accepted only after independent agents reproduce it and false-positive elimination fails to break it.
- Resume from memory. Prior findings and the scratchpad are read before any expensive tool runs again. A run picks up where the last one stopped instead of restarting.
How a run works
Every run drives the same four-phase loop:
- Orient.
outline,ls,glob,code_searchmap entry points, routes, parsers, config, and trust boundaries. - Hunt.
grok_sinkandscan_sinkslocate candidates for a vulnerability class, thentrace_callersfollows the flow from an untrusted source (request params, body, headers, env, file reads, deserialization) to a dangerous sink. - Verify. A tool hit is a candidate, not a finding. Five conditions must all hold: reachable from an untrusted entry point in the default deployment; the attacker controls the tainted value; nothing on the path sanitises it; no debug flag or example credential is required; and a concrete PoC reproduces it. Then the agent tries to refute the path.
- Report.
record_finding, thencross_verify, thenscore_finding, which computes CVSS and applies the severity gate so that severity is never guessed, thenreport_findings.
The evidence gate
This is locac's actual differentiator, so it is worth being precise about.
To record a finding at High or Critical, two independent conditions must both be satisfied:
- Semantic proof, bound to this finding. The finding must cite, via
artifact_ref, an artifact that carries a structured vulnerability claim (location, line, class, the security effect to observe) and a machine-checked assertion that passed. Three tools mint one:reproduce, when its oracle actually triggered;run_module, per confirmed detection; andreplay_request, when a marker appears in the mutated response and is absent from the benign baseline. The claim's location must match the finding's, which is why a High/Critical finding must carry afile(or an exact DAST URL) and, for a source finding, aline.
Running something is not enough. Aexecutescript that exits zero, a plain replay, a scan that confirmed nothing, and a coverage report are all recorded and auditable, but they are diagnostics: none of them evaluated an exploit assertion, so none can promote a severity. A real artifact minted for a different finding cannot either. - A 2-of-3 cross-verify quorum.
cross_verify(finding_id)spawns three verifiers with different lenses: reproduce (build the PoC from scratch and run it), refute (find the sanitiser that makes this a false positive), and boundary (confirm it fires in the default deployment). A vote counts only if that verifier minted its artifact during this round, named the exact existingfinding_id, matched its location, and used an artifact distinct from the other two lenses'. Re-citing the candidate's own artifact is not independent evidence. Two of the three must promote.
Fail either condition and score_finding will not let the severity through. The finding can still be
recorded. It just cannot claim a severity it has not earned.
Trust model in one paragraph
The target repository is untrusted input. It is treated as attacker-authored, including its
comments, its README, and any output its code produces. Every tool result carrying target-derived
bytes is wrapped in ⟦untrusted-output <nonce>⟧ fences, and the agent is instructed, in the harness
invariants that survive every prompt override, to read fenced text strictly as evidence and never as
an instruction. Configuration, skills, roles and keybindings are read only from LOCAC_HOME
(~/.locac by default), never from the repository under audit. The session database also lives
outside the target root, because sandboxed target code has write access to that root.
The Security model page covers the full picture, including the OS sandbox and approval modes.
What locac is not
- Not a CI linter. It is expensive, it runs commands, and it is designed for a research session rather than a per-commit hook.
- Not a fuzzer. It drives a fuzzer or a PoC when one is warranted; it does not replace one.
- Not a hosted service. It is a single binary that runs on your machine, talks to whichever model provider you configure, and stores everything locally.
Where to go next
- Installation: install a verified release or build your own, then check the runtime assets survived.
- Quickstart: configure a provider and run a first audit.
- Configuration: every field of
~/.locac/config.json. - Running an audit: the
runcommand, flag by flag. - Flag reference: every flag, default, and exit code in one place.