<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ilias Almerekov</title>
    <description>The latest articles on DEV Community by Ilias Almerekov (@iliasalmerekov).</description>
    <link>https://dev.to/iliasalmerekov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3956020%2F72d7bd34-06c2-40e6-8c25-f68fc28c9697.jpeg</url>
      <title>DEV Community: Ilias Almerekov</title>
      <link>https://dev.to/iliasalmerekov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iliasalmerekov"/>
    <language>en</language>
    <item>
      <title>I built Aegis — a firewall between AI coding agents and your shell</title>
      <dc:creator>Ilias Almerekov</dc:creator>
      <pubDate>Thu, 09 Jul 2026 07:58:19 +0000</pubDate>
      <link>https://dev.to/iliasalmerekov/i-built-aegis-a-firewall-between-ai-coding-agents-and-your-shell-4bba</link>
      <guid>https://dev.to/iliasalmerekov/i-built-aegis-a-firewall-between-ai-coding-agents-and-your-shell-4bba</guid>
      <description>&lt;p&gt;A few months ago I watched Claude Code run &lt;code&gt;rm -rf&lt;/code&gt; on a directory it had misunderstood. Nothing critical was lost, but it got me thinking: I had given an autonomous agent unrestricted access to my shell, and the only thing standing between it and my filesystem was... nothing.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://aegisdev.me/" rel="noopener noreferrer"&gt;Aegis&lt;/a&gt; — a small Rust CLI that sits between an AI agent and your real shell, and checks every command before it runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;AI coding agents are genuinely useful, but they move fast and they make mistakes. The failure modes are well known by now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deleting files or whole directories they misidentified&lt;/li&gt;
&lt;li&gt;resetting or force-pushing git history&lt;/li&gt;
&lt;li&gt;dropping database tables&lt;/li&gt;
&lt;li&gt;publishing packages you didn't mean to publish&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most agents have their own permission prompts, but those live inside the agent. One misconfigured "auto-approve" setting, one YOLO mode session, and there's nothing left between the model and your data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Aegis does
&lt;/h2&gt;

&lt;p&gt;Aegis intercepts every command and classifies it into one of four risk levels:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Safe&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runs immediately — no delay, no prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Warn&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pauses and asks for your approval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Danger&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Takes a best-effort snapshot first, then asks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Block&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Refused outright — no prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cargo build&lt;/code&gt;, &lt;code&gt;git status&lt;/code&gt; — these run instantly. The classification happens in under 2 milliseconds, so on the happy path you never notice Aegis is there.&lt;/p&gt;

&lt;p&gt;But when the agent tries something like &lt;code&gt;rm -rf ~/.config&lt;/code&gt;, you get this instead of silent data loss:&lt;/p&gt;

&lt;p&gt;⚠ DANGER — FS-001 · Recursive delete&lt;br&gt;
Command  rm -rf ~/.config&lt;br&gt;
Risk     Danger&lt;br&gt;
Pattern  FS-001 — rm with -rf flag&lt;br&gt;
Snapshot git stash created (a3f9b12)&lt;/p&gt;

&lt;p&gt;[A] approve  [D] deny  [i] info&lt;/p&gt;

&lt;p&gt;Note the snapshot line: before a dangerous command even asks for approval, Aegis takes a best-effort snapshot (git stash, or a Docker/SQLite-aware backup depending on context). If you approve the command and regret it, you can roll back. If you deny it, the snapshot is retained anyway.&lt;/p&gt;

&lt;p&gt;Everything — every command, every decision, every snapshot — goes into an append-only, integrity-checked audit log. You can always answer the question "what exactly did the agent do yesterday?"&lt;/p&gt;
&lt;h2&gt;
  
  
  How it hooks in
&lt;/h2&gt;

&lt;p&gt;For &lt;strong&gt;Claude Code&lt;/strong&gt; and &lt;strong&gt;Codex&lt;/strong&gt;, Aegis registers &lt;code&gt;PreToolUse&lt;/code&gt; hooks, so every Bash command the agent runs goes through the scanner regardless of what &lt;code&gt;$SHELL&lt;/code&gt; is set to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aegis install-hooks &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other agents that respect $SHELL, there's a shell-proxy mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aegis setup-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This points SHELL at the aegis binary and keeps your real shell in AEGIS_REAL_SHELL. Aegis parses the command, classifies it, and only forwards to your real shell what you approved.&lt;/p&gt;

&lt;p&gt;The interesting engineering bits&lt;/p&gt;

&lt;p&gt;The hot path is Aho-Corasick, not regex. The first pass over every command is a multi-pattern scan with zero allocations. Regex only kicks in for commands that trip the fast scan. That's how safe commands stay under 2 ms.&lt;/p&gt;

