Threat Hunting cookbook

Copy-paste recipes for hunting with TweetFeed IOCs in your terminal, SIEM, Threat Intelligence platform and detection content.


Threat Hunting cookbook

Copy-paste recipes for terminal, SIEM, TIP and detection content.

25
Recipes
9
Stacks covered
15 min
Feed refresh
CC0
Public domain, no auth

Get the raw IOCs

Four ways to pull the feed itself. Everything below is free, unauthenticated and CC0.

Raw feeds

REST API

#

Every window and IOC type as JSON. No key, no signup, no per-caller throttling.

Windows: today · week · month · yearRefresh: 15 min

All of today's IOCs as JSON:

curl -s https://api.tweetfeed.live/v1/today | jq .

Filter by IOC type (url, domain, ip, sha256, md5):

curl -s https://api.tweetfeed.live/v1/today/url

Combine type and tag - this week's Cobalt Strike IPs:

curl -s https://api.tweetfeed.live/v1/week/ip/CobaltStrike

Response shape, one IOC per array element:

{
  "date": "2026-05-03 06:07:00",
  "user": "PhishStats",
  "type": "domain",
  "value": "evil.example.shop",
  "tags": ["#phishing"],
  "tweet": "https://x.com/PhishStats/status/..."
}
Raw feeds

CSV download

#

The same four windows as CSV, straight off the data repo. Header: date,user,type,value,tags,tweet.

Windows: today · week · month · year

wget https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/today.csv
wget https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/week.csv
wget https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/month.csv
Raw feeds

RSS

#

The latest IOCs as an item stream, for feed readers and no-code automations.

Refresh: 15 min

curl -s https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/rss.xml
Raw feeds

Plain-text blocklists

#

Seven ready-to-consume exports of the last 30 days, one indicator per line, for Pi-hole, AdGuard Home, hosts files, dnsmasq, BIND RPZ and firewalls.

Window: 30 daysRefresh: 15 min

# Seven plain-text exports, rolling 30-day window, one indicator per line
curl -sfL https://api.tweetfeed.live/v1/blocklist/domains.txt   # bare domains (Pi-hole)
curl -sfL https://api.tweetfeed.live/v1/blocklist/hosts.txt     # 0.0.0.0 hosts file
curl -sfL https://api.tweetfeed.live/v1/blocklist/adguard.txt   # AdGuard Home
curl -sfL https://api.tweetfeed.live/v1/blocklist/dnsmasq.txt   # dnsmasq address= rules
curl -sfL https://api.tweetfeed.live/v1/blocklist/rpz.txt       # BIND RPZ zone
curl -sfL https://api.tweetfeed.live/v1/blocklist/ips.txt       # bare IPs
curl -sfL https://api.tweetfeed.live/v1/blocklist/urls.txt      # full URLs, not just hosts

urls.txt is the exception: it carries the full URL rather than the host, so it also covers IOCs sitting on shared infrastructure that host-level blocking cannot reach without collateral damage. These files are a 1:1 mirror of the feed with no extra quality gate - pair them with an allowlist.


Terminal & shell

Recipes you can paste into a shell right now. All of them return clean stdout, ready to pipe.

Terminal

Daily blocklist refresh

#

Rewrites a flat file every 15 minutes, ready for a firewall or proxy to reload.

Window: todayRefresh: 15 min

*/15 * * * * curl -sfL https://api.tweetfeed.live/v1/today/url \
  | jq -r '.[].value' | sort -u > /etc/blocklists/tweetfeed-urls.txt
Terminal

Slice by malware family

#

Only the IPs tagged Cobalt Strike this week. Swap the tag for any of the tracked hashtags.

Window: week

curl -sL https://api.tweetfeed.live/v1/week/ip/CobaltStrike | jq -r '.[].value'
Terminal

Pivot from a researcher

#

Every IOC published in the last 30 days by one handle, filtered server-side: a researcher handle is a valid path filter as long as you keep the leading @.

Window: month

