Cyber Weather in your SOC dashboard
Today’s global threat condition, the flaws CISA confirmed as exploited this week and three things to do, as one JSON document your SIEM or wallboard can read. No key, no sign-up.
The feed
One GET returns the day’s reading: https://www.bitscore.in/api/connector/cyber_weather_today. The answer has two parts: text, a summary to quote, and data, the same facts as fields. The same data is the cyber_weather_today tool on the MCP connector, and the OpenAPI description covers both.
- The condition.
condition(clear, cloudy, showers, storm, severe),pointsofmax_points, andparts: each of the five instruments with its points and what it read. - The dates.
issued_foris the IST day of the forecast,data_daythe UTC day the figures describe,fetched_atwhen the feeds were read. - The detail.
kev_7d(CISA’s exploited flaws this week, with ransomware use and due dates),epss_risersandwatch_list,outlook,traffic,patch_calendar,outagesandactions. - Where it came from.
sourceslists every source with its licence, andfield_sourcessays which source each field is drawn from.
The schema is versioned (schema_version, now 1.0). New fields may be added within a version; a field is renamed or removed only with a new major version.
When to poll
- The reading is rebuilt daily at 07:30 IST (02:00 UTC), with a catch-up at 08:30 IST if a feed failed. Poll once a day, after 08:45 IST (03:15 UTC).
- Responses are cached until shortly after the next refresh, so polling more often returns the same reading. Requests are rate-limited per IP address.
- If a refresh fails, the previous reading stays up with its own date.
staleturnstrueonce it is more than 26 hours old; alert on that rather than on the HTTP status. - There is no SLA. It is a free, best-effort feed from public sources, and a source can be late or change its format.
curl
curl -s https://www.bitscore.in/api/connector/cyber_weather_today \
| jq '.data | {issued_for, condition_label, points, max_points, stale}'Splunk
A scripted input in its own app. Make the script executable, and create the index first or change it.
#!/bin/sh
curl -sf --max-time 30 https://www.bitscore.in/api/connector/cyber_weather_today
echo[script://$SPLUNK_HOME/etc/apps/bitscore_cyber_weather/bin/cyber_weather.sh]
# 08:45 IST is 03:15 UTC. The schedule runs in the Splunk server's time zone.
interval = 15 3 * * *
index = threat_intel
sourcetype = bitscore:cyber_weather
disabled = 0[bitscore:cyber_weather]
KV_MODE = json
SHOULD_LINEMERGE = false
TRUNCATE = 0
DATETIME_CONFIG = CURRENTTRUNCATE = 0 matters: a busy week’s reading runs past Splunk’s default 10,000-byte event limit. Then:
index=threat_intel sourcetype=bitscore:cyber_weather
| head 1
| table data.issued_for data.condition_label data.points data.max_points data.staleMicrosoft Sentinel
A Logic App that reads the feed each morning and sends one row to a custom table through the Logs Ingestion API.
- In the Sentinel workspace, create a DCR-based custom table named
CyberWeather(Tables → Create → New custom log). Use a data collection endpoint, and give it the columnsTimeGenerated(datetime),IssuedForandCondition(string),Points(int),Stale(boolean) andFeed(dynamic). - Create a Logic App with a system-assigned managed identity, and give that identity the Monitoring Metrics Publisher role on the data collection rule.
- Paste the workflow below into the code view, with your endpoint and the rule’s immutable ID.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"triggers": {
"Daily_0845_IST": {
"type": "Recurrence",
"recurrence": {
"frequency": "Day",
"interval": 1,
"timeZone": "India Standard Time",
"schedule": { "hours": ["8"], "minutes": [45] }
}
}
},
"actions": {
"Get_Cyber_Weather": {
"type": "Http",
"runAfter": {},
"inputs": { "method": "GET", "uri": "https://www.bitscore.in/api/connector/cyber_weather_today" }
},
"Send_to_Log_Analytics": {
"type": "Http",
"runAfter": { "Get_Cyber_Weather": ["Succeeded"] },
"inputs": {
"method": "POST",
"uri": "https://<your-dce>.ingest.monitor.azure.com/dataCollectionRules/<dcr-immutable-id>/streams/Custom-CyberWeather_CL?api-version=2023-01-01",
"headers": { "Content-Type": "application/json" },
"body": [
{
"TimeGenerated": "@{utcNow()}",
"IssuedFor": "@{body('Get_Cyber_Weather')?['data']?['issued_for']}",
"Condition": "@{body('Get_Cyber_Weather')?['data']?['condition']}",
"Points": "@body('Get_Cyber_Weather')?['data']?['points']",
"Stale": "@body('Get_Cyber_Weather')?['data']?['stale']",
"Feed": "@body('Get_Cyber_Weather')?['data']"
}
],
"authentication": { "type": "ManagedServiceIdentity", "audience": "https://monitor.azure.com" }
}
}
},
"outputs": {}
}
}CyberWeather_CL
| summarize arg_max(TimeGenerated, *) by IssuedFor
| project IssuedFor, Condition, Points, Stale
| order by IssuedFor descElastic
Filebeat’s HTTP JSON input. Hourly is fine, because the response is cached; the fingerprint gives each reading one document, so repeat polls overwrite rather than duplicate.
filebeat.inputs:
- type: httpjson
id: bitscore-cyber-weather
interval: 1h
request.url: https://www.bitscore.in/api/connector/cyber_weather_today
request.method: GET
processors:
- decode_json_fields:
fields: ["message"]
target: "bitscore"
- fingerprint:
fields: ["bitscore.data.issued_for", "bitscore.data.fetched_at"]
target_field: "@metadata._id"
- drop_fields:
fields: ["message", "bitscore.text"]Grafana
The Infinity data source plugin. Provision it with the site allowed, then add a table panel with the query below. For a stat panel of the condition, set the root selector to data and pick condition_label, points and stale.
apiVersion: 1
datasources:
- name: BitScore Cyber Weather
type: yesoreyeram-infinity-datasource
jsonData:
allowedHosts:
- https://www.bitscore.in{
"refId": "A",
"type": "json",
"source": "url",
"parser": "backend",
"format": "table",
"url": "https://www.bitscore.in/api/connector/cyber_weather_today",
"url_options": { "method": "GET" },
"root_selector": "data.parts",
"columns": [
{ "selector": "label", "text": "Instrument", "type": "string" },
{ "selector": "points", "text": "Points", "type": "number" },
{ "selector": "max_points", "text": "Out of", "type": "number" }
]
}Badge for wallboards and intranets
Today’s condition as an image, updated with each refresh.
<a href="https://www.bitscore.in/cyber-weather?utm_source=badge&utm_medium=embed&utm_campaign=cyber-weather">
<img src="https://www.bitscore.in/cyber-weather/badge.svg" width="280" height="64"
alt="Today’s Cyber Weather by BitScore">
</a>Credit and licences
Show Cyber Weather by BitScore with a link to the forecast page wherever the data appears. Each source keeps its own terms, listed in the feed’s sources:
- Non-commercial. Fields from SANS ISC (traffic, ports, Infocon, and the wind and pressure instruments) are CC BY-NC-SA 4.0; Cloudflare Radar’s outages and DDoS trend are CC BY-NC 4.0. Inside a commercial product or service, leave those fields out or ask the source.
- Open. CISA’s KEV is public domain, abuse.ch data is CC0, EPSS is free with credit to FIRST, and CVE records follow the CVE Program’s terms of use.
What the feed is not
Indicative only, and not a measure of any organisation’s risk. Cyber Weather reports aggregate, public signals and names no affected organisation.