&lt;p&gt;Shell parsing is where the real work is. Agents don't write polite one-liners. They write heredocs, inline scripts, pipes, bash -c inside bash -c, and quoting that would make POSIX blush. Aegis has its own parser for this, and it's fuzzed in CI — because a guardrail with a parser bypass is worse than no guardrail at all. Some of the bypasses we've already fixed: uppercase variations, $IFS obfuscation, SQL hidden inside psql/mysql invocations.&lt;/p&gt;

&lt;p&gt;Hooks fail closed. If the aegis binary goes missing or a hook dependency breaks, the hook denies the command instead of silently letting it through. A safety tool that fails open is just decoration.&lt;/p&gt;

&lt;p&gt;Config can only get stricter. A per-project .aegis.toml can tighten the security posture but never weaken it. So a repository you cloned (or an agent editing files in it) can't quietly turn the guardrails off.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Aegis is not
&lt;/h2&gt;

&lt;p&gt;I want to be honest here, because security tools that oversell themselves are a plague: Aegis is a heuristic guardrail, not a sandbox. It is not a privilege boundary. A determined attacker — or a sufficiently creative agent — can construct commands that evade pattern-based classification. There's a full threat model (&lt;a href="https://github.com/IliasAlmerekov/aegis/blob/main/docs/threat-model.md" rel="noopener noreferrer"&gt;https://github.com/IliasAlmerekov/aegis/blob/main/docs/threat-model.md&lt;/a&gt;) in the repo that spells out exactly what's in and out of scope.&lt;/p&gt;

&lt;p&gt;What Aegis protects you from is the realistic everyday case: an agent making an honest mistake at machine speed. In my experience, that covers the vast majority of near-disasters.&lt;/p&gt;

