shadowaitools 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- shadowaitools-1.0.0/LICENSE +21 -0
- shadowaitools-1.0.0/MANIFEST.in +2 -0
- shadowaitools-1.0.0/PKG-INFO +336 -0
- shadowaitools-1.0.0/README.md +300 -0
- shadowaitools-1.0.0/setup.cfg +4 -0
- shadowaitools-1.0.0/setup.py +52 -0
- shadowaitools-1.0.0/shadowaitools/__init__.py +22 -0
- shadowaitools-1.0.0/shadowaitools/__main__.py +5 -0
- shadowaitools-1.0.0/shadowaitools/cli.py +107 -0
- shadowaitools-1.0.0/shadowaitools/client.py +98 -0
- shadowaitools-1.0.0/shadowaitools/inventory.py +184 -0
- shadowaitools-1.0.0/shadowaitools/parser.py +266 -0
- shadowaitools-1.0.0/shadowaitools.egg-info/PKG-INFO +336 -0
- shadowaitools-1.0.0/shadowaitools.egg-info/SOURCES.txt +16 -0
- shadowaitools-1.0.0/shadowaitools.egg-info/dependency_links.txt +1 -0
- shadowaitools-1.0.0/shadowaitools.egg-info/entry_points.txt +2 -0
- shadowaitools-1.0.0/shadowaitools.egg-info/requires.txt +1 -0
- shadowaitools-1.0.0/shadowaitools.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alpha Quantum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: shadowaitools
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Shadow AI detection from the logs you already have: parse a DNS, proxy or firewall export locally, look up each unique domain against the AI Tools Blocklist, and get an inventory of the AI tools in use with category, AI type and vendor training verdicts.
|
|
5
|
+
Home-page: https://www.shadowaitools.com
|
|
6
|
+
Author: Alpha Quantum
|
|
7
|
+
Author-email: info@alpha-quantum.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://www.shadowaitools.com
|
|
10
|
+
Project-URL: Documentation, https://www.shadowaitools.com
|
|
11
|
+
Project-URL: Source, https://github.com/explainableaixai/shadowaitools
|
|
12
|
+
Project-URL: Tracker, https://www.shadowaitools.com/contact.php
|
|
13
|
+
Project-URL: AI Tools Blocklist, https://www.aitoolsblocklist.com
|
|
14
|
+
Project-URL: AI Agent Allow List, https://www.aiagentallowlist.com
|
|
15
|
+
Project-URL: Shadow AI Tools, https://www.shadowaitools.com
|
|
16
|
+
Keywords: shadow ai,shadow ai detection,shadow ai tools,shadow ai discovery,ai tools inventory,dns log analysis,proxy log analysis,firewall log,ai governance,ai acceptable use,data loss prevention,ai blocklist,generative ai usage,ai risk management
|
|
17
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
18
|
+
Classifier: Environment :: Console
|
|
19
|
+
Classifier: Intended Audience :: Information Technology
|
|
20
|
+
Classifier: Intended Audience :: System Administrators
|
|
21
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
22
|
+
Classifier: Programming Language :: Python :: 3
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
29
|
+
Classifier: Topic :: Security
|
|
30
|
+
Classifier: Topic :: System :: Networking :: Monitoring
|
|
31
|
+
Classifier: Topic :: System :: Systems Administration
|
|
32
|
+
Requires-Python: >=3.7
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
License-File: LICENSE
|
|
35
|
+
Requires-Dist: requests>=2.20.0
|
|
36
|
+
|
|
37
|
+
# shadowaitools
|
|
38
|
+
|
|
39
|
+
`shadowaitools` turns a DNS, proxy or firewall export into an inventory of the AI tools in use on your network. It runs on your own machine: the export is parsed locally, every hostname is reduced to its registrable domain, and each unique domain is looked up once against the [AI blocklist for web filtering](https://www.aitoolsblocklist.com) at aitoolsblocklist.com. What comes back is a list of tools with category, AI type, hit counts, the users or devices that reached them, and the vendor's position on training with your data, dated.
|
|
40
|
+
|
|
41
|
+
It is the command line and Python counterpart of the hosted service at shadowaitools.com, which lets you [find the AI tools employees use](https://www.shadowaitools.com) from the same export in a browser and produces the per-user breakdown, the sanctioned versus unsanctioned split and a PDF evidence pack.
|
|
42
|
+
|
|
43
|
+
Only `requests` is required. Python 3.7 and newer.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install shadowaitools
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
This installs the `shadowaitools` command and the `shadowaitools` package. The API key is an AI Tools Blocklist key from the account area at aitoolsblocklist.com; pass it as `--key` or export it once:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
export SHADOWAITOOLS_API_KEY=your_key
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
shadowaitools scan nextdns-export.csv --csv inventory.csv --json inventory.json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
Shadow AI inventory (csv export, 400 lines, 45 unique domains, 45 lookups)
|
|
67
|
+
AI tools found: 34 users involved: 10 train on your data by default: 16 terms silent: 15
|
|
68
|
+
|
|
69
|
+
domain hits ai type category trains on data sanctioned users
|
|
70
|
+
-------------------------- ----- ---------- -------------------------- --------------- ---------- ----------------------
|
|
71
|
+
character.ai 10 ai_native Text & Language yes no laptop-marketing-02 +2
|
|
72
|
+
openai.com 10 ai_native Code & Development opt_out_default yes laptop-eng-07 +4
|
|
73
|
+
otter.ai 7 ai_native Audio, Voice & Music yes no laptop-sales-09 +2
|
|
74
|
+
midjourney.com 5 ai_native Image & Visual unstated no laptop-exec-01 +1
|
|
75
|
+
elevenlabs.io 4 ai_native Text & Language opt_out_default no laptop-eng-07 +1
|
|
76
|
+
fireflies.ai 3 ai_native Audio, Voice & Music no no desktop-support-03 +1
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
In Python:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from shadowaitools import scan, to_csv
|
|
83
|
+
|
|
84
|
+
inventory = scan(
|
|
85
|
+
"zscaler-web.csv",
|
|
86
|
+
api_key="your_key",
|
|
87
|
+
sanctioned=["openai.com", "github.com"],
|
|
88
|
+
cache_file="lookups.json",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
print(inventory["summary"])
|
|
92
|
+
# {'lines': 400, 'records': 400, 'unique_domains': 45, 'lookups': 45, 'ai_tools_found': 34,
|
|
93
|
+
# 'sanctioned': 2, 'unsanctioned': 32, 'users_involved': 10, 'training_default_yes': 16,
|
|
94
|
+
# 'training_no': 3, 'unstated': 15, 'quota_remaining': 9999940}
|
|
95
|
+
|
|
96
|
+
for tool in inventory["tools"]:
|
|
97
|
+
if not tool["sanctioned"] and tool["ai_type"] == "ai_native":
|
|
98
|
+
print(tool["domain"], tool["hits"], [u["name"] for u in tool["users"]], tool["trains_on_data"])
|
|
99
|
+
|
|
100
|
+
with open("inventory.csv", "w") as fh:
|
|
101
|
+
fh.write(to_csv(inventory))
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## How a scan works
|
|
105
|
+
|
|
106
|
+
1. **Parse.** The first non-empty line decides the format. A header row with a known column name means CSV (comma, tab, semicolon or pipe). `hostname=` or `dstname=` tokens mean key=value syslog. `query[A]` means dnsmasq. The Squid `access.log` layout and Windows DNS Server debug packets have their own detectors. Anything else is read line by line for the first hostname and the first private IP address.
|
|
107
|
+
2. **Reduce.** Each hostname becomes a registrable domain (`chat.openai.com` to `openai.com`, `news.bbc.co.uk` to `bbc.co.uk`). Names in reserved zones (`.local`, `.internal`, `.lan`, `.corp`, `.home`, `.arpa`, `.test`, `.example`) are dropped before anything is sent.
|
|
108
|
+
3. **Look up.** Each unique domain is sent once to `GET https://www.aitoolsblocklist.com/api/check?domain=<domain>` with the key in the `X-API-Key` header. With `cache_file`, domains seen on a previous run are answered from the cache.
|
|
109
|
+
4. **Assemble.** Domains with `blocked: true` become tools. Hits, hosts and users are attached from the parse, the sanctioned flag from your list, and the category, AI type and training fields from the lookup.
|
|
110
|
+
|
|
111
|
+
A first run on a 400-line export with 45 distinct domains makes 45 lookups. A month of resolver logs with two million lines usually collapses to a few thousand registrable domains, because most traffic goes to a small set of hosts, and the second run through the same cache pays only for domains that are new that day. The `domains` command prints the exact count before any lookup is made.
|
|
112
|
+
|
|
113
|
+
The user or device column is optional. When the export carries `Identities`, `user`, `Source User`, `device_name`, `client_ip`, `src` or a similar column, every tool lists who reached it; when it does not, the inventory still has the tools and the hit counts.
|
|
114
|
+
|
|
115
|
+
## Accepted exports
|
|
116
|
+
|
|
117
|
+
| Source | Format | Hostname column or field | User column or field |
|
|
118
|
+
|---|---|---|---|
|
|
119
|
+
| Cisco Umbrella activity export | csv | `Domain` | `Identities`, `Internal IP` |
|
|
120
|
+
| Cloudflare Gateway DNS log | csv | `QueryName` | `DeviceName`, `SourceIP`, `Email` |
|
|
121
|
+
| DNSFilter query log | csv | `domain` | `client`, `device` |
|
|
122
|
+
| NextDNS log export | csv | `domain` | `client_ip`, `device_name` |
|
|
123
|
+
| Palo Alto URL filtering log | csv | `URL` | `Source User`, `Source address` |
|
|
124
|
+
| Zscaler web log | csv | `url` | `user`, `cip` |
|
|
125
|
+
| Fortinet FortiGate web filter syslog | key-value | `hostname=` | `user=`, `srcip=` |
|
|
126
|
+
| SonicWall syslog | key-value | `dstname=` | `usr=`, `src=` |
|
|
127
|
+
| Pi-hole and dnsmasq | dnsmasq | `query[A] name` | `from address` |
|
|
128
|
+
| Squid | squid | `CONNECT host:443` | client IP, authenticated user |
|
|
129
|
+
| Windows DNS Server debug log | windows-dns | encoded question name | client address |
|
|
130
|
+
| Plain hostname or URL list | generic | the line | none |
|
|
131
|
+
| Any other text log | generic | first hostname on the line | first private IPv4 on the line |
|
|
132
|
+
|
|
133
|
+
Anything with a header row and a hostname column works, whatever produced it. The `formats` command prints this list from the installed version.
|
|
134
|
+
|
|
135
|
+
## API
|
|
136
|
+
|
|
137
|
+
### `scan(source, api_key=None, **options)`
|
|
138
|
+
|
|
139
|
+
`source` is a file path, a string of contents, `bytes` or an open file. Options:
|
|
140
|
+
|
|
141
|
+
| Option | Default | Meaning |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| `api_key` | env `SHADOWAITOOLS_API_KEY` or `ATB_API_KEY` | AI Tools Blocklist key |
|
|
144
|
+
| `concurrency` | 1 | parallel lookups |
|
|
145
|
+
| `pause` | 0.0 | seconds to wait after each lookup |
|
|
146
|
+
| `max_lines` | none | stop parsing after this many lines |
|
|
147
|
+
| `cache_file` | none | JSON file of previous lookups, reused and extended |
|
|
148
|
+
| `sanctioned` | `[]` | domains to flag as sanctioned |
|
|
149
|
+
| `on_progress` | none | callback `(done, total)` |
|
|
150
|
+
| `timeout`, `max_retries`, `base_url` | 30, 2, production | passed to the client |
|
|
151
|
+
|
|
152
|
+
Returns a dict with `generated`, `format`, `summary`, `by_category` and `tools`.
|
|
153
|
+
|
|
154
|
+
### Tool fields
|
|
155
|
+
|
|
156
|
+
| Field | Values |
|
|
157
|
+
|---|---|
|
|
158
|
+
| `domain`, `hosts`, `hits`, `users` | from the export |
|
|
159
|
+
| `sanctioned` | `True` when the domain is in your list |
|
|
160
|
+
| `primary_category` | one of 18 functional categories |
|
|
161
|
+
| `categories` | `[{"category", "subcategory"}]`, a tool can sit in several |
|
|
162
|
+
| `ai_type` | `ai_native` or `ai_enabled` |
|
|
163
|
+
| `trains_on_data` | `yes`, `no`, `opt_out_default`, `unstated` |
|
|
164
|
+
| `opt_out_available`, `enterprise_no_training`, `api_no_training` | same value set |
|
|
165
|
+
| `terms_checked` | ISO date the vendor terms were last read |
|
|
166
|
+
|
|
167
|
+
### Other functions
|
|
168
|
+
|
|
169
|
+
| Function | Purpose |
|
|
170
|
+
|---|---|
|
|
171
|
+
| `parse_log(source, max_lines=None)` | `{"format", "lines", "records": [{"host", "user"}]}` with no network call |
|
|
172
|
+
| `extract_domains(records)` | `[{"domain", "hosts", "hits", "users"}]` sorted by hits |
|
|
173
|
+
| `registrable_domain(host)` | reduce a hostname |
|
|
174
|
+
| `to_csv(inventory)` | one CSV row per tool |
|
|
175
|
+
| `to_table(inventory)` | fixed-width text table |
|
|
176
|
+
| `Client(api_key).lookup(domain)` | the raw lookup |
|
|
177
|
+
|
|
178
|
+
### Exceptions
|
|
179
|
+
|
|
180
|
+
`AuthenticationError` (401), `QuotaError` (403, inactive account or monthly quota used up), `RateLimitError` (429 after two retries) and the base `ShadowAIToolsError` (anything else, including 503 after retries). Each carries `.status` and `.body`.
|
|
181
|
+
|
|
182
|
+
## Command line
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
shadowaitools scan <file> [--key KEY] [--json FILE] [--csv FILE] [--cache FILE]
|
|
186
|
+
[--sanctioned a.com,b.com] [--max-lines N] [--concurrency N]
|
|
187
|
+
[--pause SECONDS] [--quiet]
|
|
188
|
+
shadowaitools domains <file> unique registrable domains and hit counts, no lookups
|
|
189
|
+
shadowaitools formats the accepted export formats
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`domains` is the dry run: it prints the format that was detected and the number of lookups a scan would need.
|
|
193
|
+
|
|
194
|
+
## Worked examples
|
|
195
|
+
|
|
196
|
+
### Weekly report for a security team
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
# weekly_shadow_ai.py
|
|
200
|
+
import datetime
|
|
201
|
+
import json
|
|
202
|
+
from shadowaitools import scan, to_csv
|
|
203
|
+
|
|
204
|
+
week = datetime.date.today().isocalendar()[1]
|
|
205
|
+
inv = scan(
|
|
206
|
+
f"/exports/umbrella-week-{week}.csv",
|
|
207
|
+
cache_file="/var/lib/shadowaitools/lookups.json",
|
|
208
|
+
sanctioned=open("/etc/shadowaitools/approved.txt").read().split(),
|
|
209
|
+
pause=0.05,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
with open(f"/reports/shadow-ai-week-{week}.csv", "w") as fh:
|
|
213
|
+
fh.write(to_csv(inv))
|
|
214
|
+
|
|
215
|
+
risky = [t for t in inv["tools"] if not t["sanctioned"] and t["trains_on_data"] in ("yes", "opt_out_default")]
|
|
216
|
+
print(f"week {week}: {inv['summary']['ai_tools_found']} tools, {len(risky)} unsanctioned tools that train on input")
|
|
217
|
+
for t in sorted(risky, key=lambda t: -t["hits"])[:10]:
|
|
218
|
+
print(f" {t['domain']:28} {t['hits']:5} hits {len(t['users']):3} users {t['primary_category']}")
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Comparing two weeks
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from shadowaitools import scan
|
|
225
|
+
|
|
226
|
+
before = scan("proxy-week-36.log", cache_file="lookups.json")
|
|
227
|
+
after = scan("proxy-week-37.log", cache_file="lookups.json")
|
|
228
|
+
|
|
229
|
+
seen_before = {t["domain"] for t in before["tools"]}
|
|
230
|
+
new_tools = [t for t in after["tools"] if t["domain"] not in seen_before]
|
|
231
|
+
print("new AI tools this week:", [t["domain"] for t in new_tools])
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Because both scans share the cache, the second one only pays for domains that did not appear in the first.
|
|
235
|
+
|
|
236
|
+
### Streaming a large export in chunks
|
|
237
|
+
|
|
238
|
+
Exports from a busy resolver run to millions of lines. `parse_log` accepts a string, so a file can be read in blocks and grouped before a single lookup is made.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
from shadowaitools import Client, extract_domains, parse_log, registrable_domain
|
|
242
|
+
|
|
243
|
+
records = []
|
|
244
|
+
with open("dns-month.log", encoding="utf-8", errors="replace") as fh:
|
|
245
|
+
block = []
|
|
246
|
+
for line in fh:
|
|
247
|
+
block.append(line)
|
|
248
|
+
if len(block) == 200_000:
|
|
249
|
+
records.extend(parse_log("".join(block))["records"])
|
|
250
|
+
block = []
|
|
251
|
+
if block:
|
|
252
|
+
records.extend(parse_log("".join(block))["records"])
|
|
253
|
+
|
|
254
|
+
groups = extract_domains(records)
|
|
255
|
+
print(len(records), "records,", len(groups), "unique domains")
|
|
256
|
+
|
|
257
|
+
client = Client("your_key")
|
|
258
|
+
tools = []
|
|
259
|
+
for g in groups:
|
|
260
|
+
r = client.lookup(g["domain"])
|
|
261
|
+
if r.get("blocked"):
|
|
262
|
+
tools.append((g["domain"], g["hits"], r.get("primary_category"), r.get("trains_on_data")))
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Only the lookup
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from shadowaitools import Client
|
|
269
|
+
|
|
270
|
+
c = Client("your_key")
|
|
271
|
+
print(c.lookup("chat.openai.com"))
|
|
272
|
+
# {'domain': 'openai.com', 'blocked': True, 'primary_category': 'Code & Development', 'ai_type': 'ai_native',
|
|
273
|
+
# 'categories': [...], 'trains_on_data': 'opt_out_default', 'opt_out_available': 'yes', ...}
|
|
274
|
+
print(c.lookup("example.com")["blocked"])
|
|
275
|
+
# False
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Why the logs are the right starting point
|
|
279
|
+
|
|
280
|
+
Every governance framework begins with an inventory. The [NIST AI Risk Management Framework](https://www.nist.gov/itl/ai-risk-management-framework) puts "Map" before "Measure" and "Manage": an organisation has to know which AI systems are in use before any control can be applied. The [ENISA](https://www.enisa.europa.eu/) work on AI cybersecurity makes the same point for European organisations, and the [CISA](https://www.cisa.gov/) guidance on secure AI deployment assumes that operators can enumerate the AI services their people reach. On the data-protection side, the [ICO's guidance on AI and data protection](https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/artificial-intelligence/) treats the flow of personal data into third-party AI services as a processing activity that has to be documented.
|
|
281
|
+
|
|
282
|
+
The inventory you need already exists in the DNS filter, proxy or firewall. It is complete in a way a survey can never be, it costs nothing to export, and it names the hostnames rather than the products people remember. The missing step is classification, which is what the lookup adds: is this domain an AI tool, what kind, and what does the vendor do with the input. Alongside the tool inventory, the same organisation usually wants the opposite control for its own agents, which is where an allow list for AI agents comes in: the [AI agent allow list](https://www.aiagentallowlist.com) tells a browsing agent which pages on a site it may open and which it must not, so the two datasets cover both directions of AI traffic.
|
|
283
|
+
|
|
284
|
+
## Hosted audit
|
|
285
|
+
|
|
286
|
+
The package produces the inventory. The hosted [shadow AI inventory](https://www.shadowaitools.com) at shadowaitools.com produces the report: upload the same export, get every tool with category and risk level, the per-user breakdown, dated training verdicts, the sanctioned split against your approved list, sector policy verdicts from the AI Policy Profiles, a CSV and a PDF evidence pack. The free preview names a fifth of the tools found and comes with a preview PDF; full reports are one-time purchases, and the subscription plans on aitoolsblocklist.com include one to ten audits a month.
|
|
287
|
+
|
|
288
|
+
## Related packages
|
|
289
|
+
|
|
290
|
+
- [`aiblocklist`](https://pypi.org/project/aiblocklist/) and [`aitoolsblocklist`](https://pypi.org/project/aitoolsblocklist/): Python clients for the lookup and feed APIs of the [AI domain blocklist](https://www.aitoolsblocklist.com), 20,000+ AI tool domains in 18 categories, refreshed daily, with EDL, PAC, hosts and DNS feeds.
|
|
291
|
+
- [`aiagentallowlist`](https://pypi.org/project/aiagentallowlist/): per-URL allow, deny and flag verdicts for browsing agents across 40 million+ domains, up to 28 verified page types each.
|
|
292
|
+
- [`websiteclassificationapi`](https://pypi.org/project/websiteclassificationapi/): the [website categorization API](https://www.websitecategorizationapi.com), 700+ IAB content categories for any URL.
|
|
293
|
+
- [`cipawebfiltering`](https://pypi.org/project/cipawebfiltering/) and [`phishingdetectionapi`](https://pypi.org/project/phishingdetectionapi/): the [CIPA web filtering](https://www.cipawebfiltering.com) client for schools and the [phishing detection API](https://www.phishingdetectionapi.com) with 390,000+ DNS-verified active phishing domains.
|
|
294
|
+
- The [web filtering database](https://www.webfilteringdatabase.com), 120M+ domains in 59 categories, for the same firewalls and resolvers.
|
|
295
|
+
- Node.js: [`shadowaitools` on npm](https://www.npmjs.com/package/shadowaitools), same formats, same inventory, same cache file.
|
|
296
|
+
- Source: [github.com/explainableaixai/shadowaitools](https://github.com/explainableaixai/shadowaitools) and [gitlab.com/url-classifications/shadowaitools](https://gitlab.com/url-classifications/shadowaitools).
|
|
297
|
+
|
|
298
|
+
## Frequently asked questions
|
|
299
|
+
|
|
300
|
+
**How do I detect shadow AI on my network?**
|
|
301
|
+
Export a week of DNS, proxy or firewall logs, run `shadowaitools scan export.csv`, and read the inventory. Every hostname is matched against 20,000+ known AI tool domains, so the result is the AI traffic that actually crossed your network. For a report with the per-user breakdown and a PDF, upload the same file at [shadowaitools.com](https://www.shadowaitools.com).
|
|
302
|
+
|
|
303
|
+
**Is anything installed on endpoints or inspected in transit?**
|
|
304
|
+
No. The tool reads a log export that your DNS filter, proxy or firewall already produces. There is no agent, no TLS inspection and no change to the network.
|
|
305
|
+
|
|
306
|
+
**Does the export leave my machine?**
|
|
307
|
+
No. It is parsed locally. Only unique registrable domains are looked up, one request each, and reserved internal zones are never sent.
|
|
308
|
+
|
|
309
|
+
**Which exports are supported?**
|
|
310
|
+
Cisco Umbrella, Zscaler, Palo Alto, Fortinet, Cloudflare Gateway, DNSFilter, NextDNS, Pi-hole, SonicWall, Squid, Windows DNS Server debug logs, any CSV with a header row, key=value syslog lines and plain hostname lists. See the table above.
|
|
311
|
+
|
|
312
|
+
**What is the difference between `ai_native` and `ai_enabled`?**
|
|
313
|
+
`ai_native` is a service whose product is the AI: a chatbot, a code assistant, an image generator. `ai_enabled` is an ordinary product that has added AI features, such as an office suite with a built-in assistant. Both appear in the inventory because both can receive pasted content; the flag lets you treat them differently.
|
|
314
|
+
|
|
315
|
+
**How current is the database behind the lookup?**
|
|
316
|
+
It is rebuilt daily, with about 300,000 new domains checked every day against a 120-million-domain corpus, so new tools are caught close to launch. The training verdicts come from a review of 13,000+ vendor terms and carry the date they were checked.
|
|
317
|
+
|
|
318
|
+
**Can I limit how many lookups a scan makes?**
|
|
319
|
+
Yes. `shadowaitools domains file` shows the count first; `--max-lines` caps parsing; `--cache` makes repeated runs free for domains already seen; `--pause` slows the run down.
|
|
320
|
+
|
|
321
|
+
**Who is behind shadowaitools?**
|
|
322
|
+
Alpha Quantum, which also builds the [AI tools blocklist](https://www.aitoolsblocklist.com), the [AI agent allow list](https://www.aiagentallowlist.com), the [website categorization API](https://www.websitecategorizationapi.com) and the [web filtering database](https://www.webfilteringdatabase.com).
|
|
323
|
+
|
|
324
|
+
## Links
|
|
325
|
+
|
|
326
|
+
- Hosted shadow AI audit: [https://www.shadowaitools.com](https://www.shadowaitools.com)
|
|
327
|
+
- The lookup database: [https://www.aitoolsblocklist.com](https://www.aitoolsblocklist.com)
|
|
328
|
+
- AI agent allow list: [https://www.aiagentallowlist.com](https://www.aiagentallowlist.com)
|
|
329
|
+
- NIST AI Risk Management Framework: [https://www.nist.gov/itl/ai-risk-management-framework](https://www.nist.gov/itl/ai-risk-management-framework)
|
|
330
|
+
- ENISA: [https://www.enisa.europa.eu/](https://www.enisa.europa.eu/)
|
|
331
|
+
- CISA: [https://www.cisa.gov/](https://www.cisa.gov/)
|
|
332
|
+
- ICO, AI and data protection: [https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/artificial-intelligence/](https://ico.org.uk/for-organisations/uk-gdpr-guidance-and-resources/artificial-intelligence/)
|
|
333
|
+
|
|
334
|
+
## License
|
|
335
|
+
|
|
336
|
+
MIT
|