DEV Community

Kushal
Kushal

Posted on

SecureLocal AI: A Local-First Python Security Auditor for Hacktoberfest Week 2

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

What I built

For Hacktoberfest 2026 Week 2's Side Hustle challenge, I built SecureLocal AI: an offline-first desktop tool for a first-pass review of Python source code.

The scanner uses Python's built-in AST to flag seven heuristic patterns: dynamic execution, unsafe pickle deserialization, shell-enabled subprocess calls, possible hardcoded credentials, weak hashes, disabled TLS verification in recognized HTTP clients, and dynamically constructed SQL. It scans selected .py files without importing or executing the project, and its findings remain deterministic whether or not a language model is installed.

I tested the application end to end during development. This is an early working tool—not a claim of customer adoption or proven commercial demand.

Who might pay for it?

The plausible buyer is someone who needs a low-friction first review but cannot or does not want to upload source code to a hosted scanner: an independent Python consultant handling client repositories, or a small development team that wants a local triage step before human review. A paid offering might eventually be useful as a supported desktop workflow or team setup, but that is a market hypothesis, not a validated business. I have no paying customers, customer feedback, or commercial validation to report.

Why open innovation matters here

The static scanner is useful on its own. When a developer wants more context, SecureLocal AI can ask a locally running Ollama service to explain one selected finding using the open-weight Qwen2.5-Coder 3B model (qwen2.5-coder:3b). The model is optional; the app does not download it automatically. Install Ollama, start its local service, and pull the model yourself:

ollama pull qwen2.5-coder:3b
python app.py
Enter fullscreen mode Exit fullscreen mode

The client defaults to http://127.0.0.1:11434 and rejects non-loopback endpoints. A normal scan makes no HTTP/API requests. Only after the user explicitly asks for an explanation does the app send a small, redacted finding context to local Ollama—not the project, source file, file path, or report. The model adds advice; it does not set severity, change the deterministic finding, edit files, or apply a fix. Its explanation is unverified and should be checked independently.

Running inference locally avoids per-request cloud-model charges and means source files do not need to leave the machine for this workflow. It is not cost-free: the user supplies the compute, electricity, storage, and initial model download, and local performance depends on their hardware. I have not measured or benchmarked it. Keeping the model choice and inference on the developer's machine also gives users more control than making a hosted model API a required dependency.

How the app works

The Tkinter interface lets me choose a project folder, start a scan, filter results by severity or text, and inspect a finding's rule, severity, confidence, location, redacted evidence, limitations, and remediation guidance. Findings can be exported as JSON or Markdown. Reports include the findings and relative paths, with credential-like evidence redacted; they do not include complete source files.

File discovery and scanning have safety limits and skip symbolic links, generated directories, oversized files, malformed source, and files that cannot be safely read. The app does not write to the scanned project. These controls reduce accidental exposure and unbounded work, but they do not protect against a compromised operating system or malicious local software. Review any report before sharing it.

Demo: screenshots from the repository

SecureLocal AI is a desktop application, so these existing screenshots are the demo rather than a hosted web instance.

Vulnerable scan and finding list

SecureLocal AI showing detected findings

Clean fixture scan

SecureLocal AI showing a clean fixture scan

Finding inspection

Finding details with severity, evidence, limitations, and remediation

Optional local-model explanation

An explanation from the locally running model

The image files are committed under docs/screenshots/. The image links above use their raw GitHub URLs so DEV can render the existing assets.

Testing and limitations

A recorded development result was 51 tests passing, exercising the scanner, rules and redaction, file discovery, exports, Ollama client behavior, and UI paths. The suite includes synthetic fixtures and mocked model responses; passing tests is evidence that those tested behaviors worked, not proof of complete security coverage or real-world detection accuracy.

The rules are heuristics: they can miss vulnerabilities and flag safe code, and they do not establish whether a value is attacker-controlled. This is Python-only first-pass triage, not full data-flow analysis, dependency scanning, a clean bill of health, or a replacement for review by a security professional.

Project and challenge

GitHub Copilot Session
You

attachment:Pasted text #1

Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

