DEV Community

Amara Graham
Amara Graham

Posted on

Building a Self-Triaging CVE Checker with Gemini, Kestra, and Notion

I built a CVE checker for a nice enterprise-y use case, and of course, it's getting bigger and bigger as I go "ooooh, what if I add this?!" So this is me taking a break and telling you what I've done so far because this was the original stopping point.

The idea

I needed some kind of data to populate a Notion database (basically a table) so I could do something interesting with our Notion + Kestra plugins. Bonus points if I could sprinkle in some AI augmentation. Extra bonus points if I could make it a realistic enterprise example. Something that really resonates with the enterprise crowd.

And immediately I was like - CVEs!

The distraction

Side note, I spent far too long last week discovering that things may look like and act like Notion Pages, but a Notion Database is not a Notion Page. So if you give the API a Database id when it wants a Page id, it tells you it doesn't exist. Because a database is not a page. Hence, we have a Kestra plugin for Pages and a separate one for Databases now!

The Notion API makes you use UUIDs, but the value you need is presented in the URL if you are looking at Notion in a browser... but you need to turn that into a UUID. So my search history looks like this:

A Google Search bar and AI summary turning a string of characters into a UUID format

I also use Google Search to do calculations because I could not be bothered to open the calculator app when I'm already in a browser. Follow me for more tips on what Google Search can do. 😂

What I built

The Kestra flow code editor and topology panels open to show the completed (for now) demo

I needed a list of CVEs, so I went out to CISA and found their Known Exploited Vulnerabilities Catalog. They make this available in a few formats, so I found it in JSON.

The objects are pretty clean and tidy and look something like this:

{
    "cveID": "CVE-2026-33017",
    "vendorProject": "Langflow",
    "product": "Langflow",
    "vulnerabilityName": "Langflow Code Injection Vulnerability",
    "dateAdded": "2026-03-25",
    "shortDescription": "Langflow contains a code injection vulnerability that could allow building public flows without requiring authentication.",
    "requiredAction": "Apply mitigations per vendor instructions, follow applicable BOD 22-01 guidance for cloud services, or discontinue use of the product if mitigations are unavailable.",
    "dueDate": "2026-04-08",
    "knownRansomwareCampaignUse": "Unknown",
    "notes": "https:\/\/github.com\/langflow-ai\/langflow\/security\/advisories\/GHSA-vwmf-pq79-vjvx ; https:\/\/nvd.nist.gov\/vuln\/detail\/CVE-2026-33017",
    "cwes": [
        "CWE-94",
        "CWE-95",
        "CWE-306"
    ]
},
Enter fullscreen mode Exit fullscreen mode

CVEs are kind of notorious for being hard to understand. They can pop up randomly and the anxiety that comes with trying to decide if your codebase is impacted, plus how fast you need to mitigate them, can make things harder than necessary. So I wanted to augment this a bit and sprinkle in some AI to help. I want Gemini to help me set the priority and action plan and hopefully make it a little easier for a human to parse than the CVE itself.

I want to pass new vulnerabilities to AI because, as of writing this, the list is 1557 CVEs long and I want to be conscious of token use. I also think it's more realistic for my demo to have a smallish subset of CVEs to triage.

Once I have this, I want to send it to a Notion Database, where I can have a nice little visual table to assign a human reviewer and create a Notion Page on the specific CVE to capture any implementation details or other notes the human wants to provide for more context on how this applies (or doesn't apply) to us.

A screenshot of the Notion Database for CVE tracking with 4 items

More on the design

I should start by saying, as always, I'm not looking to make highly performant, production-ready demos. There are times I want to do something less than ideal to show particular aspects or features of the product and workflow mechanics. The things I make should spark a conversation or ideation. Besides, you know your use case better than I do.

Now that I got the disclaimer out of the way, let's talk about the design of this demo.

Store individual CVE IDs in KV Store

I wanted to store the known CVE IDs in a way that was searchable within Kestra, and to do that I used the KV Store. The keys map to the CVE IDs and the values are the names. The CVE IDs will always be a specific format, but the names could be quite lengthy. However, I could see a case where I need to reference both in my demo.

This searchability within Kestra gives an admin a fast way to reference whether this is a known CVE in the system since the table in Notion will only show new known CVEs.

Iterate through the JSON

Since I have this running during off hours, I don't really care how long it takes. With 1500+ CVEs to iterate through, this takes about 20-30 minutes with the concurrency limit set to run some tasks in parallel (5). Without setting the concurrency limit and just letting this default to running everything sequentially, it takes over an hour. Again, running off hours, I could easily tolerate this.

What's next

I'm always like HOW DO I MAKE THIS EVEN BIGGER. What more can I pack into this demo?

Could I just iterate over the top of the JSON?

Rethinking how I iterate over the JSON. CVEs don't get reported every day, and sometimes multiple get reported in a single day. I could probably be smarter with the iteration and only "read" until I hit a known CVE in my system and then stop since CVEs are added to the top of the JSON response.

However, if I wanted to build a really robust example and look for any edits or updates to the CVE information (like whether there is a new known ransomware campaign) I would still need to iterate through all of them.

This assumes that the behavior I'm seeing, where the CVEs are added to the top of the JSON, is the typical practice. Since I've only been working with this list for ~4 days, this seems typical.

How would you approach this?

Pre-populate Notion pages with more CVE info

I want to pre-populate the page with more info from the CVE. When I add a new item to the database, I get the page id returned. I could then take this page id and send over some content with the rest of the info in the JSON. In the execution outputs, I actually have all that info returned in the Database CreateItem task, so this would be quite trivial. They even give me the page ID as a UUID!!!!

Oops, found a bug

I wanted to add a checkbox about whether it should be mitigated now. To me, this is different than priority, but more of an urgency indicator. There's a bug with the Notion Database plugin where I couldn't pass in a boolean, so I removed the checkbox for now.

Wrapping up

If you want to view or use this example you can find it over on GitHub. I do not recommend running it the first time with the AI and Notion tasks enabled because you'll get 1557+ CVEs run through Gemini and added to your Notion database. Comment those out for the first run.

In fact, as I was building this demo the last ~4 days, the CVEs trickled in at a near perfect rate for me to see 1-3 pop into the table, but often I would have to delete a KV item manually to ensure I could get something to populate in my table.

If you use it as inspiration, let me know what you are building, or what you want to build! Keen eyes will notice I used Kestra EE, but you could definitely build this with Kestra OSS too with a few tweaks for things like secret management.

Top comments (0)