<?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: Setounkpe7</title>
    <description>The latest articles on DEV Community by Setounkpe7 (@setounkpe7).</description>
    <link>https://dev.to/setounkpe7</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3912877%2F9005fb1b-d1cd-4a74-9e87-63439d121e6b.png</url>
      <title>DEV Community: Setounkpe7</title>
      <link>https://dev.to/setounkpe7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/setounkpe7"/>
    <language>en</language>
    <item>
      <title>Sector-aware threat intel API: stop triaging hundreds of CVEs manually</title>
      <dc:creator>Setounkpe7</dc:creator>
      <pubDate>Mon, 18 May 2026 11:30:00 +0000</pubDate>
      <link>https://dev.to/setounkpe7/sector-aware-threat-intel-api-stop-triaging-hundreds-of-cves-manually-5097</link>
      <guid>https://dev.to/setounkpe7/sector-aware-threat-intel-api-stop-triaging-hundreds-of-cves-manually-5097</guid>
      <description>&lt;h2&gt;
  
  
  A Monday morning in a SOC
&lt;/h2&gt;

&lt;p&gt;A SOC (Security Operations Center) is the team that watches for cyberattacks against a company. They sit between the firewall and the incident report, and one of their daily jobs is to read the day's new software vulnerabilities and decide which ones the company has to patch first.&lt;/p&gt;

&lt;p&gt;A vulnerability is published as a &lt;strong&gt;CVE&lt;/strong&gt; (Common Vulnerabilities and Exposures), a kind of barcode the industry uses to refer to a single bug. "CVE-2025-12345" means one specific flaw, in one specific piece of software, at one specific moment in time.&lt;/p&gt;

&lt;p&gt;Now picture a typical morning. Three public feeds land in the analyst's inbox:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NVD&lt;/strong&gt; (National Vulnerability Database, run by the US government). The official catalogue. Around 150 new CVEs a day. Every flaw eventually shows up here, dangerous or not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CISA KEV&lt;/strong&gt; (Known Exploited Vulnerabilities). A shortlist of CVEs that attackers are already using in real attacks. Maintained by CISA, the US cybersecurity agency. Smaller, scarier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GHSA&lt;/strong&gt; (GitHub Security Advisories). Same idea, but for open-source code. A vulnerability in a Python library or a Node package shows up here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these feeds is wrong. None is targeted either. A bank's SOC and a hospital's IT team subscribe to the same firehose, and a junior analyst spends the first two hours of every shift reading titles and asking the only question that really matters: "is this us?".&lt;/p&gt;

&lt;p&gt;Is the bug in software &lt;em&gt;we&lt;/em&gt; run? Does it touch a system &lt;em&gt;we&lt;/em&gt; care about? Could an attacker use it against &lt;em&gt;our&lt;/em&gt; customers? Most of the 150 daily CVEs are noise for any given company. A Minecraft mod RCE is irrelevant to a bank. A SCADA bug in a German PLC is irrelevant to a SaaS startup. But to find the five that matter, the analyst has to skim the headlines of the hundred-plus that don't.&lt;/p&gt;

&lt;p&gt;That re-triage happens in every SOC, every morning, against the same feeds, with the rules living in someone's head instead of being written down anywhere. Different person on call, different answers. Different week, different priorities. No memory.&lt;/p&gt;

&lt;p&gt;That triage step is the one I wanted to push down into an API.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Setounkpe7/threat-intel-api" rel="noopener noreferrer"&gt;&lt;code&gt;threat-intel-api&lt;/code&gt;&lt;/a&gt; is an open-source (MIT) vulnerability intelligence service. It pulls in NVD, CISA KEV and GHSA, removes the duplicates between them, and scores every CVE against a YAML file you write that describes what your sector and your stack actually care about.&lt;/p&gt;

&lt;p&gt;Six starter profiles ship in the box: finance, healthcare, ICS (industrial control systems, the software that runs factories and power grids), government, SaaS and e-commerce. Each profile is a list of keywords, technologies, CWE categories (a CWE is a &lt;em&gt;type&lt;/em&gt; of bug, like SQL injection or hardcoded credentials) and weights you can tune.&lt;/p&gt;

&lt;p&gt;Every score ships with the per-criterion breakdown that produced it. Paste it into a ticket and the analyst sees exactly why CVE-X scored 78 and CVE-Y scored 35. No hidden model, no opaque weight, no "trust the vendor".&lt;/p&gt;

