AI Tools Blocklist
Home AI Tools Database Taxonomy Pricing
Solutions
Enterprise IT & CISO Education Firewall Admins Shadow AI Prevention REST API
Download Free Sample
Shadow AI Detection

Detect Shadow AI Usage
Through Network Intelligence

Cross-reference DNS, proxy, and traffic logs against 16,024+ classified AI domains. Surface every shadow AI tool in hours.

16,024+AI Domains Classified
102MDomains Scanned
18Functional Categories
Download Free Sample View Pricing
The Detection Gap

Why Traditional Security Tools Miss Shadow AI Entirely

AI tools require no installation, skip OAuth, and run on domains unknown to legacy threat feeds. Your security stack was not built for this.

What Your Existing Tools Miss

CASB

Flags Dropbox OAuth but misses employees pasting drafts into AI writing assistants on brand-new domains.

EDR / Endpoint

Alerts on unauthorized executables but ignores browser tabs sending source code to AI debugging services over HTTPS.

DLP

Inspects outbound email attachments but cannot inspect text pasted into web forms on unknown domains.

The Solution

Operate at the network layer where all web traffic is visible.

Data sources — DNS resolution, HTTP proxy logs, and raw traffic metadata
Reference dataset — 16,024+ AI tool domains across 18 functional categories
Continuously updated — Daily scans from a 102M+ domain pipeline

The Three Detection Layers

DNS Query Logs

Every connection starts with a DNS lookup. Correlate resolver logs against the AI tools feed to reveal every tool accessed.

Lowest friction   Broadest coverage

Proxy & SWG Logs

HTTP-level detail: full URLs, methods, content types, and bytes transferred. Large POST payloads flag data submission.

Higher fidelity   Content visibility

NetFlow & Traffic Metadata

Connection-level metadata: source, destination, duration, bytes. Detects long-lived interactive AI sessions.

No proxy needed   Protocol-agnostic

DNS Detection

DNS Log Analysis for Shadow AI Detection

DNS is the most valuable data source for shadow AI detection. Every browser navigation triggers a query your resolver already logs.

How It Works

1

Export DNS Logs

Export query logs from Infoblox, BlueCat, Microsoft DNS, or Cisco Umbrella.

2

Join Against Blocklist

Load the AI Tools Blocklist as a lookup table. Every domain match confirms AI tool access.

3

Generate Report

Rank AI tools by frequency, identify heaviest users, and break down usage across 18 categories.

This Python script processes BIND-style query logs. Modify the parsing function to adapt to any DNS format.

#!/usr/bin/env python3
"""Shadow AI detection via DNS query log analysis.
Cross-references DNS resolver logs against the AI Tools Blocklist
to identify unauthorized AI tool usage across the enterprise."""

import csv
import re
import sys
import json
from collections import Counter, defaultdict
from datetime import datetime
from pathlib import Path

def load_blocklist(csv_path: str) -> dict:
    """Load AI Tools Blocklist CSV into a domain lookup dictionary."""
    domains = {}
    with open(csv_path, "r") as f:
        reader = csv.DictReader(f)
        for row in reader:
            domains[row["domain"].strip().lower()] = {
                "category": row.get("primary_category", "Uncategorized"),
                "tool_name": row.get("tool_name", "Unknown"),
                "risk_level": row.get("risk_level", "medium"),
            }
    return domains

def parse_bind_log(log_path: str):
    """Parse BIND/named query log lines.
    Expected format: DD-Mon-YYYY HH:MM:SS.mmm ... query: domain IN A ... (client_ip)
    Yields (timestamp_str, client_ip, queried_domain) tuples."""
    pattern = re.compile(
        r"(\d{2}-\w{3}-\d{4}\s+\d{2}:\d{2}:\d{2})\.\d+\s+"
        r".*query:\s+([\w.\-]+)\s+IN\s+\w+.*\((\d+\.\d+\.\d+\.\d+)\)"
    )
    with open(log_path, "r") as f:
        for line in f:
            m = pattern.search(line)
            if m:
                yield m.group(1), m.group(3), m.group(2).lower().rstrip(".")

def extract_root_domain(fqdn: str) -> str:
    """Extract registrable domain from FQDN for matching."""
    parts = fqdn.split(".")
    if len(parts) >= 2:
        return ".".join(parts[-2:])
    return fqdn