&lt;p&gt;Try it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/IliasAlmerekov/aegis/main/scripts/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or via npm / Homebrew if you prefer your installs package-managed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; @iliasalmerekov/aegis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  or
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap IliasAlmerekov/aegis &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class="nb"&gt;install &lt;/span&gt;aegis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify it's working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aegis &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'echo hello'&lt;/span&gt;              &lt;span class="c"&gt;# safe — runs instantly&lt;/span&gt;
aegis &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf /tmp/aegis-test'&lt;/span&gt;  &lt;span class="c"&gt;# danger — prompt appears, press D&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Linux, macOS, and WSL2 are supported (no native Windows build).&lt;br&gt;
GitHub (&lt;a href="https://github.com/IliasAlmerekov/aegis" rel="noopener noreferrer"&gt;https://github.com/IliasAlmerekov/aegis&lt;/a&gt;) — issues and PRs welcome, especially bypass reports. If you can sneak a dangerous command past the scanner, I genuinely want to know.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>ai</category>
      <category>security</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Reviving My School's AI Assistant: Moodle + Ollama</title>
      <dc:creator>Ilias Almerekov</dc:creator>
      <pubDate>Thu, 28 May 2026 07:54:01 +0000</pubDate>
      <link>https://dev.to/iliasalmerekov/reviving-my-schools-ai-assistant-moodle-ollama-4o63</link>
      <guid>https://dev.to/iliasalmerekov/reviving-my-schools-ai-assistant-moodle-ollama-4o63</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-05-21"&gt;GitHub Finish-Up-A-Thon Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Moodle AI Assistant — an AI-powered learning companion embedded directly into Moodle, the LMS used at my vocational school Berufsschule ITECH in Germany, where I'm training as a Fachinformatiker (IT Specialist)&lt;/p&gt;

&lt;p&gt;This project means a lot to me because it solves a real problem I see every day at school: students get stuck on assignments after hours, teachers get flooded with the same repeated questions, and there's no smart help available on demand. I built this to change that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Github Repository: &lt;a href="https://github.com/IliasAlmerekov/moodle" rel="noopener noreferrer"&gt;https://github.com/IliasAlmerekov/moodle&lt;/a&gt;&lt;br&gt;
Demo Video: &lt;a href="https://youtube.com/shorts/Iiy4re43cMM?feature=share" rel="noopener noreferrer"&gt;https://youtube.com/shorts/Iiy4re43cMM?feature=share&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comeback Story
&lt;/h2&gt;

&lt;p&gt;The project started as a school initiative at Berufsschule ITECH. My teachers loved the idea and we were planning to finish it together and actually deploy it to the school's real Moodle instance. Then our block-based curriculum kicked in — a new Lernfeld (learning field) began, everyone's schedules shifted, and the project quietly slipped into the "we'll get back to it someday" pile.&lt;/p&gt;

&lt;p&gt;It sat there. Months passed. Then I found the GitHub Finish-Up-A-Thon Challenge — and something clicked. This was exactly the push I needed. The thought of finally showing my teachers a working, production-ready version of what we once planned together was all the motivation I needed to open the repo again.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;When I first built this project, I had a GitHub Student subscription with access to powerful models and no strict weekly limits. Back then, Copilot was my real pair programmer — it helped me move fast and learn even faster.&lt;/p&gt;

&lt;p&gt;Unfortunately, the tighter weekly limits that came later made it much harder to use Copilot the same way. But those months of working with it weren't wasted — I learned a lot, grew as a developer, and now I feel ready to come back to this project and do a full refactoring, applying everything I picked up along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Comeback 04.06.2026: What was broken and What I Actually Fixed?
&lt;/h2&gt;

&lt;p&gt;The prototype worked — it answered questions. But it was a single-file Fastify server with logic mixed into routes, and it would not have survived contact with real students. Here's the honest before → after, by area:&lt;/p&gt;

&lt;p&gt;🔐 Identity&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: userId trusted straight from the request body — any user could read another's chat (IDOR).&lt;/li&gt;
&lt;li&gt;After: HMAC-SHA256 signed identity, constant-time verify, per-session ownership checks (401/403).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🏛️ Architecture&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: Business logic tangled into route handlers.&lt;/li&gt;
&lt;li&gt;After: Clean Architecture, 4 layers, dependency rule enforced — use cases testable without Fastify or Docker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🤖 AI grounding&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: The model could see all courses.&lt;/li&gt;
&lt;li&gt;After: Course search is fail-closed to the student's own enrolments; no secrets reachable by the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🛡️ Frontend XSS&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: Model output dumped into raw innerHTML.&lt;/li&gt;
&lt;li&gt;After: DOMPurify + tag/attribute allowlist + Moodle-origin-locked links, with a CSP backstop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚙️ Reliability&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: Direct fetch, no limits.&lt;/li&gt;
&lt;li&gt;After: Timeout + retry (Moodle), circuit breaker + bounded queue (Ollama), graceful shutdown, SSE abort on disconnect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💾 Persistence&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: In-memory — every restart wiped all chat history.&lt;/li&gt;
&lt;li&gt;After: SQLite (WAL, prepared statements, indexed, retention pruning) behind a repository interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚀 Deploy&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: Manual, container ran as root.&lt;/li&gt;
&lt;li&gt;After: Multi-stage non-root Docker image, healthchecks, ordered startup, one-command Compose.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Quality gate&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Before: None.&lt;/li&gt;
&lt;li&gt;After: 417 tests, ESLint, Prettier, npm audit, Gitleaks, Trivy image scan + container smoke test in CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 3 critical blockers I closed for this challenge&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unauthenticated PII leak — /moodle/user/:id and /moodle/users/:id/courses returned personal data with no auth (only accidentally hidden by nginx routing). Now production-gated to 404.&lt;/li&gt;
&lt;li&gt;Known high-severity CVEs — Fastify 4.28.1 carried 3 high CVEs (body-validation bypass, host/proto spoof). Upgraded to Fastify 5 + matching
plugins; npm audit now reports 0 vulnerabilities.&lt;/li&gt;
&lt;li&gt;Root container, no build hardening — rebuilt as a multi-stage image running as USER node with npm ci and a HEALTHCHECK.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Where I was honest instead of perfect&lt;/p&gt;

&lt;p&gt;I didn't fake "done." The per-user rate limiter is in-memory (fine for a single instance, documented as a known limit), and the prompt-injection guard is a best-effort blocklist — its real safety net is that the model simply can't reach anything sensitive (fail-closed course scope, no secrets in context). These are written down in the README's Limitations section, not hidden.&lt;/p&gt;

&lt;p&gt;The result&lt;/p&gt;

&lt;p&gt;The prototype went from "it answers questions on my laptop" to a production-lite service: Clean Architecture (90/100 in my own readiness&lt;br&gt;
  review), HMAC auth, sanitized LLM output, resilient external calls, persistent history, a hardened container, and a full CI pipeline — all&lt;br&gt;
  behind a single docker compose up.&lt;/p&gt;

&lt;p&gt;The next step is the one that started it all: showing my teachers a working version, and finally deploying it to the school's real Moodle&lt;br&gt;
  instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thank You 🙏
&lt;/h2&gt;

&lt;p&gt;Huge thanks to GitHub and the DEV community for the chance to take part in such a cool challenge. The Finish-Up-A-Thon was exactly the push I needed to reopen a project I genuinely cared about and finally carry it across the finish line.&lt;/p&gt;

&lt;p&gt;These challenges do more than hand out prompts — they turn "someday" projects into shipped ones and give motivation real momentum. Thank you for creating that space. I had a great time building this, and I'll happily jump into more challenges like this one in the future. 🚀&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
    </item>
  </channel>
</rss>