&lt;p&gt;The rest of this post is how to plug it into your stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does in 30 seconds
&lt;/h2&gt;

&lt;p&gt;The live API runs at &lt;a href="https://threat-intel-api-production.up.railway.app/" rel="noopener noreferrer"&gt;threat-intel-api-production.up.railway.app&lt;/a&gt;. No auth on the public endpoints, no key required. Three calls cover the demo:&lt;/p&gt;

&lt;h3&gt;
  
  
  Top 5 finance-relevant threats, last 24h
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'https://threat-intel-api-production.up.railway.app/api/v1/sectors/finance/dashboard'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'.top_24h[:5] | .[] | {cve: .external_id, score, cvss: .cvss_score, title: .title[0:80]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cve"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CVE-2026-7579"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;35.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cvss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hard-coded credentials in AstrBot dashboard auth (CWE-798)"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Subscribe a SIEM to the finance RSS feed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://threat-intel-api-production.up.railway.app/api/v1/sectors/finance/feed.rss?min_score=70'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inspect the score breakdown of a single CVE
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'https://threat-intel-api-production.up.railway.app/api/v1/sectors/finance/dashboard'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="s1"&gt;'.top_24h[0].score_breakdown'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cwe_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"matched"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CWE-798"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cvss_threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"threshold"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"technology_match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"matched"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"points"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That CVE scored 35 for finance: +20 for the CWE-798 match (hardcoded credentials matter in banking), +15 because CVSS 7.3 clears the 7.0 threshold. Not a wake-up call, but it lands in the 7-day digest with a reason attached.&lt;/p&gt;

&lt;p&gt;Swap &lt;code&gt;finance&lt;/code&gt; for &lt;code&gt;healthcare&lt;/code&gt;, &lt;code&gt;ics&lt;/code&gt;, &lt;code&gt;gov&lt;/code&gt;, &lt;code&gt;saas&lt;/code&gt;, or &lt;code&gt;ecommerce&lt;/code&gt; and you get a sector-weighted view of the same underlying CVE corpus.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a SOC team should care
&lt;/h2&gt;

&lt;p&gt;This isn't a replacement for Recorded Future or Mandiant. It's the free, self-hosted thing you put next to them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sector-relevant by default.&lt;/strong&gt; The Minecraft-mod RCEs that NVD publishes ten times a week don't surface in your finance feed. The &lt;code&gt;excluded_keywords&lt;/code&gt; rule kills them at score time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auditable scoring.&lt;/strong&gt; No tuned ML model, no opaque weights. Eleven additive rules, a flat function, the breakdown stored in Postgres next to the score. When the SOC lead asks why CVE-X is a 78 and CVE-Y is a 62, you can answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SIEM-ready out of the box.&lt;/strong&gt; Every sector exposes a JSON dashboard and an RSS feed with a &lt;code&gt;min_score&lt;/code&gt; filter. Splunk, Sentinel and Elastic all consume RSS natively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot-reloadable profiles.&lt;/strong&gt; Your team adds the keywords that match your stack without touching code or restarting the service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No vendor lock-in.&lt;/strong&gt; MIT, Docker, Postgres, one &lt;code&gt;docker compose up&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Plug it into your stack in 5 minutes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SIEM via RSS
&lt;/h3&gt;

&lt;p&gt;In Splunk, Sentinel, or Elastic: add an RSS input pointing at the feed. Done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Splunk-style: poll finance threats scoring &amp;gt;= 70&lt;/span&gt;
curl &lt;span class="s1"&gt;'https://threat-intel-api-production.up.railway.app/api/v1/sectors/finance/feed.rss?min_score=70'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tune &lt;code&gt;min_score&lt;/code&gt; per sector. KEV-flagged threats get +25 automatically, so 70+ is usually the "actively-exploited or stack-relevant" band.&lt;/p&gt;

&lt;h3&gt;
  
  
  SOAR via JSON polling
&lt;/h3&gt;

&lt;p&gt;A ~10-line Python poller for any SOAR runbook (Cortex XSOAR, Tines, Shuffle, n8n):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;SEEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://threat-intel-api-production.up.railway.app/api/v1/sectors/finance/dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;top_24h&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;external_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SEEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;SEEN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;external_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="c1"&gt;# hand off to your SOAR: create incident, enrich, notify
&lt;/span&gt;            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NEW &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;external_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; score=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; cvss=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cvss_score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  reasons:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score_breakdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 15 minutes — collectors run hourly
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The breakdown gives the SOAR playbook a structured "why" field to include in the auto-created ticket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Slack / Teams alert
&lt;/h3&gt;

