Security scanning my own code with Scrutineer and local coding models Open source maintainer Anil Madhavapeddy deployed Scrutineer, a security scanner from the Alpha-Omega project, to proactively find bugs in his code, using a local GLM 5.3 Flash model on his Mac Studio after being blocked from frontier models without guardrails. Scrutineer, which supports multiple coding model backends, scheduled agent scans via ephemeral Docker containers and found many bugs, with initial triage of cohttp taking Claude Opus about 13 minutes and 18 agent turns. After the recent surge of security reports https://anil.recoil.org/notes/rumour-is-the-exploit in my projects, I wanted to help us open source maintainers use scanning tools to find bugs before the bad guys do. Luckily, Andrew Nesbitt https://nesbitt.io leapt in enthusiastically https://amok.recoil.org/@andrewnez@mastodon.social/117150259002007792 with Scrutineer https://github.com/alpha-omega-security/scrutineer , a new project he's working on to help maintainers proactively manage the flood. I decided to give it a quick spin. By default, Scrutineer supports a number of different coding models, but I remain blocked on access to frontier models https://www.anthropic.com/glasswing without security guardrails for our own code. Therefore, I decided to get a local coding model powered by GLM 5.3 https://huggingface.co/zai-org/GLM-5.3-Flash running on my own Mac Studio. Read on if you want to set up your own instance; Scrutineer is worryingly good at finding lots of bugs Scrutineer https://github.com/alpha-omega-security/scrutineer is a scanner built under the Alpha-Omega https://alpha-omega.dev project. It lets me add a Git repository or a whole org of them, and then schedules a big pipeline of agent scans via a swarm of ephemeral Docker containers. These scans include a first triage pass, then metadata analysis, dependency and SBOM extraction, static analysis with tools like semgrep https://semgrep.dev/ and zizmor https://docs.zizmor.sh/ , defining a threat model, and then a security deep-dive that does hours of analysis. A web UI organises the often raw results for human triage, with a workflow designed to avoid flooding maintainers with low-quality reports https://alpha-omega.dev/blog/scrutineer-scanning-open-source-without-flooding-maintainers/ . The agent CLI of choice is quite pluggable with Claude Code by default, with Codex, OpenCode and Copilot as alternatives only one backend can be active at a time . Andrew kindly added an OCaml runner profile https://github.com/alpha-omega-security/scrutineer/pull/901 days after my earlier post https://anil.recoil.org/notes/2026w34 , so OCaml repositories now also have a specialised scanning container with our toolchains like opam installed. I deployed it on an exe.dev https://exe.dev VM, a service I'm fast becoming a fan of https://anil.recoil.org/notes/2026w30 due to its nice CLI and convenient HTTPS proxies. Scrutineer runs as a dedicated host process there, as every scan it does spawns a fresh Docker container so there's no point running the service itself in a container. The UI doesn't have any auth of its own, so for now it's using exe's authenticated HTTPS tunnel https://exe.dev/docs/proxy . I'm not sure how to set up a 'production' multiuser version of this yet, but it's early days and I return to this below https://anil.recoil.org/ figuring-out-usable-workflows-here . Deploying it was extremely simple by following the docs, despite it being under rapid development. I submitted a minor fix to the Dockerfile 949 https://github.com/alpha-omega-security/scrutineer/pull/949 and upgraded git-pkgs https://github.com/git-pkgs/git-pkgs to the latest one with opam support I bootstrapped the instance with the default Claude Code backend just to get going. Its initial triage of cohttp took Claude Opus about 13 minutes/18 agent turns, with the lighter skills completing on Sonnet in seconds. I then switched the instance to an OpenCode backend, pointed at a GLM 5.3 Flash Q4 model served from my Mac Studio by my ocaml-deepseek https://tangled.org/anil.recoil.org/ocaml-deepseek inference engine the glm-5.3 branch , which I previously described https://anil.recoil.org/notes/language-integrated-llms . This exposes an OpenAI-compatible endpoint, and Scrutineer's per-scan proxy routes each container's traffic to it. I was a little sad that I couldn't keep both Claude and OpenCode simultaneously active, though. Using the local model is much slower than Claude as I've done absolutely no performance tuning yet and for some reason, Spotlight is chewing up 100% CPU on my Mac Studio in the Golden Gate beta . I got decode speeds of around ten tokens per second, so I raised the scan timeout to eight hours to let the security deep-dives complete. While this seems slow, it's totally fine for security scans as I just left them running overnight and there's no marginal cost per scan with local models given cheap nighttime renewable electricity. Sadiq Jaffer https://toao.com is going to install GLM 5.3 on our beefy 4-GPU machine in a few days to give us a speedup, but this is fine for now. The first repo was cohttp as that was the last one I issued an advisory https://osv.dev/vulnerability/OSEC-2026-16 for. The generated scan configuration first uses an agent to map its attack surface file by file, and so in the case of an HTTP parser it figured out that it needed to cover the request-line parser, the chunked transfer decoder, cookie and authorisation header parsing, and the lex/menhir grammar behind content negotiation. This is actually quite a good summary that would double as an onboarding doc for a new contributor I picked a real 'harmless' finding for the purposes of exposition here, since I obviously don't want to talk about potential real bugs. In this case, the agent decided that the COHTTP DEBUG environment variable is tested for presence rather than its value, so setting it to 0 or the empty string still enables full wire logging. I don't really care enough to fix this; the agent got alarmed that it logs authorisation headers to stderr, but this is strictly a debugging flag as the name implies so my judgement is that it's fine as is. Note that this might not always be true: if an attacker could somehow inject environment variables as part of a chain attack, they might suddenly be able to use this to retrieve some valuable auth tokens. Scrutineer then hands this over to a 'disclosure' workflow where it uses another agent to independently verify the bug and/or draft a vulnerability disclosure. I'm pretty convinced I want to put more time into using Scrutineer now. Here are some notes in no particular order about what's needed to do a bigger deployment. As I type this, I left it running over the weekend on 10 more repositories and it found over 100 potential issues that need triaging The coding model backend is currently instance-wide as far as I can tell, so once I switched to OpenCode I could no longer mix in Claude or Codex. It would be quite nice for routine security deep-dives to run overnight on the local model, but then to push promising fixes to a frontier model since those fixes usually aren't blocked by the cybersecurity guards, just the act of finding them . Since the Scrutineer UI doesn't have a login of its own, the exe.dev proxy is the only access control on a deployment like mine. I do this by running ssh exe.dev share add scrutineer