I’ve mapped the existing UI to the main app shell and detail panel. The planned edits are confined to ui/main_window.py and ui/finding_details.py: introduce a shared light-theme styling layer, add summary cards for scan totals, modernize the findings table and filter toolbar, and refresh the detail panel while keeping the scanner logic, redaction, and Ollama flow intact.

Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

The redesign is in place; I’m validating the existing suite to confirm the scanner, exporter, and Ollama UI behavior still hold after the visual refresh.

Agent
Agent

Done — I redesigned the Tkinter UI without changing the scanner logic or security behavior.

Files updated:
- ui/main_window.py
- ui/finding_details.py

What changed:
- Modern light-themed security workbench with navy branding, cleaner spacing, and consistent button styling
- Organized project selection + scan controls into a dedicated section
- Added live summary cards for total/high/medium/low findings, with Info shown only when present
- Refreshed filtering toolbar and findings table with better readability, row styling, and severity color cues
- Reworked the detail panel into a structured, readable view for title, severity, rule, evidence, limitations, and remediation
- Preserved the existing scan, filter, export, and local Ollama request flows and error handling

Validation:
- Ran: python -m unittest discover -s tests -v
- Result: 46 tests passed, OK

You

There is a regression after the Tkinter UI redesign.

When I run python app.py and click Scan project on tests/fixtures/vulnerable, the scan results are not displayed. The terminal shows:

_tkinter.TclError: Item finding-6 already exists

The traceback points to:

  • ui/main_window.py, line 267: _process_events
  • ui/main_window.py, line 282: _show_result
  • ui/main_window.py, line 314: _populate_findings
  • self.table.insert(...) Please investigate and fix the root cause.

Requirements:

  1. Inspect _populate_findings(), _show_result(), and the Treeview initialization.
  2. Determine why a Treeview item ID such as finding-6 is being inserted more than once.
  3. Check whether the table is properly cleared before repopulating it after a scan, and whether finding IDs are unique.
  4. Fix the underlying issue while preserving stable selection behavior and any severity tags or row styling.
  5. Ensure repeated scans of the same folder and scans of different folders both work without duplicate-ID errors.
  6. Preserve the summary counts, severity filters, text search, finding details, exports, and local Ollama integration.
  7. Do not change scanner rules, finding generation, security controls, or report schemas to work around this UI bug.
  8. Add or update focused tests if the table-population logic can be tested safely.
  9. Run python -m unittest discover -s tests -v and python -m compileall -q ., and report the actual results. Make the smallest appropriate change. Do not rewrite the UI or modify unrelated files. Do not commit or push anything.

After fixing the issue, explain its root cause and list the files changed.

Agent
Agent

I’ll trace the Treeview creation and repopulation path, then check whether item IDs collide across insertions or stale rows survive a scan. I’ll keep the fix within the UI and focused tests, then run both requested validation commands.

Agent
Agent
Agent
Agent
Agent
Agent
Agent

The duplicate is caused by filtering: _apply_filters() detaches nonmatching rows, but Treeview’s get_children() omits detached rows. On the next scan, clearing only visible children leaves those old finding-N IDs registered, so a new row reuses an existing ID. I’m adding a regression test that exercises this lifecycle before making the targeted cleanup fix.

Agent
Agent
Agent
Agent
Agent
Agent
Agent

The regression now reproduces before the fix and passes after it. The cleanup removes every item ID still tracked by the findings map—including detached rows—plus visible Treeview rows, before resetting the map. I’m running the full test suite and compilation check now.

Agent
Agent
Agent
Agent

Fixed the duplicate Treeview ID regression.

finding-N IDs are unique within each scan because they’re assigned from the finding index. The problem was that filtering detaches rows rather than deleting them, and get_children() doesn’t return detached rows. Clearing the visible rows before a scan therefore left old IDs registered in the Treeview; when the next scan reused an ID, insertion failed.

Added shared table cleanup that deletes rows tracked in findings_by_id, including detached rows, as well as visible Treeview rows. This cleanup runs before both repopulation and scan clearing. Severity tags, row styling, and per-scan IDs remain unchanged.

Files changed
- ui/main_window.py
- tests/test_ui_table.py

