This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
GitView CodeAudit is a security review for Go backends that runs on your laptop. A static analyzer finds the problems and collects the evidence; an open-weight model, Gemma running on Ollama, explains a finding when you ask, but it never decides one.
GitView started as my terminal tool for watching Git changes and studying Go code: call graph, data flow, SQL operations and HTTP routes, each with the evidence behind it. This week I built CodeAudit on top of those analyses.
Who would pay for it? Freelancers and small agencies that build Go APIs for clients. Clients ask for a security review before a launch, a funding round or a big customer's due diligence, and they pay for it. But that code usually comes under an NDA, and pasting it into a cloud AI tool is exactly what the contract forbids. CodeAudit lets one developer do that review on their own laptop and hand over a real deliverable: an offline HTML report with each finding, the path that reaches it, the evidence, and the reviewer's decision with its justification.
That is the side hustle: the client pays for the review, and producing it costs nothing per token.
Every finding answers the questions a client will ask:
- Where? File, line and function.
-
Why? The rule, and the data that reaches the line, for example
c.Query("q")→"... LIKE '%" + term + "%'"→db.QueryContext. - How is it reached? Every HTTP route that leads there, through each middleware, marking the one that authenticates.
- How sure are we? Severity, confidence and verdict are separate fields. A possible IDOR is shown as Review Required — Authorization Not Established, never as "IDOR confirmed".
- How do I fix it, and how do I test the fix?
- What did we decide? Open → Investigating → Confirmed / False Positive / Accepted Risk / Fixed, with a history of every change: its date, its justification and the commit it refers to.
Demo
GitView is a local tool, so there is no deployed link: everything below runs on your machine. The repository ships a small vulnerable API, with safe variants of each case, that the tests use. You can reproduce these screenshots with it:
git clone https://github.com/Darrkkens/gitview && cd gitview && go install . # Go 1.25
gitview audit scan --module internal/audit/testdata/app
gitview audit serve --module internal/audit/testdata/app # opens 127.0.0.1 in the browser
A SQL injection: the route, the middleware chain and the handler lead to the query, and the inspector shows the evidence.
The same finding explained by Gemma. Each evidence ID the model cites is checked against the analysis.
A possible IDOR is a review, not a verdict. The resource ID comes from the request and the query has no owner or tenant condition, but authorization could live somewhere the static analysis cannot see.
The report you hand to the client is a single offline HTML file. It has no network access, a strict CSP, and only bounded, redacted excerpts of the code.
Code
GitView
Monitor de alterações Git em tempo real no terminal. Cada arquivo modificado pode ser expandido ou recolhido individualmente, e os diffs se atualizam sozinhos. Inclui busca global nos diffs, exportação de relatórios, execução de testes, Code Flow e o Go Deep Inspector, para estudar código Go com evidências verificáveis.
go install .
gitview [opções] [diretório]
| Opção | Descrição |
|---|---|
--delta |
Renderiza diffs com git-delta (alternável com d) |
--expand |
Expande automaticamente arquivos novos |
--interval 2s |
Intervalo do polling de segurança |
--no-watch |
Desativa fsnotify e usa apenas polling |
--export-dir DIR |
Diretório padrão dos relatórios (também GITVIEW_EXPORT_DIR) |
--test-timeout 10m |
Tempo limite de uma execução de testes |
--ascii |
SĂmbolos ASCII (tambĂ©m GITVIEW_ASCII=1) |
Atalhos
? mostra a ajuda da tela atual.
Mouse: a roda rola o diff; clicar numa dica do rodapé (por exemplo x Exportar) equivale a pressionar a tecla; na exportação, clicar num formato, escopo ou caixa [x] escolhe ou…
-
internal/audit: the rules, the taint paths, the review store, the audit diff and the report. -
internal/audit/ai: the Ollama client, the context builder and the validator of the model's answers.
How I Built It
Static analysis first. CodeAudit has 18 deterministic rules for injection, authentication, authorization, sensitive data, configuration and dependencies. They run over analyses GitView already had: go/packages, go/types and SSA for the call graph and the data flow, the SQL operations, and the HTTP routes with their middleware chains.
- Taint: a taint finding is the shortest path in the data flow graph from an HTTP input to a sink.
-
Sanitizers: they only count when their meaning is known.
strconv.Atoineutralizes everything andfilepath.Baseneutralizes paths; an arbitrary function call is not a sanitizer. -
Checks: an
ifthat dominates the sink and examines the value, likeif !allowed(origin), turns "vulnerable" into "review", because the analyzer cannot prove the check is sufficient. - Authorization: a 403 only counts as authorization when the request is already authenticated. A 403 from a CORS filter is shown as a request filter instead.
- Dependencies: they are checked only against a local copy of the Go vulnerability database (OSV format). Without one, the report says "dependencies not checked" instead of pretending, and a database older than 30 days is flagged as possibly out of date.
Gemma on Ollama, kept on a short leash.
-
Model: by default GitView picks the smallest installed Gemma model (
gemma3:4bon my machine). It never downloads one, and it refuses any endpoint that is not on this machine unless you pass--ai-allow-remote. - Context: the context sent to the model is built from the analysis, not from a file dump. It holds the finding, its evidence, the route path and the function's code, within a budget of about 6,000 tokens. Secrets are redacted, and the repository's comments and strings go in as data, never as instructions.
-
Answer: Ollama's structured outputs (
formatwith a JSON schema) shape the reply. Every evidence ID, file, line and symbol the model cites is validated against the context, and a citation that does not exist is shown as rejected. - Cache: answers are cached by context hash, model digest and prompt version.
- No authority: the model can recommend a review state, but it cannot change one. The reviewer decides.
Being honest about the model. On my CPU-only laptop, one explanation from gemma3:4b took between three and a half and five minutes (215 s and 310 s in two runs), and gemma3:12b did not fit in the free memory. The prose is useful but not perfect; in one test the model expanded "IDOR" incorrectly. That is exactly why the model is not allowed to decide anything and why its citations are checked.
Testing without a model. The test suite never needs a real model. It runs against a simulated Ollama, including answers that cite evidence that does not exist. The fixture app has one case per rule plus its safe variant (Atoi before the query, filepath.Base, a tenant filter, an admin route that answers 403, a secure cookie…), and the test fails on any unexpected finding.
Dogfooding found my own false positives. Running CodeAudit on GitView itself flagged three "hardcoded secrets". They were descriptions like credential = "Authorization header". The rule now skips values with spaces, the fixture has that case, and the rule documents what it misses because of it: a hardcoded passphrase.
I built this with Claude Code as my pair, from the spec to the browser tests.
Why Does Open Innovation Matter?
- The code cannot leave. For a review under an NDA, a model I run myself is the only way AI can touch the code at all. A closed API is simply not an option here.
- The economics work. A fixed-price review cannot absorb a per-token bill that grows with the size of the codebase. On a local model, each explanation costs electricity.
-
No lock-in. Swapping models takes one flag (
--model), and the validator does not trust any model, so a better open model is a drop-in upgrade. - The client can audit the auditor. The investigator's prompt, the answer schema and the validator are in the repository. A client can check exactly what was sent to the model: a bounded, redacted context built from the evidence.
My First User
The first real codebase it audited was my own: the Go backend of a production SaaS I maintain, with 134 HTTP routes. The whole analysis took about a second and a half, and CodeAudit reported 16 findings, none of them a confirmed vulnerability:
- 4 public routes of the authentication flow that write to the database, shown as Review Required — No Authentication Identified. A login route is public by design, which is exactly why the rule asks instead of accusing.
-
1 CORS middleware that reflects the
Originwith credentials, but only after an allow-list check. It is a review, and the inspector points to the check itself. - 11 SQL statements built at runtime whose origin the data flow could not determine. They are reported as info instead of being silently dropped, so the reviewer knows where the analysis stopped.
The first version was much noisier, and fixing it on real code shaped the rules:
- A CORS filter that answers 403 counted as authorization on every route, which hid the authorization rule entirely. A 403 now only counts after authentication.
- Once that was fixed, the authorization rule flagged login routes, webhooks and reference-data tables. It now skips handlers that authenticate themselves, and it reads the SQL migrations to know which tables have an owner or tenant column.
Prize Categories
- Best Use of Gemma: Gemma, running locally on Ollama, is the AI Security Investigator. It explains findings and paths from the static evidence, its answers are schema-constrained, and every citation is validated.
This post and the code it describes were written with the help of AI (Claude Code).




Top comments (0)