Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ logs/*
testing*/
venv/*
venv
.venv/*
.venv
env/*
env
*.log
Expand Down
47 changes: 27 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@
---

## Table of Contents
1. [Introduction](#introduction)
2. [Key Features](#key-features)
3. [Installation & Usage](#installation--usage)
4. [Discovery Phases](#discovery-phases)
5. [Endpoint Testing](#endpoint-testing)
6. [PII Detection](#pii-detection)
7. [Output Examples](#output)
8. [Stats & Reporting](#stats--reporting)
9. [Acknowledgments](#acknowledgments)
- [Autoswagger by Intruder](#autoswagger-by-intruder)
- [Table of Contents](#table-of-contents)
- [Introduction](#introduction)
- [Key Features](#key-features)
- [Installation \& Usage](#installation--usage)
- [Flags](#flags)
- [Help](#help)
- [Discovery Phases](#discovery-phases)
- [Endpoint Testing](#endpoint-testing)
- [PII Detection](#pii-detection)
- [Output](#output)
- [Interpreting Results](#interpreting-results)
- [Stats \& Reporting](#stats--reporting)
- [Acknowledgments](#acknowledgments)

---

Expand Down Expand Up @@ -80,17 +85,19 @@ Autoswagger automates the process of finding **OpenAPI/Swagger** specifications,

## Flags

| Flag | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------|
| `urls` | List of base URLs or direct spec URLs. |
| `-v, --verbose` | Enables verbose logging. Creates a log file under `~/.autoswagger/logs`. |
| `-risk` | Includes non-GET methods (POST, PUT, PATCH, DELETE) in testing. |
| `-all` | Includes 200 and 404 endpoints in output (excludes 401/403). |
| `-product` | Outputs only endpoints with PII or large responses, in JSON format. |
| `-stats` | Displays scan statistics (e.g. requests, RPS, hosts with PII). |
| `-rate <N>` | Throttles requests to N requests per second. Default is 30. Use 0 to disable rate limiting. |
| `-b, --brute` | Enables brute-forcing of parameter values (multiple test combos). |
| `-json` | Outputs results in JSON format instead of a Rich table in default mode. |
| Flag | Description |
| ---------------- | ------------------------------------------------------------------------------------------- |
| `urls` | List of base URLs or direct spec URLs. |
| `-v, --verbose` | Enables verbose logging. Creates a log file under `~/.autoswagger/logs`. |
| `-risk` | Includes non-GET methods (POST, PUT, PATCH, DELETE) in testing. |
| `-all` | Includes 200 and 404 endpoints in output (excludes 401/403). |
| `-product` | Outputs only endpoints with PII or large responses, in JSON format. |
| `-stats` | Displays scan statistics (e.g. requests, RPS, hosts with PII). |
| `-rate <N>` | Throttles requests to N requests per second. Default is 30. Use 0 to disable rate limiting. |
| `-b, --brute` | Enables brute-forcing of parameter values (multiple test combos). |
| `-json` | Outputs results in JSON format instead of a Rich table in default mode. |
| `-d, --discover` | Add URLs from the specs `server` object to the scan. |
| `-l, --limit` | Limit the scan to the given URL prefix. |


## Help
Expand Down
37 changes: 30 additions & 7 deletions autoswagger.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ def test_endpoint(base_url, base_path, path_template, method, parameters, reques

def test_endpoints(base_url, base_path, swagger_spec, verbose=False,
include_risk=False, include_all=False, product_mode=False,
rate=30, tried_basepath_fallback=False, brute=False):
rate=30, tried_basepath_fallback=False, brute=False, limit="", discover=False):
"""
Iterates over all paths and methods in the provided swagger_spec.
Submits tasks to test_endpoint if the method is allowed (GET or others if -risk).
Expand All @@ -795,6 +795,22 @@ def test_endpoints(base_url, base_path, swagger_spec, verbose=False,
all_results = []
max_workers = min(100, os.cpu_count() * 5)

# Base path contains a domain, use it as well!
if (base_path.startswith("http://") or base_path.startswith("https://")):
parsed_base_path = urlparse(base_path)
if discover:
rslts = test_endpoints(base_path, parsed_base_path.path, swagger_spec, verbose=verbose, include_risk=include_risk, include_all=include_all, product_mode=product_mode, rate=rate, tried_basepath_fallback=tried_basepath_fallback, brute=brute, limit=limit, discover=False)
all_results.extend(rslts)

base_path = parsed_base_path.path

if limit and not base_url.startswith(limit):
if verbose:
parsed_base_url = urlparse(base_url)
base_url_no_path = f"{parsed_base_url.scheme}://{parsed_base_url.netloc}"
log(f"Skipping base URL '{base_url_no_path}' as it does not match the limit prefix.", level="INFO")
return results

with ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_endpoint = {}
for path, methods in swagger_spec['paths'].items():
Expand Down Expand Up @@ -873,7 +889,7 @@ def test_endpoints(base_url, base_path, swagger_spec, verbose=False,
fallback = test_endpoints(
base_url, '/', swagger_spec, verbose,
include_risk, include_all, product_mode=product_mode,
rate=rate, tried_basepath_fallback=True, brute=brute
rate=rate, tried_basepath_fallback=True, brute=brute, limit=limit, discover=discover
)
return fallback

Expand Down Expand Up @@ -1125,7 +1141,7 @@ def process_input(urls):
processed.append(url)
return processed

def main(urls, verbose, include_risk, include_all, product_mode, stats_flag, rate, brute, json_output):
def main(urls, verbose, include_risk, include_all, product_mode, stats_flag, rate, brute, json_output, limit, discover):
"""
Main function controlling flow:
1. Tracks start time
Expand Down Expand Up @@ -1185,7 +1201,8 @@ def process_url(base_url):
rslts = test_endpoints(
base_url, base_path, swagger_spec,
verbose, include_risk, include_all,
product_mode=product_mode, rate=rate, brute=brute
product_mode=product_mode, rate=rate, brute=brute,
limit=limit, discover=discover
)
del swagger_spec
with results_lock:
Expand Down Expand Up @@ -1222,7 +1239,8 @@ def process_url(base_url):
rslts = test_endpoints(
base_url, base_path, swagger_spec,
verbose, include_risk, include_all,
product_mode=product_mode, rate=rate, brute=brute
product_mode=product_mode, rate=rate, brute=brute,
limit=limit, discover=discover
)
del swagger_spec
with results_lock:
Expand Down Expand Up @@ -1259,7 +1277,8 @@ def process_url(base_url):
rslts2 = test_endpoints(
base_url, base_path, sws,
verbose, include_risk, include_all,
product_mode=product_mode, rate=rate, brute=brute
product_mode=product_mode, rate=rate, brute=brute,
limit=limit, disocver=discover
)
del sws
with results_lock:
Expand Down Expand Up @@ -1464,6 +1483,8 @@ def process_url(base_url):
parser.add_argument("-rate", type=int, default=30, help="Set the rate limit in requests per second (default: 30). Use 0 to disable rate limiting.")
parser.add_argument("-b", "--brute", action="store_true", help="Enable exhaustive testing of parameter values.")
parser.add_argument("-json", action="store_true", help="Output results in JSON format in default mode.")
parser.add_argument("-limit", type=str, default="", help="Limit scan to url prefix.")
parser.add_argument("-d", "--discover", action="store_true", help="Discover additional domains from the spec.")

args = parser.parse_args()

Expand All @@ -1485,6 +1506,8 @@ def process_url(base_url):
rate = args.rate
brute = args.brute
json_output = args.json
limit = args.limit
discover = args.discover

# Set up file logging if verbose is enabled
if verbose:
Expand All @@ -1498,4 +1521,4 @@ def process_url(base_url):
logger.addHandler(file_handler)
logger.propagate = False

main(urls, verbose, include_risk, include_all, product_mode, stats_flag, rate, brute, json_output)
main(urls, verbose, include_risk, include_all, product_mode, stats_flag, rate, brute, json_output, limit, discover)