You do not need a paid attack surface management platform to catch the obvious mistakes. In a fast-moving information system, public exposure changes all the time. New subdomains appear, temporary services stay online longer than expected, demo applications become production dependencies, and with the rise of vibe coding it is even easier to ship something quickly and forget the boring security cleanup.
That is why I like having a simple blackbox monitoring loop on the public perimeter. Not because it replaces a pentest. It does not. But because it catches low-hanging fruits before they become embarrassing: forgotten admin panels, exposed Swagger documentation, database banners, directory listing, debug pages, or old test applications still reachable from the internet.
Subdomain Analysis Toolkit is my small open-source toolbox for that use case. It is not an ASM platform and it will not do miracles. It is a cheap safety net that you can run once, then automate if it proves useful.
1. The Basic Idea
The workflow is intentionally simple:
targets.txt -> subdomains.sh -> targets.latest.txt -> nuclei.sh -> report.2026-Week16.txttargets.txt contains the root domains you are allowed to test. subdomains.sh collects and consolidates subdomains. nuclei.sh scans the resulting list by severity and protocol. The output is a weekly report that can be archived, compared, or plugged into your own internal alerting.
The important part is not only finding subdomains. The useful part is repeating the scan over time and noticing what changed.
2. 10-Minute Bootstrap
Assuming you already have Go available, clone the project and install only what is needed for this first loop: subfinder and amass for discovery, then nuclei for the scan. curl is also used by nuclei.sh to check the current outbound IP, but it is usually already installed on Linux servers.
$ git clone https://github.com/nbeguier/SubdomainAnalysisToolkit.git $ cd SubdomainAnalysisToolkit $ go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest $ go install -v github.com/owasp-amass/amass/v3/...@master $ go install -v github.com/projectdiscovery/nuclei/v2/cmd/nuclei@latestThe other Python and Go dependencies are useful for the rest of the toolbox: stats, CSV exports, provider mapping, Wayback URLs, public bucket checks, or TCP exposure checks. You do not need them to validate the main idea.
Create your local configuration and a small target file. Only scan domains you own or have explicit permission to test.
$ cp settings.sample.py settings.py $ echo "beguier.eu" > targets.txtNow generate the subdomain list and run the Nuclei scan. For a first manual run, keep the colored output in your terminal:
$ bash subdomains.sh $ bash nuclei.shIf you want to archive the run as a clean weekly report, use the no-color output variant:
$ bash nuclei.sh --no-color > "report.$(date +%G-Week%V).txt"At this point you already have the two files that matter most for a first run: the latest known public targets and the current scan report.
3. Reading the Target List
The consolidated list is stored in targets.latest.txt. For example:
$ cat targets.latest.txt
beguier.eu
secret.beguier.eu
www.beguier.eu
In a real perimeter, this file quickly becomes your blackbox inventory. It will not replace your CMDB, cloud inventory, DNS management, or asset ownership data. It gives you a simple outside view: what can an external observer discover and try to reach?
4. Why Nuclei Is Split by Severity and Protocol
nuclei.sh does not launch everything as one big opaque scan. It loops over severities and protocols. This keeps the scan easier to follow, limits the impact of heavy template categories, and gives you progress visibility while the run is still active.
$ more report.2026-Week16.txt
[*] Checking SOCKS5 proxy at socks5://127.0.0.1:9050...
[-] SOCKS5 proxy not detected. Proceeding without proxy.
[+] Current IP without proxy: 10.0.0.1
[*] Updating HTTPx, DNSx, Nuclei and templates...
[*] Starting Nuclei scans on 1050 targets...
[*] Severity: critical
[*] Protocol: dns
[+] Found 2 templates for severity: critical and protocol: dns
[*] Protocol: file
[+] Found 5 templates for severity: critical and protocol: file
[*] Protocol: http
[+] Found 1618 templates for severity: critical and protocol: http
[*] Protocol: headless
[+] Found 3 templates for severity: critical and protocol: headless
[*] Protocol: tcp
[+] Found 31 templates for severity: critical and protocol: tcp
[*] Protocol: workflow
[+] Found 2 templates for severity: critical and protocol: workflow
[*] Severity: high
[*] Protocol: http
[+] Found 2267 templates for severity: high and protocol: http
[CVE-2025-4123:open-redirect] [http] [high] https://secret.beguier.eu/grafana/..%2F%5coast.pro%2F%3f%2F..%2F..
[symfony-debug] [http] [high] https://www.beguier.eu
[...]
During a run, Nuclei exposes runtime metrics on port 9092:
$ curl localhost:9092/metrics; echo ""
{"matched":0,"total":4024467,"templates":1605,"summary":"[0:00:04] | Templates: 1605 | Hosts: 1251 | RPS: 182 | Matched: 0 | Errors: 384 | Requests: 790/4024467 (0%)\n","duration":"0:00:04","rps":"182","requests":790,"errors":384,"startedAt":"2026-05-03T08:24:57.631716231Z","hosts":1251,"percent":"0"}
5. What I Triage First
The first pass is obvious: critical, high, and medium findings. But do not ignore all low or info templates blindly. Some of them are low from a generic scanner perspective but very interesting in a real company context.
If I have limited time, I usually start with high signal findings such as:
- mysql-detect and pgsql-detect - exposed database services should always raise questions.
- dir-listing - directory listing is often boring until it leaks backups, source maps, or deployment artifacts.
- phpmyadmin-panel and other admin panels - even when authentication exists, the exposure itself may be unwanted.
- swagger-api - public API documentation can reveal endpoints, models, and internal assumptions.
- exposed-gitignore, makefile-exposure, and package-json - small files can disclose stack details and deployment habits.
Nuclei has a lot of templates. That is a strength, but it also means you must tune your review process. The goal is not to worship scanner severity. The goal is to find things that should not be public.
6. Run It Continuously with systemd
For a one-shot test, the commands above are enough. In a company environment, I prefer turning it into a recurring monitoring loop. The public repository gives the scanning toolbox; your environment can add storage, ownership mapping, ticketing, Slack alerts, or whatever matches your constraints.
On Linux, a simple pattern is to refresh subdomains every day, then run Nuclei once a week.
Subdomain discovery service
# /etc/systemd/system/subdomains.service
[Unit]
Description=Subdomain Analysis Toolkit - Daily run
[Service]
Type=oneshot
WorkingDirectory=/opt/SubdomainAnalysisToolkit
ExecStart=/bin/bash /opt/SubdomainAnalysisToolkit/subdomains.sh
# /etc/systemd/system/subdomains.timer
[Unit]
Description=Run Subdomain Analysis Toolkit every day at 23:00
[Timer]
OnCalendar=*-*-* 23:00:00
Persistent=true
[Install]
WantedBy=timers.target
Nuclei scan service
# /etc/systemd/system/nuclei.service
[Unit]
Description=Nuclei scan - daily run
[Service]
Type=oneshot
User=root
WorkingDirectory=/opt/SubdomainAnalysisToolkit
Environment=HOME=/root
Environment=XDG_CONFIG_HOME=/root/.config
Environment=XDG_CACHE_HOME=/root/.cache
ExecStart=/bin/bash -c '/bin/bash nuclei.sh --no-color > report.$(date +%%G-Week%%V).txt'
# /etc/systemd/system/nuclei.timer
[Unit]
Description=Run Nuclei scan every Monday at 00:00
[Timer]
OnCalendar=Mon *-*-* 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
$ systemctl daemon-reload
$ systemctl enable --now subdomains.timer nuclei.timer
$ systemctl list-timers subdomains.timer nuclei.timer
$ journalctl -x -u subdomains.service -f
$ journalctl -x -u nuclei.service -f
7. Limits
This is not a replacement for a pentest. It does not test business logic, authenticated workflows, chained vulnerabilities, or architecture decisions. It is also not a full external attack surface management platform.
It is a small blackbox control that costs almost nothing and catches obvious mistakes. If it finds nothing, good. If it finds a forgotten panel, an exposed debug endpoint, a database banner, or a public Swagger file, it already paid for itself.
Conclusion
The public perimeter is your storefront. In a system that constantly changes, you need at least a cheap way to notice when something new becomes visible from the outside.
Start small: one target file, one subdomain discovery run, one Nuclei report. Then automate it if the signal is useful.