dir vs scan vs inventory (API9) — Differences, Overlaps, and What Is Redundant¶
This document answers precisely: is there real duplication between dir, scan --fuzz-versions, and the inventory module? The short answer is yes, there is a partial real overlap, but only at one of the three levels. Here is what the code says.
The Three Layers That Touch API Versions¶
Before comparing commands, it helps to understand that there are three distinct layers that interact with "API versions":
| Layer | Activation | Engine | Output |
|---|---|---|---|
A — dir wordlist | Always (if the wordlist contains /v1, etc.) | EndpointFuzzer | Discovered endpoints (no semantic classification) |
B — --fuzz-versions / --enable-advanced | Opt-in on dir or scan | VersionFuzzer via EnhancedOrchestrator.advanced_discovery | Finding category API_VERSION_FOUND, severity INFO |
C — inventory module | When inventory is in enabled_modules (default in scan) | VersionFuzzer via InventoryManagementModule | Findings DEPRECATED_API_VERSION, UNDOCUMENTED_API_VERSION, NON_CURRENT_API_VERSION, severity LOW with semantic analysis |
dir — Endpoint Discovery¶
Purpose: Find which endpoints respond. It does not understand or care whether a path is an API version or not.
How it touches versions: - If the wordlist (wordlists/endpoints.txt) contains entries like /v1, /v2, /api/v1, dir probes them like any other path and reports the ones that respond. - With --fuzz-versions enabled, the EnhancedOrchestrator additionally runs the VersionFuzzer directly against the target and emits API_VERSION_FOUND findings (severity INFO).
What dir does NOT do: - Does not compare versions against each other - Does not determine which is the "current" version (the highest one) - Does not detect whether a version carries a Deprecation: or Sunset: header - Does not generate OWASP-categorized findings with remediation recommendations - Does not distinguish between an active, deprecated, shadow, or development version
Version output from dir: a list of endpoints that responded, or with --fuzz-versions one API_VERSION_FOUND finding per accessible URL — it only says "it exists", with no context.
scan with --fuzz-versions — Advanced Discovery¶
Purpose: Same as dir plus running the OWASP modules. The --fuzz-versions part lives in the advanced_discovery phase of the orchestrator.
How it touches versions with --fuzz-versions: EnhancedOrchestrator._execute_version_fuzzing() instantiates a VersionFuzzer, calls fuzz_api_versions(target), and for each accessible version emits:
finding = self.findings_collector.add_finding(
category="API_VERSION_FOUND",
severity=None, # → INFO
evidence=f"API version endpoint found: {version}",
recommendation="Test all discovered API versions for vulnerabilities"
)
This is a reconnaissance finding — it says the version exists, with severity INFO, with no further analysis.
inventory (API9) — Semantic Version Analysis¶
Purpose: Take the endpoints already discovered by the discovery phase and determine whether any API version represents a concrete security problem (API9).
How it works: 1. Receives the discovered endpoints (the same ones that went through dir / discovery) 2. Extracts the unique base URLs (scheme://host:port) 3. Instantiates its own VersionFuzzer and calls fuzz_api_versions(base_url) 4. Analyzes each found version with _classify_versions(): - Reads Deprecation: and Sunset: headers and status code 410 Gone - Looks for body indicators: "deprecated", "beta", "staging", "sunset", "end-of-life" - Determines which is the "current" version (the highest numerically accessible one) - Emits differentiated findings:
| Finding | Severity | When |
|---|---|---|
DEPRECATED_API_VERSION | LOW | Deprecation: or Sunset: header, 410 status, or body containing "deprecated" |
UNDOCUMENTED_API_VERSION | LOW | Body containing "beta", "staging", "dev", "alpha", or "canary" |
NON_CURRENT_API_VERSION | LOW | Active version that is numerically lower than the highest accessible version |
The Real Overlap¶
Here is an honest side-by-side of what the VersionFuzzer does in each case:
| Operation | dir --fuzz-versions | scan --fuzz-versions | scan with inventory |
|---|---|---|---|
Calls VersionFuzzer.fuzz_api_versions() | ✅ | ✅ | ✅ |
Instantiates its own VersionFuzzer | ✅ | ✅ | ✅ (one per base URL) |
Emits API_VERSION_FOUND finding (INFO) | ✅ | ✅ | ❌ |
| Classifies as deprecated/shadow/non-current | ❌ | ❌ | ✅ |
| Emits OWASP API9 findings with recommendation | ❌ | ❌ | ✅ |
| Issues extra HTTP requests to the target | ✅ | ✅ | ✅ |
The Concrete Overlap¶
When scan --fuzz-versions runs with inventory active (which is the default), the VersionFuzzer is called twice against the same host:
- First call:
EnhancedOrchestrator._execute_version_fuzzing()—advanced_discoveryphase - Second call:
InventoryManagementModule._discover_versions()—owasp_testingphase
Both calls issue the same HTTP requests to /v1, /v2, /api/v1, etc. That is real duplicated work — the same URLs are probed twice.
When scan runs without --fuzz-versions (the most common case), only inventory runs the VersionFuzzer. There is no duplication.
What Makes Sense to Remove¶
What NOT to remove: inventory¶
inventory is not equivalent to dir. Its output is qualitatively different: it generates OWASP-categorized findings with semantic analysis, severity, concrete evidence, and remediation recommendations. dir cannot do any of that.
What IS duplicated: --fuzz-versions + inventory together¶
If you enable --fuzz-versions (or --enable-advanced) AND inventory is active (default in scan), the VersionFuzzer runs twice against the same host. The HTTP requests are identical. The outputs are different (API_VERSION_FOUND INFO vs API9 LOW findings), but the HTTP cost is doubled.
Confirmed duplication: - scan --fuzz-versions → VersionFuzzer.fuzz_api_versions(target) → API_VERSION_FOUND findings (INFO) - scan with inventory → VersionFuzzer.fuzz_api_versions(base_url) → DEPRECATED/UNDOCUMENTED/NON_CURRENT findings (LOW)
Same requests, different result processing.
What to Change (Concrete Proposal)¶
The problem is not that both exist — it is that when they coexist in the same run, the HTTP requests happen twice. The right fix is not to remove either layer, but to prevent the VersionFuzzer from running twice when inventory is already going to run it.
Options:
- When
inventoryis inenabled_modules, automatically skip--fuzz-versionsin the orchestrator (or vice versa), with a user-visible warning. - Cache the first
VersionFuzzerresult in the orchestrator context and pass it toinventoryinstead of havinginventoryre-run the fuzzer. - Document the behavior so the user knows that
--fuzz-versions+inventoryissues double requests (most conservative option — no code changes).
Option 2 is the cleanest technically but requires refactoring the interface between the orchestrator and the OWASP modules. Option 1 is the simplest and already eliminates the duplicated work.
Executive Summary¶
| Question | Answer |
|---|---|
Are dir and inventory duplicated? | No. dir discovers paths; inventory semantically analyzes the versions found. |
Are --fuzz-versions and inventory duplicated? | Partially. They produce different outputs but issue the same HTTP requests when both are active. |
Should inventory be removed? | No. It is the only place that generates OWASP API9 findings with semantic classification. |
| Is there real redundant work? | Yes. scan --fuzz-versions with inventory active calls the VersionFuzzer twice against the same host. |
| What should be done? | Prevent the double VersionFuzzer execution when --fuzz-versions and inventory are both active. |