Generate 3,000 Suricata-style intrusion detection alerts with realistic IP distributions, severity spikes, and protocol mix. 30 days of synthetic SOC data.
This script generates realistic IDS alert data. Source IPs include repeat offenders from internal ranges and random external addresses. Severity follows a pyramid distribution: mostly low, few critical. Alert categories span recon, port scans, malware C2, brute force, and lateral movement.
-- demo_security.lua — Network IDS alerts (3,000 alerts over 30 days)
--
-- Simulates Suricata-style alert data with realistic IP distributions,
-- severity spikes, and protocol mix. Great for timeline scrubbing
-- and City View (height=severity, color=alert_category, district=action).
ds.log("=== Network Security Alerts Demo ===")
ds.query([[
SELECT
-- Timestamps spread over 30 days with some clustering
timestamp '2025-12-01 00:00:00'
+ INTERVAL (floor(random() * 30)::int) DAY
+ INTERVAL (floor(random() * 86400)::int) SECOND AS timestamp,
-- Source IPs: mix of internal ranges with a few repeat offenders
CASE
WHEN random() < 0.15 THEN '10.0.1.' || (100 + (i % 5))
WHEN random() < 0.35 THEN '192.168.' || (1 + (i % 3)) || '.' || (10 + floor(random() * 240)::int)
WHEN random() < 0.60 THEN '172.16.' || floor(random() * 16)::int || '.' || floor(random() * 254 + 1)::int
ELSE floor(random() * 223 + 1)::int || '.' || floor(random() * 254 + 1)::int || '.' || floor(random() * 254 + 1)::int || '.' || floor(random() * 254 + 1)::int
END AS src_ip,
-- Destination IPs: mostly internal servers
CASE
WHEN random() < 0.40 THEN '10.0.0.' || (1 + (i % 20))
WHEN random() < 0.70 THEN '10.0.1.' || (1 + floor(random() * 50)::int)
ELSE '10.0.2.' || (1 + floor(random() * 10)::int)
END AS dst_ip,
-- Ports
CASE
WHEN random() < 0.30 THEN 443
WHEN random() < 0.50 THEN 80
WHEN random() < 0.65 THEN 22
WHEN random() < 0.75 THEN 53
WHEN random() < 0.85 THEN 8080
ELSE floor(random() * 60000 + 1024)::int
END AS dst_port,
-- Protocol
CASE
WHEN random() < 0.55 THEN 'TCP'
WHEN random() < 0.80 THEN 'UDP'
WHEN random() < 0.92 THEN 'ICMP'
ELSE 'DNS'
END AS protocol,
-- Alert severity 1-4 (most are low)
CASE
WHEN random() < 0.05 THEN 1 -- critical
WHEN random() < 0.20 THEN 2 -- high
WHEN random() < 0.55 THEN 3 -- medium
ELSE 4 -- low/info
END AS severity,
-- Alert category
CASE
WHEN random() < 0.20 THEN 'Attempted Recon'
WHEN random() < 0.35 THEN 'Port Scan'
WHEN random() < 0.50 THEN 'Malware C2'
WHEN random() < 0.62 THEN 'Policy Violation'
WHEN random() < 0.72 THEN 'Brute Force'
WHEN random() < 0.82 THEN 'Data Exfiltration'
WHEN random() < 0.90 THEN 'Lateral Movement'
ELSE 'Anomalous Traffic'
END AS alert_category,
-- Bytes transferred (log-normal-ish distribution)
round(
CASE
WHEN random() < 0.6 THEN random() * 5000
WHEN random() < 0.9 THEN random() * 50000
ELSE random() * 500000 + 50000
END, 0
)::int AS bytes_transferred,
-- Action taken
CASE
WHEN random() < 0.40 THEN 'Allowed'
WHEN random() < 0.75 THEN 'Blocked'
WHEN random() < 0.90 THEN 'Alerted'
ELSE 'Quarantined'
END AS action
FROM generate_series(0, 2999) AS t(i)
ORDER BY timestamp
]])
ds.log("Generated " .. ds.data.row_count .. " alerts over 30 days")
ds.log("Columns: " .. table.concat(ds.data.column_names, ", "))
-- Line chart: alert count over time
ds.chart.type = "scatter"
ds.chart.x = 1 -- timestamp
ds.chart.y = {6} -- severity
ds.chart.title = "Alert Severity Over Time"
ds.log("=== Chart ready — switch to City View for 3D exploration ===")
ds.log(" Height: severity or bytes | Color: alert_category | District: action")
10 fields: timestamp, src_ip, dst_ip, dst_port, protocol, severity, alert_category, bytes_transferred, action.
Internal ranges (10.x, 192.168.x, 172.16.x) with repeat offenders. External IPs are randomized. Destination IPs are mostly internal servers.
SELECT alert_category, count(*) FROM _cl_result WHERE severity = 1 GROUP BY 1 ORDER BY 2 DESC
Set height to severity or bytes_transferred, color to alert_category, district to action. Critical alerts tower over noise.
Paste it into the Script Console. No data download needed.
Or try the free version (up to 100 MB)