External CVE / threat feeds. Background poller fetches at each feed's interval; items land in Intel. Force-fetch and validator are below each feed.
Additive, not a replacement.
Feeds supplement the existing scanner pipeline (pip_audit, grype, osv_scanner, dependency_check, etc.) — they don't replace it.
Scanner findings remain the source of truth for what's actually in your apps; intel items provide external context (severity scoring, disclosure timing, mitigation links) for the same CVEs.
Cross-references are visible on each Finding detail page when a CVE id matches.
Add a feed
Configured feeds
{% macro feed_row(f, show_history=True) -%}
{{ f.name }}{% if not f.enabled %} paused{% endif %}
{{ total_feeds }} feed{{ 's' if total_feeds != 1 else '' }} total
{%- if groups %} · {{ ungrouped|length }} individual · {{ groups|length }} group{{ 's' if groups|length != 1 else '' }} ({{ groups|sum(attribute='count') }} feeds collapsed){% endif %}
{# Ungrouped feeds — the user's hand-curated set sits in the main table. #}
{% if ungrouped %}
Name
URL
Format
Poll
Status
Last fetch
Items / new
Actions
{% for f in ungrouped %}
{{ feed_row(f, show_history=True) }}
{% endfor %}
{% endif %}
{# Auto-collapsed groups — large clusters of feeds sharing a URL prefix
(e.g. cvedaily.com/feed-tags/* with 800+ per-tag feeds) get hidden
behind a so the main view stays scannable. #}
{% for g in groups %}
{{ g.prefix }}{{ g.count }} feeds{{ g.ok }} ok
{% if g.errored %}{{ g.errored }} errored{% endif %}
{% if g.never %}{{ g.never }} never fetched{% endif %}
items in store: {{ g.total_items }}
{% if g.last_fetch_ts %}last fetch: {{ g.last_fetch_ts|localtime }}{% endif %}
Name
URL
Format
Poll
Status
Last fetch
Items / new
Actions
{% for f in g.feeds %}
{{ feed_row(f, show_history=False) }}
{% endfor %}