def detect_shadow_ai(log_path: str, blocklist_path: str):
    """Main detection: correlate DNS logs against AI tools blocklist."""
    ai_domains = load_blocklist(blocklist_path)
    hits = defaultdict(lambda: {
        "clients": Counter(),
        "first_seen": None,
        "last_seen": None,
        "total_queries": 0,
    })
    category_stats = Counter()
    total_queries = 0
    matched_queries = 0

    for ts, client_ip, domain in parse_bind_log(log_path):
        total_queries += 1
        root = extract_root_domain(domain)
        match_domain = domain if domain in ai_domains else (
            root if root in ai_domains else None
        )
        if match_domain:
            matched_queries += 1
            entry = hits[match_domain]
            entry["clients"][client_ip] += 1
            entry["total_queries"] += 1
            if not entry["first_seen"] or ts < entry["first_seen"]:
                entry["first_seen"] = ts
            if not entry["last_seen"] or ts > entry["last_seen"]:
                entry["last_seen"] = ts
            category_stats[ai_domains[match_domain]["category"]] += 1

    # Generate report
    report = {
        "scan_date": datetime.now().isoformat(),
        "total_dns_queries": total_queries,
        "ai_tool_queries": matched_queries,
        "unique_ai_domains": len(hits),
        "unique_clients": len(set(
            ip for h in hits.values() for ip in h["clients"]
        )),
        "category_breakdown": dict(category_stats.most_common()),
        "top_domains": [],
    }

    for domain, data in sorted(
        hits.items(), key=lambda x: x[1]["total_queries"], reverse=True
    )[:50]:
        info = ai_domains[domain]
        report["top_domains"].append({
            "domain": domain,
            "tool_name": info["tool_name"],
            "category": info["category"],
            "risk_level": info["risk_level"],
            "total_queries": data["total_queries"],
            "unique_clients": len(data["clients"]),
            "first_seen": data["first_seen"],
            "last_seen": data["last_seen"],
        })

    return report

if __name__ == "__main__":
    report = detect_shadow_ai(sys.argv[1], sys.argv[2])
    print(json.dumps(report, indent=2))
    print(f"\n{'='*60}")
    print(f"Shadow AI Detection Report — {report['scan_date'][:10]}")
    print(f"{'='*60}")
    print(f"Total DNS queries analyzed:  {report['total_dns_queries']:,}")
    print(f"AI tool queries detected:   {report['ai_tool_queries']:,}")
    print(f"Unique AI tool domains:     {report['unique_ai_domains']}")
    print(f"Unique client IPs:          {report['unique_clients']}")
    print(f"\nTop 20 Shadow AI Tools:")
    for i, d in enumerate(report["top_domains"][:20], 1):
        print(f"  {i:2}. {d['domain']:<35} {d['category']:<25} "
              f"queries={d['total_queries']:<8} users={d['unique_clients']}")

What This Script Reveals

Typical Results

40-200 distinct AI domains found in one week of logs
The long tail of obscure, new tools is where manual blocklists fail

Subdomain Matching

extract_root_domain matches both FQDNs and root domains
Use tldextract for public suffix handling in production

Scaling DNS Detection with Streaming Analysis

Batch processing works for audits. For continuous monitoring, stream DNS queries and alert in near-real-time.

#!/usr/bin/env python3
"""Real-time shadow AI detection — tail DNS logs and alert on AI tool queries."""

import csv
import time
import json
import re
import logging
from pathlib import Path
from datetime import datetime, timedelta
from collections import defaultdict