&lt;p&gt;Same poll, different sink:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="n"&gt;THREATS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.../sectors/ics/dashboard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;top_24h&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;THREATS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SLACK_WEBHOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:rotating_light: *&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;external_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;* (score &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;) — &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Webhook alerting from the API itself is on the roadmap as M4, so you won't need the poller forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add your sector profile
&lt;/h2&gt;

&lt;p&gt;This is the part that earns the project its keep. Sector knowledge belongs to the people in the sector — not to me. A payments analyst can ship a better finance profile than I ever will.&lt;/p&gt;

&lt;p&gt;Profiles are YAML. Here's the real &lt;code&gt;profiles/public/finance.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;finance&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Finance &amp;amp; Banking&lt;/span&gt;
&lt;span class="na"&gt;keywords&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;banking&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;payment&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;swift&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;sepa&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;ach&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;card&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pos&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;atm&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;technologies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Java&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Spring&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Tomcat&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;WebSphere&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Oracle Database&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Apache Struts&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;cwe_priorities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;CWE-89&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;CWE-79&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;CWE-352&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;CWE-287&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;CWE-798&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;CWE-22&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;cvss_threshold&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7.0&lt;/span&gt;
&lt;span class="na"&gt;priority_boost_keywords&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;wire transfer&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;swift network&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;card skimming&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;excluded_keywords&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;minecraft&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;game&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;mod&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want &lt;code&gt;iso20022&lt;/code&gt; weighted as a priority boost? Want &lt;code&gt;mitre-att&amp;amp;ck-t1486&lt;/code&gt; in the keyword set? Edit one file, then:&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;-X&lt;/span&gt; POST http://localhost:8000/api/v1/admin/reload-profiles &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-Admin-Key: &lt;/span&gt;&lt;span class="nv"&gt;$ADMIN_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No restart. No migration. The reload response lists profiles added, updated, removed, and any parse errors with file paths. Private profiles live in &lt;code&gt;profiles/private/&lt;/code&gt; and require the admin header to read — useful if your internal product list is sensitive.&lt;/p&gt;

&lt;p&gt;Full schema reference: &lt;a href="https://github.com/Setounkpe7/threat-intel-api/blob/main/profiles/README.md" rel="noopener noreferrer"&gt;&lt;code&gt;profiles/README.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scoring algorithm in one table
&lt;/h2&gt;

&lt;p&gt;Eleven rules. Additive. Clamped to &lt;code&gt;[0, 100]&lt;/code&gt;. Whole-word, case-insensitive matching, so &lt;code&gt;java&lt;/code&gt; doesn't match &lt;code&gt;javascript&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rule&lt;/th&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;th&gt;Points&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Technology match&lt;/td&gt;
&lt;td&gt;profile &lt;code&gt;technology&lt;/code&gt; appears in corpus&lt;/td&gt;
&lt;td&gt;+30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keyword match&lt;/td&gt;
&lt;td&gt;profile &lt;code&gt;keyword&lt;/code&gt; appears in corpus&lt;/td&gt;
&lt;td&gt;+25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CWE match&lt;/td&gt;
&lt;td&gt;threat CWE listed in &lt;code&gt;cwe_priorities&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;+20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CVSS threshold&lt;/td&gt;
&lt;td&gt;&lt;code&gt;cvss_score &amp;gt;= cvss_threshold&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;+15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Priority boost&lt;/td&gt;
&lt;td&gt;profile &lt;code&gt;priority_boost_keyword&lt;/code&gt; appears&lt;/td&gt;
&lt;td&gt;+20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Excluded&lt;/td&gt;
&lt;td&gt;profile &lt;code&gt;excluded_keyword&lt;/code&gt; appears&lt;/td&gt;
&lt;td&gt;-30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;KEV tag&lt;/td&gt;
&lt;td&gt;threat tagged &lt;code&gt;kev&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;+25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actively exploited&lt;/td&gt;
&lt;td&gt;threat tagged &lt;code&gt;actively-exploited&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;+15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ransomware&lt;/td&gt;
&lt;td&gt;threat tagged &lt;code&gt;ransomware&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;+15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-source&lt;/td&gt;
&lt;td&gt;documented by 3+ sources (or +5 for 2)&lt;/td&gt;
&lt;td&gt;+10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Package match&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;package&lt;/code&gt; indicator matches a &lt;code&gt;technology&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;+20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every score the API returns ships with the per-criterion breakdown that produced it. Drop it straight into a ticket and the analyst can defend the priority to the SOC lead without re-running anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture, briefly
&lt;/h2&gt;

