It was 2:00 AM, our terminal was glowing with an angry shade of red, and my monitor looked like it had caught digital chickenpox.
We had just run a popular CI/CD linter on an open-source repository’s GitHub Actions workflows. The output? 3,541 warnings across 165 files.
Thirty-five hundred alerts.
If you’ve ever worked in software engineering, you know exactly what happens when a developer sees 3,500 security alerts: they close the tab, make a cup of coffee, and pretend they never saw it. That’s not security; that’s pure, distilled alert fatigue.
Sitting there in the dim glow of our laptops, our team had a collective realization: CI/CD security isn’t broken because we lack scanners. It’s broken because existing scanners treat complex pipelines like flat text files.
This is the story of how we built ChokePoint (Alepheus) during the hackathon—a graph-powered CI/CD attack-path agent that uses FalkorDB’s graph algorithms to turn an overwhelming swamp of warnings into mathematically proven, minimal fixes.
The Anatomy of the Nightmare: Strangers Meet Your Crown Jewels
Think about what a GitHub Actions workflow actually does.
It’s the one place in your entire infrastructure where code and text submitted by complete strangers on the internet (forked pull requests, issue titles, casual comments, third-party action tags) directly share computing resources with your most sensitive production secrets: AWS deployment roles, npm publishing tokens, and Docker registry keys.
Remember the tj-actions incident? A compromised third-party action tag meant that every pipeline running that action handed over all of its environment secrets on a silver platter.
Or consider the classic "Pwn-Request":
- An external contributor opens a pull request.
- The workflow triggers on
pull_request_target(which grants write access). - A step checks out the untrusted PR branch.
- A bash script interpolates
${{ github.event.issue.title }}into anechocommand. - Three steps down, a deploy job uses that runner’s token to push to production.
Existing linters flag step 4 as a "script injection" and step 2 as an "untrusted trigger." But they evaluate each file in isolation. They have zero clue whether that injection actually flows into a job with production credentials, or if it dies harmlessly in an empty test runner.
The Lightbulb Moment: "Wait... Pipelines Are Graphs!"
At about 3:30 AM, after our third energy drink, the whiteboard came alive.
A CI/CD pipeline isn't a list of lines.
- Steps depend on Jobs.
- Jobs depend on Workflows.
- Workflows consume Actions and output Artifacts.
- And data flows from untrusted inputs down to crown-jewel capabilities.
It’s a directed graph. And if it’s a graph, we shouldn't be using regex and AST grep. We should be using a graph database.
Enter FalkorDB.
The FalkorDB Adventure: Building the Brain
We spun up FalkorDB in Docker (docker compose up -d), pinned our Redis ports, and got down to business.
We designed a dual-layer graph model:
-
The Structural Layer: Real-world entities (
Workflow,Job,Step,Action,Secret,Permission) connected by structural relationships (HAS_JOB,USES,HOLDS). -
The Flow Layer (
FLOWS): Derived dynamic edges representing attacker movement (inject,exec,expose,poison,consume) annotated with exploit difficulty, line numbers, and remediation costs.
Writing the Cypher query to find multi-hop attack chains felt like watching magic happen:
MATCH p = (i:Input {attacker: true})-[:FLOWS*1..8]->(c:Capability {crown: true})
RETURN p, reduce(cost = 0, e IN relationships(p) | cost + e.difficulty) AS total_difficulty
ORDER BY total_difficulty ASC
Suddenly, with variable-depth traversal, we weren't looking at 3,500 isolated line warnings. We were looking at 5 actual, exploitable end-to-end paths leading from an attacker to AWS root.
The Mathematical Secret Sauce: Min-Cut with algo.maxFlow
Now came the coolest part of the project—the part where computer science theory saved our sanity.
Once you know there are 25 attack paths in your system, do you really need to rewrite 25 workflows?
No!
Think of attack paths like water flowing through pipes from an attacker source to your crown-jewel sink. To stop the flood, you don’t need to replace every pipe; you just need to close the minimum cut—the narrowest bottleneck of edges whose removal completely disconnects the attacker from your secrets.
FalkorDB has native graph algorithms built right in. We fed our pipeline graph into algo.maxFlow, using our fix_cost property as the edge capacity:
# Run FalkorDB max-flow and residual BFS
cut = min_fix_set(graph)
The algorithm solved the bottleneck in 60 milliseconds.
Instead of telling the developer to fix 25 disparate items across 10 files, FalkorDB pointed directly to two high-leverage choke points:
- Move one unquoted issue title into an
env:variable block. - Pin one third-party action to an immutable commit SHA.
Boom. All 25 attack chains severed. An 80% reduction in developer fix fatigue.
"What-If" Verification: The Power of GRAPH.COPY
One of our biggest hurdles was: How do we prove to a skeptical security team that our fix actually works without pushing broken code to production?
FalkorDB had our back with GRAPH.COPY.
Whenever our agent drafted a YAML patch (using ruamel.yaml so we didn't wipe out developers' carefully crafted comments):
- It copied the live graph into a temporary
whatif:*sandbox in memory. - Re-parsed the candidate YAML and re-ingested it into the clone.
- Re-ran the attack chain traversal queries.
- If and only if the active chains dropped from $N \to 0$, it marked the patch as Verified.
No production mutations. No guessing. Mathematical proof in sub-second time.
Bringing It All Together: Autonomous Gemini Agent + React Web Console
To make this feel like a tool from 2026, we wired everything together:
- LLM Engine: We hooked up Google Gemini 2.5 Flash using its native function-calling SDK on the free tier (zero API costs, super fast response times!).
-
FastMCP Server: We exposed the whole FalkorDB toolset (
list_chains,min_fix_set,blast_radius) over the Model Context Protocol, so AI IDEs like Cursor and Claude Desktop can run our queries natively. - React + Vite Dashboard: We built a dark-mode cybersecurity console with real-time SSE event streaming so you can watch the AI agent "think", inspect hop-by-hop evidence, compare PR snapshot diffs, and review unified patch diffs.
What We Learned (The Real Takeaways)
- Graphs turn messy security panic into clean math: Trying to trace multi-file, reusable CI/CD workflows with regex is a fool's errand. Graphs don't care how deeply nested your composite actions are; traversal just works.
- Alert fatigue is a data modeling problem: Linters drown developers in warnings because they lack reachability context. Graph reachability filters out 80% of the noise automatically.
-
FalkorDB algorithms are a superpower: Having
algo.maxFlow,algo.pageRank, andGRAPH.COPYbuilt directly into the database engine meant we didn't have to export data into NetworkX or write complex graph logic from scratch in Python. It all ran at C-speed in-engine.
The Finish Line
Building ChokePoint during this hackathon was an absolute blast. We went from staring at an unreadable wall of 3,500 linter errors to watching a live dashboard prove that two targeted patches could secure an entire enterprise repository.
If you want to check out the project, explore the Cypher queries, or try out the CLI on your own workflows, check out our repository on GitHub:
👉 https://github.com/ragnaroast/alepheus
Built with ❤️, Python, React, Google Gemini, and FalkorDB.
Top comments (0)