logging.basicConfig(level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("shadow_ai_monitor")

class ShadowAIMonitor:
    def __init__(self, blocklist_path: str, alert_threshold: int = 5):
        self.ai_domains = self._load_blocklist(blocklist_path)
        self.alert_threshold = alert_threshold
        self.window = defaultdict(lambda: defaultdict(int))
        self.window_start = datetime.now()
        self.alerted = set()
        logger.info(f"Loaded {len(self.ai_domains):,} AI tool domains")

    def _load_blocklist(self, path: str) -> dict:
        domains = {}
        with open(path) as f:
            for row in csv.DictReader(f):
                domains[row["domain"].strip().lower()] = row
        return domains

    def _resolve_domain(self, fqdn: str):
        """Match FQDN or root domain against blocklist."""
        if fqdn in self.ai_domains:
            return fqdn
        root = ".".join(fqdn.split(".")[-2:])
        return root if root in self.ai_domains else None

    def process_query(self, client_ip: str, domain: str):
        matched = self._resolve_domain(domain.lower().rstrip("."))
        if not matched:
            return
        self.window[matched][client_ip] += 1
        info = self.ai_domains[matched]
        total = sum(self.window[matched].values())

        if total >= self.alert_threshold and matched not in self.alerted:
            self.alerted.add(matched)
            alert = {
                "alert_type": "shadow_ai_detected",
                "domain": matched,
                "tool_name": info.get("tool_name", "Unknown"),
                "category": info.get("primary_category", "Unknown"),
                "unique_users": len(self.window[matched]),
                "total_queries": total,
                "timestamp": datetime.now().isoformat(),
            }
            logger.warning(f"SHADOW AI ALERT: {json.dumps(alert)}")
            self._send_to_siem(alert)

    def _send_to_siem(self, alert: dict):
        """Forward alert to SIEM via syslog, webhook, or file."""
        with open("/var/log/shadow_ai_alerts.json", "a") as f:
            f.write(json.dumps(alert) + "\n")

    def rotate_window(self, interval_minutes: int = 60):
        if datetime.now() - self.window_start > timedelta(minutes=interval_minutes):
            self.window.clear()
            self.alerted.clear()
            self.window_start = datetime.now()
            logger.info("Detection window rotated")

Streaming Monitor Capabilities

Sliding Window

Groups queries by domain and client IP within configurable time intervals.

Threshold Alerting

Fires structured JSON alerts when a domain crosses the configured query count.

Window Rotation

Resets counters on a configurable interval to prevent alert fatigue.

Recommended Settings

1-hour window with threshold of 5 queries filters DNS prefetch noise from real usage.

Proxy Detection

Proxy and Secure Web Gateway Log Analysis

DNS Tells You What

Which AI tools are accessed. Could be a brief visit, curiosity click, or accidental navigation.

Proxy Tells You How Much

HTTP methods, content types, and bytes transferred in each direction reveal actual data submission.

Key Signal

POST requests carrying 5KB-500KB payloads to an AI domain are a near-certain indicator of content submission.

This script processes Squid-format logs. Adapts to Blue Coat, Zscaler, Netskope, or any SWG.

#!/usr/bin/env python3
"""Proxy log analysis for shadow AI detection with data exfiltration scoring.
Parses Squid/SWG access logs, correlates against AI Tools Blocklist,
and scores sessions by data leakage risk."""

import csv
import re
import sys
from collections import defaultdict
from dataclasses import dataclass, field
from urllib.parse import urlparse

@dataclass
class AIToolSession:
    domain: str = ""
    category: str = ""
    tool_name: str = ""
    get_count: int = 0
    post_count: int = 0
    bytes_sent: int = 0
    bytes_received: int = 0
    client_ips: set = field(default_factory=set)
    timestamps: list = field(default_factory=list)

    @property
    def risk_score(self) -> int:
        """Score 0-100 based on data submission indicators."""
        score = 0
        if self.post_count > 0: score += 30
        if self.bytes_sent > 10_000: score += 20
        if self.bytes_sent > 100_000: score += 15
        if self.post_count > 5: score += 15
        if len(self.client_ips) > 3: score += 10
        if self.bytes_sent > self.bytes_received: score += 10
        return min(score, 100)

def analyze_proxy_logs(log_path: str, blocklist_path: str):
    """Parse proxy logs and identify AI tool sessions with risk scoring."""
    ai_domains = {}
    with open(blocklist_path) as f:
        for row in csv.DictReader(f):
            ai_domains[row["domain"].strip().lower()] = row

    sessions = defaultdict(AIToolSession)
    # Squid log pattern: timestamp elapsed client action/code size method URL
    squid_re = re.compile(
        r"(\d+\.\d+)\s+\d+\s+([\d.]+)\s+\w+/(\d+)\s+(\d+)\s+(\w+)\s+(https?://\S+)"
    )

    with open(log_path) as f:
        for line in f:
            m = squid_re.search(line)
            if not m:
                continue
            ts, client_ip, status, size, method, url = m.groups()
            domain = urlparse(url).hostname
            if not domain:
                continue
            root = ".".join(domain.split(".")[-2:])
            matched = domain if domain in ai_domains else (
                root if root in ai_domains else None
            )
            if not matched:
                continue

            s = sessions[matched]
            s.domain = matched
            s.category = ai_domains[matched].get("primary_category", "")
            s.tool_name = ai_domains[matched].get("tool_name", "")
            s.client_ips.add(client_ip)
            s.timestamps.append(float(ts))
            if method == "POST":
                s.post_count += 1
                s.bytes_sent += int(size)
            elif method == "GET":
                s.get_count += 1
                s.bytes_received += int(size)

    # Output ranked by risk score
    print(f"{'Domain':<35} {'Category':<22} {'Risk':>4}  {'POSTs':>5}  {'Sent':>10}  {'Users':>5}")
    print("─" * 95)
    for s in sorted(sessions.values(), key=lambda x: x.risk_score, reverse=True):
        sent_kb = f"{s.bytes_sent / 1024:.1f} KB"
        print(f"{s.domain:<35} {s.category:<22} {s.risk_score:>4}  {s.post_count:>5}  {sent_kb:>10}  {len(s.client_ips):>5}")

analyze_proxy_logs(sys.argv[1], sys.argv[2])

Risk Scoring Breakdown

Indicator Points Interpretation
Any POST request +30 Content submission — text, files, or form data
Bytes sent > 10 KB +20 Substantial payload beyond simple prompts
Bytes sent > 100 KB +15 Document-sized uploads or code pastes
POST count > 5 +15 Sustained usage, not one-time curiosity
Multiple users (> 3) +10 Viral adoption across the organization
Bytes sent > received +10 Inverted ratio = uploading content, not browsing

Score 60+

Active data submission to AI tools. Immediate investigation recommended.

Score < 20

Incidental browsing, marketing pages, or API health checks. Low priority.

Behavioral Analysis

Traffic Pattern Analysis and Behavioral Detection

AI tools exhibit distinctive network signatures. Behavioral heuristics catch usage even before domains appear in any blocklist.

The "Paste-and-Wait" Signature

1

Large POST

Single large upload -- the user's pasted text, code, or files.

2

2-30s Pause

Model inference delay. Standard web apps respond in under 500ms.

3

Streamed Response

Persistent HTTP connection delivering tokens incrementally. Unlike standard page loads.

Additional Behavioral Signals

Upload-Heavy Sessions

Normal browsing: 10:1 download-to-upload ratio
AI sessions frequently invert this ratio
Flag sessions where outbound bytes approach inbound

Bursty Interaction Cadence

Repeated paste-and-wait cycles at regular intervals
Distinct from rapid page loads or steady media streams
Regular POST intervals between 30s and 5 minutes

Layered Detection: Domain + Behavioral

Domain Match = "Confirmed Shadow AI"

Domain in the blocklist means it is definitively an AI tool. Generate immediate alerts.

Behavioral Match = "Suspected AI Tool"

Queue for analyst review. Covers the 24-72 hour gap before blocklist inclusion.

Coverage by Detection Layer

85% DNS Only
93% DNS + Proxy
95%+ DNS + Proxy + Behavioral

The remaining ~5% is AI accessed via personal devices on cellular connections. Address through endpoint controls and user education.

Operationalization

SIEM Integration and Detection Metrics

Detection outputs integrate into your existing SIEM. The scripts output structured JSON for ingestion via any method.

Splunk Microsoft Sentinel Elastic QRadar File Forwarder Syslog Direct API

Alert Rules

New AI domains not previously seen High-risk category usage Bulk data submission patterns Privileged account usage

Dashboards

Unique AI tools over time Top categories by query volume Departments with highest usage Data volume per day

Compliance Reports

Blocklist coverage statistics Detection-to-enforcement latency False positive rates Policy violation trends

Key Detection Metrics

Coverage

Percentage of AI tool usage your program identifies. Compare detected domains against the full blocklist.

Accuracy

Under 2% false positive rate thanks to manual verification in the curation pipeline.

Latency

Known domains: effectively zero
New tools: 24 hours standard, intraday on enterprise tiers

Operational Impact

Tools blocked, violations investigated
Exfiltration incidents prevented

False Positive Tuning

Incorrectly Flagged Domains

Rare with a curated blocklist (under 2% FP rate)
Submit for reclassification; add to local allowlist pending update

Sanctioned Tools Generating Alerts

Maintain an "approved AI tools" allowlist
When sanctioned via AUP process, add domains to suppress alerts

Tiered Approval Model

1

Fully Approved

No alerts generated.

2

Conditionally Approved

Informational alerts feed dashboards. No incident response.

3

Prohibited

High-severity alerts with automated manager and SOC notification.

Implementation Guide

Shadow AI Detection Deployment Roadmap

No new infrastructure, vendors, or procurement cycles required. The AI Tools Blocklist is the missing intelligence layer.

1

Week 1

Download AI Tools Blocklist Run DNS analysis on one week of logs Produce baseline shadow AI inventory
2

Weeks 2-3

Add proxy log analysis Deploy streaming DNS monitor Integrate outputs into SIEM
3

Weeks 4-6

Configure alerts and dashboards Establish approved/prohibited tiers Begin network blocking
4

Ongoing

Automated daily blocklist updates Weekly detection reports Monthly metrics reviews

Staffing

One security engineer for initial setup Under two weeks to full capability Less than two hours per week ongoing

Auto-Updates

Daily blocklist updates eliminate curation burden ~200 new AI tools identified per week Automatically added to your feed

Start Detecting Shadow AI Today

Most enterprises discover 50-200 shadow AI tools in their first scan. Request a trial to unlock the full 16,024+ domain feed.

Request Shadow AI Detection Trial

Tell us about your environment and detection goals — we will provide a tailored trial of the full AI tools domain feed.