curl -sL https://api.tweetfeed.live/v1/month/@malwrhunterteam \
  | jq -r '.[] | "\(.type)\t\(.value)\t\(.tags|join(","))"'
Terminal

IOC to source tweet

#

Every IOC carries provenance. Resolve one back to the post it came from before you alert on it.

Window: today

curl -sL https://api.tweetfeed.live/v1/today \
  | jq -r '.[] | select(.value=="evil.example.com") | .tweet'
Terminal

Active campaigns

#

The daily clustering run, ranked by how many IOCs each campaign produced in the last 7 days.

Window: 30 daysRefresh: daily

curl -sL https://api.tweetfeed.live/v1/campaigns \
  | jq -r '.campaigns[] | select(.ioc_count_7d > 0)
           | "\(.ioc_count_7d)\t\(.confidence)\t\(.name)"' | sort -rn

Splunk

Keep a TweetFeed lookup table current, then join it against your indexes.

Splunk

Refresh the lookup table

#

A saved search that keeps the TweetFeed lookup current, in savedsearches.conf. Every query below reads from it.

Refresh: 15 min

[TweetFeed_today_lookup_refresh]
search = | inputlookup append=t external_lookup tweetfeed_today.csv \
         | outputlookup tweetfeed_today.csv
cron_schedule = */15 * * * *
dispatch.earliest_time = -15m
enableSched = 1
Splunk

Match proxy logs against URLs and domains

#

A subsearch turns the lookup into a filter, then groups the hits by source host so you see who reached what.

Window: today

index=proxy [
  | inputlookup tweetfeed_today.csv
  | where type IN ("url","domain")
  | rename value AS url
  | fields url
] | stats count, values(tags), values(tweet) by src_ip, url
Splunk

DNS query enrichment

#

Any DNS query in the last 7 days that resolved a TweetFeed domain, carrying the tags and the source tweet along for triage.

Window: week

index=dns sourcetype=dns:query [
  | inputlookup tweetfeed_week.csv
  | where type="domain" | rename value AS query | fields query
] | table _time, src_ip, query, [tweetfeed.tags], [tweetfeed.tweet]

Save this one as a Notable Event with severity=medium and trigger it as soon as count > 0 to turn it into a real-time alert.


Microsoft Sentinel

No connector needed: externaldata() reads the CSV straight off the data repo at query time.

Sentinel

DNS hits with externaldata()

#

Reads today.csv at query time - no connector, no ingestion cost - and joins it against DnsEvents.

Window: todayLookback: 24h

let TweetFeedDomains = externaldata(date:string, user:string, type:string, value:string, tags:string, tweet:string)
  [@"https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/today.csv"]
  with (format="csv")
  | where type == "domain"
  | project Domain = value, Tags = tags, Tweet = tweet;
DnsEvents
| where TimeGenerated > ago(24h)
| where Name in (TweetFeedDomains | project Domain)
| join kind=leftouter TweetFeedDomains on $left.Name == $right.Domain
| project TimeGenerated, Computer, ClientIP, Name, Tags, Tweet
Sentinel

Logon sources against TweetFeed IPs

#

The same pattern over week.csv and SecurityEvent, to catch authentication from a flagged address.

Window: weekLookback: 7d

let TweetFeedIPs = externaldata(date:string, user:string, type:string, value:string, tags:string, tweet:string)
  [@"https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/week.csv"]
  with (format="csv")
  | where type == "ip"
  | project IPAddress = value, Tags = tags, Tweet = tweet;
SecurityEvent
| where TimeGenerated > ago(7d)
| where IpAddress in (TweetFeedIPs | project IPAddress)
| join kind=leftouter TweetFeedIPs on $left.IpAddress == $right.IPAddress
| project TimeGenerated, Computer, Account, IpAddress, Tags, Tweet

Microsoft Defender for Endpoint

Advanced hunting queries covering all four IOC types. Swap week.csv for today.csv or month.csv depending on your freshness-versus-coverage trade-off.

Defender

URLs and domains

#

Joins the URL and domain rows against DeviceNetworkEvents. The domain_whitelist array at the top is where your trusted assets go.

