audit-labs/audit-tools
A collection of scripts, queries, and other goodies you can use in an audit.
clone: git clone https://gitbay.org/audit-labs/audit-tools.git
main: applications/github/collectors/webhooks.py · raw
1"""
2Collect organization and repository webhooks.
3
4Flags webhooks that deliver over plain HTTP or with SSL verification disabled.
5"""
6
7import sys
8from urllib.parse import urlparse
9
10import requests
11
12from .api import paginate
13
14
15def webhooks(org, cfg):
16 rows = [
17 _hook_row("org", h)
18 for h in paginate(f"https://api.github.com/orgs/{org}/hooks", cfg)
19 ]
20
21 for repo in paginate(f"https://api.github.com/orgs/{org}/repos", cfg):
22 name = repo["name"]
23 try:
24 hooks = paginate(f"https://api.github.com/repos/{org}/{name}/hooks", cfg)
25 except requests.HTTPError as e:
26 if e.response is not None and e.response.status_code in (403, 404):
27 print(
28 f" Skipping {name}: hooks endpoint returned "
29 f"{e.response.status_code}",
30 file=sys.stderr,
31 )
32 continue
33 raise
34 rows.extend(_hook_row(f"repo:{name}", h) for h in hooks)
35
36 return rows
37
38
39def _hook_row(scope, hook):
40 config = hook.get("config", {})
41 url = config.get("url", "")
42 return {
43 "scope": scope,
44 "url": url,
45 "insecure_url": urlparse(url).scheme == "http",
46 "ssl_verification": "disabled"
47 if str(config.get("insecure_ssl", "0")) == "1"
48 else "enabled",
49 "content_type": config.get("content_type", ""),
50 "events": ", ".join(hook.get("events", [])),
51 "active": hook.get("active"),
52 }