Validation
- python -m unittest discover -s tests -v — 47 tests passed
- python -m compileall -q . — passed (no output)

You

Fix the vertical layout and scrolling behavior in the existing SecureLocal AI Tkinter application.

Problem

After the recent UI redesign, the findings Treeview is too short and shows only around three findings at a time, even when the main window is maximized. The finding-details panel occupies too much vertical space. Users must scroll the findings table to see the remaining rows, making the scanning workflow inconvenient.

Inspect the current layout in ui/main_window.py and any relevant UI files before editing.

Required changes

  1. Give the findings table more default vertical space.
  • Configure a useful initial height that shows approximately 8–12 findings when the window is maximized, depending on available screen space.
  • Ensure the table's vertical scrollbar remains usable when there are more findings than fit.
  • Keep the existing columns, severity tags, row styling, selection, search, and severity filtering.
  • Make the details panel use space more efficiently.

  • Avoid allowing the details panel to consume most of the window when the findings table has many rows.

  • Keep finding details scrollable and readable.

  • If appropriate, use a vertically resizable ttk.Panedwindow or another layout mechanism already compatible with the application.

  • Set sensible initial pane proportions so the findings table receives adequate space on startup.

  • Avoid forcing the user to resize panes manually every time the application opens.

  • Make the layout respond correctly to resizing.

  • When the window is maximized, display as many findings as practical.

  • When the window is smaller, allow both the table and details panel to remain accessible with their own scrolling.

  • Prevent the details content from clipping important information.

  • Do not introduce nested scrollbars unnecessarily.

  • Preserve functionality.

  • Do not change scanner rules, finding generation, report schemas, evidence redaction, or Ollama behavior.

  • Preserve the duplicate-Treeview-ID fix.

  • Preserve the severity summary cards, project selection, scan button, filters, AI controls, and export buttons.

  • Do not remove finding details merely to make the table taller.

  • Test the change.

  • Inspect the actual geometry and layout manager used by the existing widgets before choosing a fix.

  • Make the smallest appropriate change.

  • Run python -m unittest discover -s tests -v.

  • Run python -m compileall -q ..

  • Report the files changed and actual test results.
    Do not commit or push anything. Do not rewrite the application or modify unrelated functionality.

Acceptance criteria

After running python app.py on a maximized window with tests/fixtures/vulnerable selected, the findings table should show substantially more than three rows—ideally 8–12 where screen dimensions permit—without requiring the user to drag its scrollbar. The details panel must remain usable, and all findings must still be reachable by scrolling.

Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

The geometry confirms the source of the cramped table: the main content is correctly given the expanding grid row, but its vertical ttk.Panedwindow currently allocates resize growth at a 3:2 table/details weight. The details Text also uses Tk’s default height (24 lines), inflating its requested pane size. I’ll keep the existing split layout and scrollbars, give details a smaller scrollable starting height, and shift pane growth toward the table.

Agent
Agent
Agent
Agent
Agent
Agent
Agent

Implemented the vertical layout adjustment.

The main content already expands with the window, but the vertical ttk.Panedwindow gave resize space a 3:2 table-to-details weight. The details text also requested Tk’s default 24-line height, reducing the table’s initial space. The table now explicitly requests 10 rows, the details text requests 6 lines and remains scrollable, and pane resize space is weighted 4:1 toward the table. Both panes retain their own scrollbars; the existing columns, severity styling, and duplicate-ID fix are unchanged.

Files changed
- ui/main_window.py
- ui/finding_details.py

Validation
- python -m unittest discover -s tests -v — 47 tests passed
- python -m compileall -q . — passed (no output)

I verified the layout configuration in code, but did not manually measure the maximized window’s rendered row count.

The active Hacktoberfest Open-Source AI Challenge: Week 2 focuses on useful projects built with open-source AI or open-weight models. SecureLocal AI’s local Ollama integration may be relevant, subject to the challenge’s submission rules.

🌐 Community Wisdom: 🐍 tkinter frame and label widget guide: common mistakes and how to fix them

Source: ptp2308
Tags: python, tkinter, gui

