How to Build an OT Security Threat Intelligence Dashboard with Claude, Using Open, Reliable Sources, and No Servers.

How to Build an OT Security Threat Intelligence Dashboard with Claude, Using Open, Reliable Sources, and No Servers.

CISA KEV, ransomware.live, and a Serverless Architecture — Open and Verifiable.

This tutorial walks you through building, from start to finish, a public threat-monitoring dashboard for the OT/ICS sector (operational technology / industrial control systems), using Claude as a technical copilot at every stage: from choosing data sources to deploying the full architecture.

This isn't a "copy and paste this code" guide. It's the real process, prompt by prompt, with the technical decisions explained so you can replicate or adapt it to your own case.

Step 1: Define what you need before writing any code

Before asking Claude for anything technical, define the scope with a single clear constraint. In this case, the constraint was: everything has to be free and from verifiable public sources.

Suggested starting prompt:

"I need a threat intelligence dashboard for the OT/manufacturing sector. I want actively exploited vulnerabilities, ransomware attacks against manufacturing, and sector news. Everything must be free and from verifiable public sources."

That constraint is what filters every decision that follows — which sources to use, which architecture to pick, and what you can't promise the end user.

Step 2: Choose and justify your data sources

Not every source is good enough. Before integrating anything, evaluate each one with these questions: Is it public? Does it require authentication? Is it the primary source or does it pass through an intermediary? Does it have usage limits?

CISA KEV (Known Exploited Vulnerabilities) The official U.S. government catalog of vulnerabilities confirmed as actively exploited. It's public JSON, no authentication required:

https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json

It's the most reliable source in the project because it doesn't go through scraping or third-party interpretation — it's the direct primary source.

ransomware.live The only public source with ransomware victim data filtered by sector. Here the technical justification needs to come with an important piece of honesty: this data reflects what ransomware groups claim on their leak sites, not victim-confirmed facts. Treat it as directional signal, never as confirmed fact, and say so explicitly in your final product.

News sources via RSS Use at least two different sources (for example, an outlet specialized in OT/ICS and a general cybersecurity outlet) to reduce single-source editorial bias. Filter articles with a keyword heuristic (scada, plc, ics, operational technology, critical infrastructure, etc.) to keep only what's relevant.

When no real public source exists If you need a data point for which there's no free public API (in this case, a per-country exposure map), ask Claude directly:

"I can't find a free API for attacks by country for OT. What are my options?"

If the answer confirms none exists, you have two paths: fabricate data disguised as real, or build an editorial index and declare it as such. Always choose the second. General rule: if you can't cite the exact source of a number, don't present it as hard data.

Step 3: Connect the ransomware.live API step by step

This is the most delicate integration in the project, so it comes with more technical detail.

3.1 — Check whether you need an API key. The free tier of ransomware.live doesn't require authentication. The endpoint you need is:

GET https://api.ransomware.live/v2/sectorvictims/<sector>

Replace <sector> with the one you care about (for example, Manufacturing).

3.2 — Ask Claude for the integration, including edge cases:

"Create a serverless function that queries the ransomware.live API, filters by the Manufacturing sector, and only returns victims from the last 15 days. I need to handle the case where the API returns a plain array or an object with the list inside, because I don't trust the response shape to always be the same."

That "edge cases" detail matters: many public APIs aren't perfectly consistent in their response shape. The resulting code needs to normalize that:

const list = Array.isArray(raw) ? raw : raw.victims || raw.data || [];

3.3 — Read the Terms and Conditions before going to production. ransomware.live states that free/unauthenticated use is "personal use only"; for corporate use or on a publicly branded domain, they ask you to review their T&C directly on their site. Document this in your own code as a warning for anyone who reuses the project.

3.4 — Solve rate limiting with caching, not a premium key. Since it's a public API with usage limits, the fix isn't paying for more quota — it's caching the response aggressively (see Step 4) so you never hit the API more than once every 24 hours, no matter how many visits your site gets.

Step 4: Design the full architecture

Ask Claude to think in layers, not just in code:

"Design the full architecture: what happens from the moment a user opens the browser to when they receive the data, going through WAF, caching, and the external APIs."

A typical flow for this kind of dashboard looks like this:

User's browser
      |
      v
WAF (Web Application Firewall)
      |  <- filters malicious traffic, bots, and attacks before they reach your infrastructure
      v
Edge Network (CDN + edge caching)
      |  <- this is where the Cache-Control: s-maxage=86400 (24h) header lives
      |  <- this layer absorbs almost all traffic without touching your backend
      v
Serverless Functions — acting as "workers"
      |  <- each function receives the browser's request,
      |     calls the external source, transforms the response, returns it
      v
External APIs / feeds (outside your control)
  Official source (e.g. CISA KEV)
  Third-party API (e.g. ransomware.live)
  News RSS feeds

About the WAF: this layer is your first line of defense — it filters malicious traffic, abusive scraping attempts, and attack patterns before they reach your application. Not every hosting provider includes this by default with configurable rules; if yours doesn't, treat it as a layer you need to add explicitly in front of your infrastructure, not something you can assume is already handled.

Why serverless instead of a traditional server (VPS/EC2)?

  • There's no constant traffic that justifies a server running 24/7
  • Each worker only runs when the cache expires
  • Zero maintenance of the operating system, patching, or process management
  • Trade-off to consider: free-tier serverless hosting plans usually limit native cron jobs to once a day, so your data refresh depends on edge caching, not a frequent scheduled job

Why edge caching instead of a database? If your dashboard only needs to show fresh data periodically (no history or analytics), edge caching can be your only "persistence" layer. Set the header like this:

Cache-Control: s-maxage=86400, stale-while-revalidate=172800

The first visit after the cache expires triggers your real worker; every visit after that during those 24h gets the cached copy from the Edge Network. This removes the need for a database entirely.

Step 5: Structure the repo for automatic deployment

Keep the project simple: no build step if you don't need one.

public/          -> static frontend (plain HTML/CSS/JS)
api/             -> your serverless functions (workers)
config           -> CORS headers and function timeouts
package.json     -> project metadata

Ask Claude for the deployment flow:

"Walk me through the full flow from my repository to a custom domain, as if I'd never done it before."

With most modern providers, connecting your repository sets up automatic deployment: every change pushed to your main branch triggers a deploy through the WAF and Edge Network without needing a separate CI/CD pipeline.

Step 6: Iterate with specific prompts, not full rewrites

Once the dashboard is in production, every improvement should be a concrete prompt scoped to a single layer of the system. Real examples from this process:

  • "The map shows an index but doesn't say where it comes from — make it so clicking a country opens the source of that data."
  • "Change the refresh window from 12 to 24 hours across the whole dashboard, including the workers' cache."
  • "In the ransomware table, some rows don't have any verifiable link — add a Source column that always has a link."

Each prompt should touch a single layer (frontend, worker/caching, or data integrity). This confirms something important: building a dashboard with AI's help isn't one giant prompt — it's a technical conversation, layer by layer, the same way you'd do it with a human developer.

Summary: the principles to follow

  1. Define where your data will come from first, and under what terms you can legally use it.
  2. Be honest when no real source exists — a declared editorial index beats fabricated data disguised as verified.
  3. Design the caching strategy before the visual design — it's what lets you run for free at any traffic scale.
  4. Use serverless + edge caching if your project doesn't need historical persistence — you save on entire infrastructure.
  5. Iterate with prompts scoped to a single layer, not full rewrites every time you want an adjustment.

You can check out the result here: ot.cafehacking.com Autor: Edu Quijano