This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
I'm a 200-level cybersecurity student in Nigeria, and I recently passed the ISC2 Certified in Cybersecurity (CC) exam. Around me, campus tech clubs and freelance developers keep shipping student portals: election systems, hostel management, grade lookups. As far as I can tell, almost none of them get a security review before launch. I wanted to sell that review as a side hustle.
I got stuck on three things almost immediately.
First, I can't paste a client's code into a cloud LLM. Source files, config files and database credentials belong to the client, and once student records are involved, data protection law applies too (FERPA in the US, the NDPA in Nigeria). I'm not a lawyer. My working rule is that client code stays on hardware I control.
Second, the scanners that exist are built for security teams. Run a standard one and you get a long XML or CVE dump that a campus sysadmin will never read.
Third, per-token pricing. A review priced for a student club can't absorb an API bill every time I re-scan after the client fixes something.
EduGuard is what I built to get around all three. It runs fixed checks first, then asks a Gemma model running on my own server to write the fix for each thing the checks found. You give it a folder or a domain, pick which of six template packs to run, and get a graded report from A to F. Each finding comes with a plain-English summary for the school board and a git-style diff for the developer. The report exports to CSV or PDF, which is the thing I would hand a client.
The packs map to OWASP ASVS v4.0 controls. This is what runs today:
| Pack | Target | What it checks |
|---|---|---|
| 1. Subdomain and email spoofing | live domain | whether a DMARC record exists, and whether its policy is only p=none (monitor mode) |
| 2. Transport and headers | live domain, nginx configs | HSTS header, cookie flags, nginx listening on port 80 with no HTTPS redirect |
| 3. Exposed configs | folder | committed .env files, APP_DEBUG=true
|
| 4. Injection | folder | SQL queries built with string interpolation |
| 5. Access control | folder | student-record routes with no session check |
| 6. Uploads and student PII | folder | upload handlers with no file type validation |
These are pattern rules, not a full code analysis. They miss things a human reviewer would catch, and they can flag harmless code. That is also why I never ask Gemma to go looking for bugs.
The clients I have in mind are campus tech clubs, small colleges, and the student developers who build portals for them. The pitch is a fixed-price pre-launch audit with a report their IT office can actually read.
Demo
Live: eduguardauditor.onrender.com
It runs on Render's free tier, so if nobody has opened it for a while the first load can take up to a minute while the instance wakes up. Open the audit page, scan the bundled ./demo_target folder or a domain you own, and pick a model from the navbar. Please only scan domains you own or have permission to test.
The demo folder is a deliberately vulnerable sample portal included in the repo: a SQL-injectable grade lookup, no session check, an upload form that accepts any file, and an nginx config with no HSTS. Scanning it returns six findings and a grade of F.
Gemma does not run on Render. The free instance is far too small to hold a model, so the model runs through Ollama on a server I control, reached through a Cloudflare tunnel. When the app can't reach it, the AI summary starts with [Local AI Fallback] and gives generic guidance instead of a Gemma-written patch.
Demo Video
Code
EduGuard
Pre-launch security audits for school portals, with a Gemma model running on hardware the auditor controls.
EduGuard runs fixed, deterministic checks against a codebase or a live domain, maps every finding to an OWASP ASVS v4.0 control, and then asks a locally hosted Gemma model to write a fix for each verified finding. The output is a graded A to F report with a plain-English summary for a school board and a git-style diff for the developer.
Built by @wilcardjayx for the Hacktoberfest Open-Source AI Challenge, Week 2: Side Hustle (October 2026).
Live demo: eduguardauditor.onrender.com
The demo runs on Render's free tier. If nobody has opened it recently, the first load can take 30 to 60 seconds while the instance wakes up.
Contents
- Why it exists
- How it works
- Template packs
- Quick start
- API
- Configuration
- Project structure
- Tests
- Security and responsible use
- Known limitations
- Roadmap
- License
Why it exists
…Apache 2.0. The repo includes a built front end, so you only need Node if you change the UI.
git clone https://github.com/wilcardjayx/eduguard-auditor.git
cd eduguard-auditor
pip install -r requirements.txt
# local model
curl -fsSL https://ollama.com/install.sh | sh
ollama pull gemma2:2b # or: ollama pull gemma4:e4b
python app.py # http://localhost:8000
You can also skip the UI and call the API directly. This scans the sample portal with the source code packs:
curl -X POST http://127.0.0.1:8000/api/scan \
-H "Content-Type: application/json" \
-d '{
"target": "./demo_target",
"scan_mode": "source_code",
"selected_packs": ["pack_3_configs", "pack_4_sast", "pack_5_rbac", "pack_6_privacy"],
"model_name": "gemma2:2b"
}'
Three tests in tests/test_eduguard.py cover the six checks on the sample portal, the AI fallback path, and the HTML report export. The part worth reading is ai_engine/gemma_remediator.py.
How I Built It
Deterministic first, Gemma second
My first idea was to hand a repo to a model and ask it to find bugs. I dropped that quickly. Models invent findings, and reading a 10,000-line repo takes a long time on a CPU. So the scanners are plain Python rules, and Gemma never hunts. It gets one verified finding at a time, with its evidence and the ASVS control it maps to, and writes three things: a short summary for a school administrator, a replacement snippet, and a unified diff.
The prompt tells the model that the finding text is untrusted data and that it must not follow instructions inside it. That text comes from the files I'm scanning, and a hostile file could try to talk to the model.
Two Gemma sizes
I run Gemma through Ollama and let the user pick gemma2:2b or gemma4:e4b from the navbar. The 2B model is for quick triage. The e4b model is for when I'm willing to wait for better patches. My server has no GPU, so the difference in waiting time is real. A call that runs too long times out, and that finding falls back to generic guidance instead of hanging the whole audit.
Running the model behind a tunnel bit me once. The first call after the model has been idle has to load several gigabytes into memory, and that first call could outrun the tunnel's request timeout, so a working pipeline looked broken on the first try.
The rest of the stack
FastAPI runs the scan, picks scanners based on the target, and calls Ollama over its HTTP API. The front end is React 19 and Tailwind: a Board view for the plain-English summaries, a Dev view for the diffs, a history drawer, and CSV and PDF export. Each Gemma call runs inside a Sentry span so I can see latency per finding. Sentry stays off unless SENTRY_DSN is set.
Where it falls short
Pack 1 covers half of email spoofing protection. It flags a missing DMARC record and a weak p=none policy, but SPF is listed in the template and not implemented yet. The header checks can mistake a CDN block page, like a 403 from Cloudflare, for a missing header, so a site behind a firewall can look worse than it is. Packs 3 to 6 need source code, so they say nothing about a live site. And the fixes Gemma writes are drafts to review, not patches to paste: I have seen it produce a malformed DNS record name. I'm working on the rest.
Why Does Open Innovation Matter?
- The whole job depends on not sending client code anywhere I don't control. With an open-weight model the weights run on my own server, so scanning a client's repo produces no prompt for a third party. I can tell a client that plainly, and they can check it by watching where the traffic goes. Scanning a live domain still sends ordinary DNS and HTTPS requests to that domain, which is the point of the scan.
- Cost is the other half. Closed APIs bill per token, which is awkward when the work is lots of small re-scans. Running Gemma costs me a fixed monthly server bill that I already pay for other security work, so a re-audit after the client fixes something costs nothing extra. Local is not free, though. It is slower than a cloud model, and my CPU-only box makes that obvious.
- Then there is control. The weights don't change under me. A provider can retire a model, or tighten a filter that starts refusing security prompts, and my scanner would break overnight. Mine can't do that, and switching sizes is a dropdown.
- A bigger cloud model would probably write better patches than a 2B model. For client work I'm choosing control over polish, and because the checks are deterministic, the model only has to write a fix, not find the bug.
Prize Categories
- Best Use of Gemma: Gemma runs locally through Ollama in two sizes you can switch between. It only writes fixes for findings the scanners already verified, and the app falls back cleanly when the model is slow or missing.
- Best Use of Render: the React front end and the FastAPI API that drives each audit are deployed on Render at eduguardauditor.onrender.com, while the model stays on my own hardware.
- Overall Challenge Winner: a security audit that a student freelancer can sell to a campus tech club, built on open-weight Gemma so client code never goes to a cloud API.
Built with terminal grit, cybersecurity passion, and ❤️ during Hacktoberfest 2026. Star, fork, or test your own repos on GitHub!



Top comments (0)