&lt;p&gt;Three collectors → one dedup'd &lt;code&gt;Threat&lt;/code&gt; table → a flat scoring function → JSON + RSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxt16o75ldzylj8uci7wk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxt16o75ldzylj8uci7wk.png" alt="threat-intel-api architecture: NVD, CISA KEV and GHSA collectors feed a deduplicated PostgreSQL store; the SectorScoringService combines that store with YAML profiles to produce per-sector scores, exposed through the FastAPI v1 layer to SIEM, SOAR and analyst consumers." width="800" height="151"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One &lt;code&gt;Threat&lt;/code&gt; row per CVE ID, one &lt;code&gt;ThreatSource&lt;/code&gt; row per (CVE, source) pair. NVD wins on CVSS at read time, KEV wins on the &lt;code&gt;actively-exploited&lt;/code&gt; and &lt;code&gt;ransomware&lt;/code&gt; tags, GHSA wins on package indicators. Provenance stays attached. You can always check what NVD said vs what KEV said about the same CVE.&lt;/p&gt;

&lt;p&gt;Stack: FastAPI, SQLAlchemy 2.0, PostgreSQL, Pydantic v2, httpx + tenacity, structlog, Sentry. Runs in a 195 MB Alpine container, non-root, no &lt;code&gt;pip&lt;/code&gt; in the runtime image, signed with cosign. CI gate is 9 blocking jobs: Bandit, Semgrep, Ruff (security ruleset), mypy strict, pip-audit, Hadolint, Trivy (fails on &lt;code&gt;CRITICAL+HIGH &amp;gt; 0&lt;/code&gt;), SBOM publish, full pytest with 86% coverage threshold.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it won't do (yet)
&lt;/h2&gt;

&lt;p&gt;Honesty section:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a TIP replacement.&lt;/strong&gt; No actor or campaign attribution, no malware-family clustering, no IOC enrichment beyond what the source feeds publish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No STIX 2.1 / TAXII export yet.&lt;/strong&gt; That's M5 on the roadmap — needed for enterprise TIP ingestion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GHSA collector is in soft-fail mode&lt;/strong&gt; in production. It runs, but GraphQL rate-limiting still bites occasionally and I haven't fully stabilised the cursor pagination. NVD and KEV are the reliable spine right now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No webhook alerting yet.&lt;/strong&gt; Poll the dashboard endpoint, or subscribe to the RSS feed. M4 will fix this.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of those are blockers for your team, the issues board is the right place to say so — priority follows usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it / contribute
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://threat-intel-api-production.up.railway.app/" rel="noopener noreferrer"&gt;Live API&lt;/a&gt; — public, no auth&lt;/li&gt;
&lt;li&gt;&lt;a href="https://threat-intel-api-production.up.railway.app/docs" rel="noopener noreferrer"&gt;Swagger UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://threat-intel-api-production.up.railway.app/api/v1/sectors/finance/dashboard" rel="noopener noreferrer"&gt;Finance dashboard sample&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Setounkpe7/threat-intel-api" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Setounkpe7/threat-intel-api/issues" rel="noopener noreferrer"&gt;Issues board&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where help would actually matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sector profiles.&lt;/strong&gt; A payments analyst can ship a better &lt;code&gt;finance.yaml&lt;/code&gt; than I can. Same for a clinical-systems engineer on healthcare, or an OT engineer on ICS. Open a PR with a YAML and a one-paragraph rationale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GHSA stabilisation.&lt;/strong&gt; GraphQL pagination and rate-limit handling in &lt;code&gt;collectors/ghsa.py&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M4 webhook alerting.&lt;/strong&gt; The shape is sketched in the roadmap. Looking for someone who's done webhook delivery at scale (retries, signing, dead-letter handling).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run it locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Setounkpe7/threat-intel-api.git
&lt;span class="nb"&gt;cd &lt;/span&gt;threat-intel-api
docker compose up
&lt;span class="c"&gt;# API on :8000, Swagger at /docs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






</description>
      <category>cybersecurity</category>
      <category>osint</category>
      <category>python</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
