From f6fdd13723e657c2750ad7cdb925bffa848db52a Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:36:50 -0700 Subject: [PATCH 1/8] Add sourcemap leakage check for subdomains The function scans for .js.map files in the subdomain's scripts and flags as vulnerable if more than 3 are found. --- subdominator/modules/scanner/sourcemap.py | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 subdominator/modules/scanner/sourcemap.py diff --git a/subdominator/modules/scanner/sourcemap.py b/subdominator/modules/scanner/sourcemap.py new file mode 100644 index 0000000..cd2e170 --- /dev/null +++ b/subdominator/modules/scanner/sourcemap.py @@ -0,0 +1,45 @@ +import httpx +import asyncio +from bs4 import BeautifulSoup +from urllib.parse import urljoin +from subdominator.modules.logger.logger import logger + +async def check_sourcemap_leakage(subdomain, timeout=10): + """ + Scans a subdomain for .js.map leakage. + Flags as vulnerable if > 3 maps are found. + """ + found_maps = [] + url = f"http://{subdomain}" + + try: + async with httpx.AsyncClient(timeout=timeout, follow_redirects=True, verify=False) as client: + response = await client.get(url) + if response.status_code != 200: + return None + + soup = BeautifulSoup(response.text, 'html.parser') + scripts = [script['src'] for script in soup.find_all('script', src=True)] + + for js_url in scripts: + full_js_url = urljoin(url, js_url) + map_url = f"{full_js_url}.map" + + try: + map_res = await client.get(map_url) + if map_res.status_code == 200 and "application/json" in map_res.headers.get("Content-Type", ""): + found_maps.append(map_url) + except httpx.RequestError: + continue + + if len(found_maps) > 3: + return { + "subdomain": subdomain, + "vulnerable": True, + "count": len(found_maps), + "files": found_maps + } + except Exception as e: + pass + + return None From 78e79bd7ada4ef3e44f212b1480181e87bdd4ae8 Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:37:10 -0700 Subject: [PATCH 2/8] Add sourcemap argument to CLI options Added a new argument for checking sourcemap leakage. --- subdominator/modules/cli/cli.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/subdominator/modules/cli/cli.py b/subdominator/modules/cli/cli.py index dc3dac3..dc19c7b 100644 --- a/subdominator/modules/cli/cli.py +++ b/subdominator/modules/cli/cli.py @@ -23,7 +23,8 @@ def cli(): parser.add_argument("-ls", "--list-source", action="store_true") parser.add_argument("-duc", "--disable-update-check", action="store_true") parser.add_argument("-V", "--verbose", action="store_true") - parser.add_argument("-sup", "--show-updates", action="store_true") + parser.add_argument("-sup", "--show-updates", action="store_true") + parser.add_argument("-sm", "--sourcemap", action="store_true", help="Check for sourcemap leakage") parser.add_argument("-fw", "--filter-wildcards", action="store_true") parser.add_argument("-json", "--json", action="store_true") parser.add_argument("-s", "--silent", action="store_true") @@ -42,4 +43,4 @@ def cli(): Exit(1) except Exception as e: logger(f"Unahandled Exception occured in the CLI module due to: {e}", "warn") - Exit(1) \ No newline at end of file + Exit(1) From ec5ce52fca6d94abbc31903d2bec2ca89c7d6338 Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:38:30 -0700 Subject: [PATCH 3/8] Implement sourcemap leakage check feature Added a new feature to check for sourcemap leakage in subdomains using asynchronous tasks and logging. --- subdominator/modules/handler.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/subdominator/modules/handler.py b/subdominator/modules/handler.py index f74f6dd..3263b3d 100644 --- a/subdominator/modules/handler.py +++ b/subdominator/modules/handler.py @@ -32,6 +32,8 @@ from .version.version import version from .logger.logger import logger from .utils.utils import filters,reader,split_to_list, check_directory_permission,check_file_permission, Exit + # Import the new scanner module + from .scanner.sourcemap import check_sourcemap_leakage from .subscraper.abuseipdb.abuseipdb import abuseipdb from .subscraper.alienvault.alientvault import alienvault from .subscraper.anubis.anubis import anubis @@ -270,7 +272,28 @@ async def _domain_handler_(domain): file(output, domain, args) elif args.output_directory: dir(output, domain, args) - + + # START NEW FEATURE: Sourcemap Leakage Check + if args.sourcemap: + if not args.silent: + logger(f"Checking for Sourcemap Leakage on {len(final)} subdomains...", "info", args.no_color) + + # Use Semaphore to limit concurrent web requests during scanning + sem = asyncio.Semaphore(10) + + async def limited_check(sub): + async with sem: + return await check_sourcemap_leakage(sub, timeout=args.timeout) + + scan_tasks = [limited_check(sub) for sub in final] + scan_results = await asyncio.gather(*scan_tasks) + + for res in scan_results: + if res and res.get("vulnerable"): + msg = f"VULNERABLE: Sourcemap Leakage at {res['subdomain']} ({res['count']} maps found)" + logger(msg, "info", args.no_color) # You can customize this logger level + # END NEW FEATURE + async with AsyncSessionLocal() as db: await add_or_update_domain(db, domain, final) From 74fbe5266f1fcee5e9703f0bf4d4385aac3aae4f Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:41:38 -0700 Subject: [PATCH 4/8] Create __init__.py --- subdominator/modules/scanner/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 subdominator/modules/scanner/__init__.py diff --git a/subdominator/modules/scanner/__init__.py b/subdominator/modules/scanner/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/subdominator/modules/scanner/__init__.py @@ -0,0 +1 @@ + From 4bb762f055465b4afc2fb9dfa49841b05e03b0d1 Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:46:45 -0700 Subject: [PATCH 5/8] Add sourcemap leakage flag to CLI arguments Added a new argument for sourcemap leakage detection in the CLI. --- subdominator/modules/cli/cli.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/subdominator/modules/cli/cli.py b/subdominator/modules/cli/cli.py index dc19c7b..38e4bd1 100644 --- a/subdominator/modules/cli/cli.py +++ b/subdominator/modules/cli/cli.py @@ -23,9 +23,12 @@ def cli(): parser.add_argument("-ls", "--list-source", action="store_true") parser.add_argument("-duc", "--disable-update-check", action="store_true") parser.add_argument("-V", "--verbose", action="store_true") - parser.add_argument("-sup", "--show-updates", action="store_true") - parser.add_argument("-sm", "--sourcemap", action="store_true", help="Check for sourcemap leakage") + parser.add_argument("-sup", "--show-updates", action="store_true") parser.add_argument("-fw", "--filter-wildcards", action="store_true") + + # New Feature: Sourcemap Leakage Flag + parser.add_argument("-sm", "--sourcemap", action="store_true") + parser.add_argument("-json", "--json", action="store_true") parser.add_argument("-s", "--silent", action="store_true") parser.add_argument("-ir", "--include-resources", type=str,default=None) From 102a1f83558fa4c964d5b7c246ef47ef469ffdd3 Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:49:14 -0700 Subject: [PATCH 6/8] Update help.py with new command options --- subdominator/modules/help/help.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/subdominator/modules/help/help.py b/subdominator/modules/help/help.py index 135b442..c30899c 100644 --- a/subdominator/modules/help/help.py +++ b/subdominator/modules/help/help.py @@ -31,7 +31,9 @@ def help(path, dbpath): {bold}{white}[{reset}{bold}{blue}OPTIMIZATION{reset}{bold}{white}]{reset}: {bold}{white}-t, --timeout : Set timeout value for API requests (default: 30s). - -fw, --filter-wildcards : Filter out wildcard subdomains.{reset} + -fw, --filter-wildcards : Filter out wildcard subdomains. + -sm, --sourcemap : Check for sourcemap leakage on discovered subdomains.{reset} + {bold}{white}[{reset}{bold}{blue}CONFIGURATION{reset}{bold}{white}]{reset}: @@ -64,4 +66,4 @@ def help(path, dbpath): -ls, --list-source : List available subdomain enumeration sources. -V, --verbose : Enable verbose output.{reset} """) - Exit() \ No newline at end of file + Exit() From 0a5622bebdcab84bad69a4a3d984894769082756 Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:56:11 -0700 Subject: [PATCH 7/8] Update sourcemap.py --- subdominator/modules/scanner/sourcemap.py | 60 ++++++++++++++--------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/subdominator/modules/scanner/sourcemap.py b/subdominator/modules/scanner/sourcemap.py index cd2e170..e81fcd0 100644 --- a/subdominator/modules/scanner/sourcemap.py +++ b/subdominator/modules/scanner/sourcemap.py @@ -1,36 +1,48 @@ -import httpx import asyncio -from bs4 import BeautifulSoup +import warnings from urllib.parse import urljoin +from bs4 import XMLParsedAsHTMLWarning +from playwright.async_api import async_playwright from subdominator.modules.logger.logger import logger -async def check_sourcemap_leakage(subdomain, timeout=10): +warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning) + +async def check_sourcemap_leakage(subdomain, timeout=15): """ - Scans a subdomain for .js.map leakage. - Flags as vulnerable if > 3 maps are found. + Uses Playwright to load a site and listen for all JS requests. + Checks for .map files for every JS resource discovered. """ found_maps = [] url = f"http://{subdomain}" try: - async with httpx.AsyncClient(timeout=timeout, follow_redirects=True, verify=False) as client: - response = await client.get(url) - if response.status_code != 200: - return None - - soup = BeautifulSoup(response.text, 'html.parser') - scripts = [script['src'] for script in soup.find_all('script', src=True)] - - for js_url in scripts: - full_js_url = urljoin(url, js_url) - map_url = f"{full_js_url}.map" - - try: - map_res = await client.get(map_url) - if map_res.status_code == 200 and "application/json" in map_res.headers.get("Content-Type", ""): - found_maps.append(map_url) - except httpx.RequestError: - continue + async with async_playwright() as p: + browser = await p.chromium.launch(headless=True) + context = await browser.new_context(ignore_https_errors=True) + page = await context.new_page() + + js_urls = set() + + page.on("request", lambda request: js_urls.add(request.url) + if request.resource_type == "script" else None) + + try: + await page.goto(url, timeout=timeout * 1000, wait_until="networkidle") + except Exception: + await page.goto(f"https://{subdomain}", timeout=timeout * 1000, wait_until="networkidle") + + await browser.close() + + import httpx + async with httpx.AsyncClient(verify=False, timeout=5.0) as client: + for js_url in js_urls: + map_url = f"{js_url}.map" + try: + res = await client.get(map_url) + if res.status_code == 200 and "application/json" in res.headers.get("Content-Type", ""): + found_maps.append(map_url) + except Exception: + continue if len(found_maps) > 3: return { @@ -39,7 +51,7 @@ async def check_sourcemap_leakage(subdomain, timeout=10): "count": len(found_maps), "files": found_maps } - except Exception as e: + except Exception: pass return None From f943737d72ec2e36081cb0ad63f5dded5e90f494 Mon Sep 17 00:00:00 2001 From: GhostyTongue <191202026+Gh0styTongue@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:56:35 -0700 Subject: [PATCH 8/8] Add playwright to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 77bbe78..5c1bb9e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,4 @@ setuptools>=75.6.0 SQLAlchemy>=2.0.32 tldextract>=5.1.2 weasyprint>=65.0 +playwright