Window: weekLookback: 30d

Defender

IP addresses

#

Same join over the IP rows, with private ranges dropped by ipv4_is_private() so RFC1918 noise never fires.

Window: weekLookback: 30d

Defender

SHA-256 hashes

#

Unions process, file and image-load events, so a flagged hash is caught whether it ran, landed on disk or was loaded into another process.

Window: weekLookback: 30d

Defender

MD5 hashes

#

The MD5 counterpart of the query above, for the samples reported without a SHA-256.

Window: weekLookback: 30d


Elastic Stack

Index the CSV every 15 minutes, then join it from Kibana with ES|QL or alert on it with Watcher.

Elastic

Logstash ingest pipeline

#

Polls today.csv every 15 minutes and upserts into tweetfeed-iocs-*, keyed on type plus value so re-reported IOCs update in place.

Window: todayRefresh: 15 min

input {
  http_poller {
    urls => {
      tweetfeed => "https://raw.githubusercontent.com/0xDanielLopez/TweetFeed/master/today.csv"
    }
    schedule => { every => "15m" }
    codec => plain
  }
}
filter {
  split { field => "message" }
  csv {
    columns => ["date","user","type","value","tags","tweet"]
    separator => ","
  }
  date { match => ["date","ISO8601"] target => "@timestamp" }
  mutate { remove_field => ["message","event"] }
}
output {
  elasticsearch {
    hosts => ["https://es:9200"]
    index => "tweetfeed-iocs-%{+YYYY.MM.dd}"
    document_id => "%{type}-%{value}"
    action => "update"
    doc_as_upsert => true
  }
}
Elastic

ES|QL join against DNS logs

#

A LOOKUP JOIN from your DNS index into the ingested IOCs, runnable straight from Kibana Discover or Lens.

Lookback: 24h

FROM logs-network-dns-*
| WHERE @timestamp > NOW() - 24h
| LOOKUP JOIN tweetfeed-iocs-* ON dns.question.name == value
| WHERE type == "domain"
| KEEP @timestamp, host.name, source.ip, dns.question.name, tags, tweet
| SORT @timestamp DESC
| LIMIT 1000
Elastic

Watcher alert

#

Fires whenever an internal endpoint resolves a TweetFeed domain. Save it under Stack Management → Watcher.

Interval: 15 min

{
  "trigger": { "schedule": { "interval": "15m" } },
  "input": {
    "search": {
      "request": {
        "indices": ["logs-network-dns-*"],
        "body": {
          "query": {
            "bool": {
              "filter": [
                {"range": {"@timestamp": {"gte": "now-15m"}}},
                {"terms": {"dns.question.name": {"index": "tweetfeed-iocs-*", "id": "domain", "path": "value"}}}
              ]
            }
          },
          "size": 100
        }
      }
    }
  },
  "condition": {"compare": {"ctx.payload.hits.total.value": {"gt": 0}}},
  "actions": {
    "log": {"logging": {"text": "TweetFeed DNS hit: {{ctx.payload.hits.total.value}} events"}}
  }
}

For detection rules, tweetfeed-iocs-* also works as a value list compatible with Elastic Security's value list exceptions - same data, alert-routable.


MISP & TAXII

Two standards-based ingest paths for Threat Intelligence platforms.

MISP

MISP feed

#

A MISP-format manifest with one Event per day and 365 days of history. In MISP go to Sync Actions → Feeds → Add Feed and give it the feed directory - MISP appends /manifest.json itself.

Window: 365 days

URL:           https://tweetfeed.live/misp
Source format: misp
Provider:      TweetFeed
Auto-pull:     yes
Default tags:  TweetFeed, tlp:clear, type:OSINT

Save, click Fetch and store all feed data to seed it, then enable Cron Jobs → Feed Pull for auto-refresh.

TAXII

TAXII 2.1 collection

#

STIX 2.1 indicators over a TAXII 2.1 endpoint, for OpenCTI, ThreatQ and anything else that speaks the standard.

