> your AI agent picks dependencies from memory; give it dated facts — try starlog.dev ↗ vet your agent's deps ↗ vibe-coding is fine. vibe-importing isn’t. — try starlog.dev ↗ vibe-importing isn’t fine ↗ your agent has never seen your private packages — try starlog.dev ↗ facts for private packages ↗ a linter for the dependencies your AI agent picks — try starlog.dev ↗ a linter for agent deps ↗

Back to Articles

Uro: How Static URL Analysis Cuts Pentesting Noise by 90%

[ View on GitHub ]

Uro: How Static URL Analysis Cuts Pentesting Noise by 90%

Hook

A typical web crawler dumps 50,000 URLs from a target site. Only 3,000 represent unique attack surfaces. The other 47,000? Pagination noise, blog archives, and static assets that waste scanner time and generate false positives.

Context

Security researchers and penetration testers face a data volume problem. Modern web applications generate massive URL sets—crawlers pull from sitemaps, archive services like Wayback Machine return years of historical URLs, and JavaScript-heavy SPAs create countless parameter combinations. Feed these raw lists into vulnerability scanners and you'll wait hours while your tools test /blog/page/1 through /blog/page/847, each functionally identical but structurally unique.

Traditional deduplication—simple string matching or hash-based uniqueness checks—doesn't understand URL semantics. It treats /product?id=123 and /product?id=456 as different targets when they're likely the same endpoint with different data. Content-based deduplication tools fetch each URL and hash responses, but that requires network overhead, triggers WAF alerts, and defeats the purpose of pre-filtering before active scanning. Uro emerged from this gap: a zero-request filter that understands URL patterns well enough to identify semantic duplicates, prioritize interesting targets, and eliminate noise before you burn time and bandwidth on actual testing.

Technical Insight

Uro's architecture revolves around URL component extraction and heuristic pattern matching. When you pipe a URL list through it, the tool parses each line into structured components (scheme, domain, path segments, parameters, extensions) without performing DNS lookups or HTTP requests. It then applies a series of composable filters that detect redundancy patterns common in web applications.

The core deduplication logic targets three primary noise sources. First, incremental pagination: URLs like /products/page/2, /products/page/3, /archive/2023/11 follow predictable numeric or date-based patterns. Uro's path analysis identifies these sequences and collapses them to a single representative URL. Second, parameter value variations: /search?q=shoes and /search?q=hats share the same attack surface—the search endpoint and its query parameter. Uro normalizes these by preserving parameter keys while treating different values as duplicates. Third, static resources and human-written content: the tool identifies file extensions (.jpg, .css, .pdf) and blog-style path patterns (/blog/my-story-title) that rarely contain injection points.

Here's a practical example. Suppose you've crawled an e-commerce site and extracted these URLs:

cat urls.txt
https://shop.example.com/products
https://shop.example.com/products/page/2
https://shop.example.com/products/page/3
https://shop.example.com/product?id=100
https://shop.example.com/product?id=101
https://shop.example.com/product?id=102
https://shop.example.com/blog/welcome-to-our-store
https://shop.example.com/blog/our-mission
https://shop.example.com/assets/logo.png
https://shop.example.com/search?q=shoes&sort=price
https://shop.example.com/search?q=hats&sort=rating

Running this through uro with default settings:

cat urls.txt | uro
https://shop.example.com/products
https://shop.example.com/product?id=100
https://shop.example.com/search?q=shoes&sort=price

The output collapses to three URLs. Pagination variants (/page/2, /page/3) merge into the base /products path. The three product detail pages with different IDs reduce to one representative. Blog posts disappear because uro recognizes human-written content patterns (long path segments with hyphens, common blog keywords). The static image gets filtered by extension. The two search queries with different parameter values consolidate into a single search endpoint.

For more control, uro exposes filter flags. The --hasparams filter keeps only URLs with query strings—useful when you're specifically hunting for parameter injection vulnerabilities. The --vuln flag activates whitelist mode, preserving only URLs with parameters historically linked to vulnerabilities (id, query, page, etc.), sourced from the parth project's research:

cat urls.txt | uro --vuln
https://shop.example.com/product?id=100
https://shop.example.com/search?q=shoes&sort=price

Now only parameterized endpoints survive, and specifically those with 'interesting' parameters. The --noext filter strips any URL with file extensions, while --whitelist and --blacklist let you define custom extension rules:

# Only keep .php and .aspx endpoints
cat urls.txt | uro --whitelist php aspx

# Remove all image and media files
cat urls.txt | uro --blacklist jpg png gif mp4 pdf

Under the hood, uro processes URLs as streams, making it memory-efficient for massive datasets. It doesn't load entire lists into RAM—it reads stdin line-by-line, applies filters, and writes matches to stdout. This design enables Unix pipeline composition:

# Combine with other tools
waybackurls example.com | uro --vuln | httpx -silent

This pipeline fetches historical URLs from Wayback Machine, filters to vulnerable-looking endpoints via uro, then probes which ones are still live with httpx. Each tool does one thing well, and uro's streaming architecture ensures it never becomes a bottleneck.

The filtering heuristics aren't configurable beyond the provided flags—there's no regex rule engine or pattern customization. This is intentional. Uro optimizes for the 80% use case where common web patterns apply. The tradeoff is speed and simplicity: no configuration files, no learning curve, just immediate noise reduction for standard web applications.

Gotcha

Uro's heuristic approach creates blind spots. Because it never fetches URLs, it can't detect actual content duplication—two genuinely different pages might have similar URL structures and both pass through, while two identical pages with different URL schemes get treated as unique. I've seen it incorrectly classify API versioning paths (/v1/users, /v2/users) as pagination duplicates, merging endpoints with completely different behaviors.

The content detection pattern is particularly aggressive. Any path segment longer than a certain threshold with hyphens triggers the 'human-written content' filter. This works great for /blog/10-ways-to-improve-your-seo but fails on applications that use hyphenated identifiers like /resource/project-ABC-123 or /documents/case-2024-001. You'll lose legitimate testing targets without realizing it. The --whitelist extension approach helps, but only if your targets use file extensions consistently. Modern REST APIs often don't, so you're stuck manually reviewing filtered results or skipping uro's content filters entirely. There's also no logging or verbose mode to see what got filtered and why, making it difficult to tune your workflow when you suspect false negatives.

Verdict

Use if: You're processing large URL sets (10k+ entries) from crawlers, Wayback Machine, or sitemaps before feeding them into active scanners or manual testing. Uro excels at reducing reconnaissance noise when you need quick wins—cutting bulk before the real work begins. It's especially valuable for bug bounty hunters working broad scopes where time efficiency directly impacts earnings, and for red team engagements where you want to minimize your network footprint during initial enumeration. Skip if: You're targeting SPAs with complex client-side routing, API-first applications without clear URL patterns, or sites with non-standard URL schemes where heuristics will misfire. Also skip for small URL sets under 1,000 entries where manual review is faster than debugging false negatives, or when you need content-aware deduplication and can afford the network overhead of tools like meg. If your workflow already includes comprehensive scanners with built-in smart crawling (Burp Suite Pro, ZAP with advanced configs), uro's value diminishes—you're duplicating logic that those tools handle contextually.