The article emphasizes getting layout structure right before refining appearance. Its advice is general; it does not specifically cover Panedwindow sizing. The article had no comments, so there was no discussion feedback to weigh.

🔗 Read Full Discussion

🌐 Community Wisdom: Tkinter GUI guide

Source: hunter-intel
Tags: programming, beginners, python, discuss

This is a basic widget guide rather than a layout case study; it illustrates that text-widget dimensions can be specified explicitly, but offers little evidence about pane proportions. It had no comments. Overall, the available community evidence is limited and indirect.

🔗 Read Full Discussion

You

Inspect the JSON and Markdown report export handlers in SecureLocal AI.

Problem: When I scan tests/fixtures/vulnerable and export a Markdown report, the report is being saved inside the vulnerable fixture folder.

Please determine why the export dialog defaults to that directory.

Requirements:

  1. Identify how the export dialog's initialdir and default filename are determined.
  2. Change the default export directory to a dedicated reports/ folder at the project root, rather than the currently selected scan folder.
  3. Create the reports/ directory if needed, using safe, predictable path handling.
  4. Apply the same default location to both Markdown and JSON exports.
  5. Preserve the existing save dialog so I can choose another location.
  6. Do not automatically overwrite existing reports. Preserve the current overwrite confirmation behavior.
  7. Do not change report content, metadata, redaction, or export formats.
  8. Ensure exported reports are not accidentally scanned as project source files during normal test runs. Do not weaken scanner behavior to achieve this.
  9. Add focused tests if the export-path logic can be tested safely.
  10. Run python -m unittest discover -s tests -v and python -m compileall -q ., and report the actual results. Inspect the current implementation first and make the smallest appropriate change. Do not commit or push anything.
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

I’ll inspect the export handler, report exporter, and tests first to confirm how the dialog picks its directory and filename, and whether existing report outputs could enter test scans.

Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent
Agent

The handler currently omits both initialdir and initialfile, so the native save dialog falls back to its current/last-used directory; selecting a fixture folder can therefore carry over to export. I’ll add one shared dialog-default helper anchored to the application’s project root, create reports/ if absent, and choose a free default filename while keeping overwrite confirmation enabled.

Agent
Agent
Agent
Agent
Agent
Agent

The shared path helper now anchors both export formats to the application-root reports/ directory, sanitizes the scan’s project name for a default filename, and picks the next available default suffix when that filename already exists. The save dialog remains interactive and has overwrite confirmation enabled. Focused path tests pass; I’m running the full requested checks now.

Agent
Agent
Agent

Root cause: The export handler omitted both initialdir and initialfile, so the native save dialog chose its current or previously used directory. After browsing to the vulnerable fixture, that directory could become the default for the next export.

Both export formats now use the same helper to open in the project-root reports/ directory, creating it if needed. The helper builds a sanitized default filename and chooses an unused suffix if that filename already exists. The save dialog remains available for choosing another location, with overwrite confirmation enabled. The scanner and report contents were not changed; discovery continues to include only .py files.

Files changed
- ui/main_window.py
- tests/test_ui_export.py

Validation
- Focused export-path tests: 3 passed
- python -m unittest discover -s tests -v: 50 passed
- python -m compileall -q .: passed (no output)

🌐 Community Wisdom: Python pathlib: Modern File Path Handling Guide

Source: qingluan
Tags: python, tutorial, programming, beginners

This search result is a general reference for Python path handling, relevant to anchoring the export directory to the application location rather than relying on the current working directory. I couldn’t retrieve the article body or comments, so this is limited evidence rather than a verified discussion of Tkinter save dialogs.

🔗 Read Full Discussion

🌐 Community Wisdom: File Handling in Python: Working With Real Data

Source: stillpurrfect
Tags: beginners, codenewbie, python, tutorial

Search surfaced this as general Python file-handling guidance; it offers little specific evidence about Tkinter dialog defaults or overwrite prompts. The article body and comments weren’t available to inspect.

🔗 Read Full Discussion

This post is an entry for the Side Hustle prompt: a small, specific tool built around open-weight AI, with its prospective users and the privacy/cost trade-offs stated plainly. No partner category is claimed.

Top comments (0)