Window: 365 daysMedia type: taxii+json 2.1

# 1. Discovery - lists the API root and its collections
curl -s https://api.tweetfeed.live/taxii2/ \
  -H 'Accept: application/taxii+json;version=2.1'

# 2. Poll everything added since a timestamp (delta sync)
COLL=b7dc78af-1d12-5059-898c-3f0e77636204
curl -s "https://api.tweetfeed.live/taxii2/root/collections/$COLL/objects/?added_after=2026-07-01T00:00:00Z" \
  -H 'Accept: application/taxii+json;version=2.1'

Paginate with limit and next. An added_after poll returns indicators only: the identity and marking-definition objects that every indicator references were created with the collection, so they fall outside any recent window. Fetch those once by id from /objects/{id}/ so your platform can resolve the attribution and the TLP:CLEAR marking.


Detection content

A vendor-neutral rule template your Sigma pipeline can compile to any SIEM.

Sigma

Sigma rule template

#

Detects DNS lookups to a TweetFeed-listed domain. Populate %TweetFeedDomains% from your Sigma processing pipeline, e.g. a sigmac lookup expansion.

Window: weekLogsource: sysmon EventID 22

title: TweetFeed-listed Malicious Domain Resolution
id: f1c0c0d0-1111-4444-9999-aaaaaaaaaaaa
status: experimental
description: Detects DNS lookups to domains published by TweetFeed within the last week
references:
  - https://tweetfeed.live/
  - https://api.tweetfeed.live/v1/week/domain
author: TweetFeed
date: 2026/05/03
logsource:
  product: windows
  service: sysmon
detection:
  selection:
    EventID: 22
    QueryName|expand: '%TweetFeedDomains%'
  condition: selection
falsepositives:
  - Allowlisted internal infrastructure
level: medium
tags:
  - attack.command_and_control
  - attack.t1071.004

AI agents

The same corpus over the Model Context Protocol, so an agent can query it as a tool.

Agents

MCP server

#

The corpus as agent tools over the Model Context Protocol, so a coding or SOC agent can query it directly instead of scraping a CSV.

Transport: streamable HTTPTools: 10

claude mcp add --transport http tweetfeed https://mcp.tweetfeed.live/

Ten tools: query_iocs, check_url, check_ip, check_hash, list_recent_iocs, get_tag_info, get_trending, enrich_ioc, get_campaigns and get_trends. No key, no auth.


Frequently asked questions

How fresh are the IOCs?

TweetFeed scrapes the source feeds every 15 minutes via cron. The end-to-end pipeline (scrape, dedupe, classify, aggregate, push) takes roughly 17 to 25 seconds, so an IOC tweeted right now lands in today.csv and the API within one cron tick.

Is there a rate limit on the API?

api.tweetfeed.live runs as a Cloudflare Worker on the Free plan (100,000 requests per day). Real traffic sits around 7 to 8K per day, leaving roughly 300x headroom. There is no authentication or per-key throttling - please be reasonable.

Can I use TweetFeed data commercially?

Yes. The IOC data is published under CC0 1.0 (no rights reserved). Attribution is appreciated but not required. The website code, branding and logos are not included in CC0.

How do I credit the original researcher?

Every IOC carries a user field (Twitter/X handle) and a tweet field (full URL to the source post). Link back to the tweet whenever you republish or alert on an IOC.

How do I handle false positives?

TweetFeed publishes everything reasonably tagged and does not suppress noise. Use a client-side allowlist (the KQL and SPL recipes show the pattern) and report false positives via GitHub issues.

Is there an MCP server for AI agents?

Yes. mcp.tweetfeed.live exposes 10 tools: query_iocs, check_url, check_ip, check_hash, list_recent_iocs, get_tag_info, get_trending, enrich_ioc, get_campaigns and get_trends. See the Agents page for the config snippet.

How do I contribute new IOCs?

Post the IOC on Twitter/X with one of the tracked hashtags (full list on the Feeds page) or get added to the curated TweetFeedList. The next cron tick picks it up automatically.