Baike.dev
All toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
U

urx

> 安全
Open source

Extracts URLs from OSINT Archives for Security Insights

189 stars0 likes0 views
WebsiteGitHub

About

Extracts URLs from OSINT Archives for Security Insights

Urx is a command-line tool designed for collecting URLs from OSINT archives, such as the Wayback Machine and Common Crawl. Built with Rust for efficiency, it leverages asynchronous processing to rapidly query multiple data sources. This tool simplifies the process of gathering URL information for a specified domain, providing a comprehensive dataset that can be used for various purposes, including security testing and analysis.

Features

  • Fetch URLs from multiple sources in parallel (Wayback Machine, Common Crawl, OTX, Arquivo.pt)
  • Plug in any other CDX index server — national web archives, a private pywb, OutbackCDX — with --cdx-endpoint URL, no code change needed
  • Keyless by default: Wayback, Common Crawl, OTX, Arquivo.pt, and URLScan (anonymous) all work without an API key
  • BeVigil provider: URLs extracted from unpacked Android apps — endpoints no web archive ever crawled
  • API key rotation support for VirusTotal and URLScan providers to mitigate rate limits
  • Filter results by file extensions, substring patterns, or full regular expressions (--match-regex / --filter-regex)
  • Predefined presets, both by file family ("no-images", "only-js") and by security interest ("only-secrets", "only-backup", "only-config", "only-api")
  • Archive-side filtering: push status code, MIME type, and date range into the CDX query itself, so filtered-out captures never cross the network
  • Client-side metadata filtering (--meta-*): filter on first/last capture date, recorded MIME type and recorded status uniformly across every provider, after collection
  • Bug-bounty scope files (--scope-file): a program's own *.example.com / !admin.example.com list used verbatim, repeatable and unioned, exclusions always winning
  • URL normalization and deduplication: Sort query parameters, remove trailing slashes, merge semantically identical URLs, and collapse near-duplicates that differ only in ids, hashes, or dates (--dedup-similar)
  • Support for multiple output formats: plain text, JSON, JSON Lines, CSV, and wordlist — the path segments and parameter names the target is built from, with ids, hashes and dates left out
  • Parameter and fuzz views: --params (the whole target's parameter inventory), --params-by-endpoint (which endpoint takes what), and --fuzz-placeholder FUZZ (one templated URL per parameter signature, ready for ffuf or dalfox)
  • Archive capture metadata: first_seen, last_seen, mime, archive_status, and digest come back with every URL a CDX archive reported, at no extra network cost
  • Streaming output (--stream): URLs are written as each provider reports them, so a pipeline starts working immediately instead of waiting for the slowest archive
  • Direct file input support: Read URLs directly from WARC files, URLTeam compressed files, and text files
  • Output results to the console or a file, or stream via stdin for pipeline integration
  • URL Testing:
    • Filter and validate URLs based on HTTP status codes and patterns.
    • Extract additional links from collected URLs — anchors, scripts, stylesheets, form actions, iframes, images, media sources, objects, embeds, and meta-refresh targets
    • Mine the archived response bodies of collected URLs (--archive-body), so pages that no longer exist still give up the links they contained — one request per distinct body, thanks to CDX digest deduplication
    • Expand API specifications (--expand-specs): OpenAPI 3.x, Swagger 2.0 and GraphQL introspection documents, JSON or YAML, turned into every route they describe — one request buys the whole documented surface
    • Response metadata: --check-status also records Location, Content-Length and Content-Type, and --check-title adds the HTML ``
  • Archived robots.txt and sitemap.xml discovery (--archived-discovery): every distinct version the Wayback Machine holds, so a Disallow: from 2015 still names the paths the site has since stopped mentioning
  • Caching and Incremental Scanning:
    • Local SQLite or remote Redis caching to avoid re-scanning domains
    • Incremental mode to discover only new URLs since last scan
    • Configurable cache TTL and automatic cleanup of expired entries
    • urx cache subcommand to inspect and maintain the cache: stats, list, prune, drop , clear

Installation

From Cargo

# https://crates.io/crates/urx
cargo install urx

From Homebrew

# https://formulae.brew.sh/formula/urx
brew install urx

From Source

git clone https://github.com/hahwul/urx.git
cd urx
cargo build --release

The compiled binary will be available at target/release/urx.

From Docker

ghcr.io/hahwul/urx

Shell Completions

urx generates its own completion script, so it always matches the flags of the binary you actually have installed.

# zsh — any directory on your $fpath works
urx --completions zsh > ~/.zfunc/_urx
# (make sure ~/.zfunc is on the fpath, then `compinit`)

# bash
urx --completions bash > ~/.local/share/bash-completion/completions/urx

# fish
urx --completions fish > ~/.config/fish/completions/urx.fish

powershell and elvish are supported too. The flag needs no target domain.

Man Page

urx --manpage > ~/.local/share/man/man1/urx.1
man urx

Usage

Basic Usage

# Scan a single domain
urx example.com

# Scan multiple domains
urx example.com example.org

# Scan domains from a file
cat domains.txt | urx

Options

…

--extract-links reads every URL-bearing tag, not just anchors: , , , , , , , , , and targets. Relative URLs resolve against the page (honouring ``), duplicates are collapsed, and discovered links pass through the same filters and host validation as the rest of the run. See docs/content/guide/cli-options.md for the full table.

--extract-js-endpoints goes one step further and reads the JavaScript itself: every collected URL that looks like a script is fetched and its string literals are mined for the paths and URLs the app calls — fetch("/api/v2/users"), axios.post("/graphql"), the static prefix of `/api/orders/${id}`. These are the endpoints that never appear in HTML. Output is aggressively de-noised (MIME types, module specifiers, base64, CSS values, regex fragments and more are dropped), each body is capped at 10 MiB, the number of files fetched is bounded by --max-js-files, and the discovered endpoints pass the same filters and host validation as everything else. The full extraction and noise-suppression policy is in docs/content/guide/cli-options.md.

--archive-body does the same extraction over the bodies the Wayback Machine stored rather than over the live site, so a page that was deleted years ago still yields the links it contained. See Mining Archived Response Bodies.

Examples

…

Regular-expression Filtering

--patterns / --exclude-patterns are plain substring tests: both sides are lower-cased, and every metacharacter is a literal. --match-regex / --filter-regex are the regex counterparts, and they differ in three ways worth remembering:

--patterns --match-regex
Matching substring full regex syntax
Case insensitive (both sides lower-cased) sensitive — use (?i) to opt out
Multiple values one comma-separated flag repeat the flag; commas are never split

Both regex flags are evaluated against the whole URL string as collected (scheme, host, path, and query), so ^https:// and \.js$ both work. Exclusion wins: a URL matching --filter-regex is dropped even if --match-regex also matched it. A malformed expression fails the run at startup, before any archive is queried.

Scope Files

A bug bounty program's scope is a list of hosts, and every platform writes it the same way. --scope-file takes that list verbatim instead of making you hand-translate it into anchored regex alternations — where getting the anchoring wrong silently widens the scope rather than failing.

# scope.txt — in scope
*.example.com
api.example.org

# out of scope, even though the wildcard above covers them
!admin.example.com
!*.internal.example.com
urx example.com --subs --scope-file scope.txt
urx --domain-list targets.txt --subs --scope-file scope-a.txt --scope-file scope-b.txt

*.example.com matches the apex as well as everything under it (the bug-bounty reading, which is what a platform's scope table means); a bare host matches exactly that host; a lone * makes the file a pure deny-list; exclusions always win; # starts a comment. Anything urx cannot honour — a port, a path, a wildcard in the middle — is a startup error naming the file and line rather than a silently wider scope. The filter applies to every provider and to extracted links, and it combines with --strict rather than replacing it, so a *.example.com scope line still needs --subs.

Archive Metadata Filters

--from/--to and the --archive-* predicates are pushed into the archive's own query, which makes them free and also limits them to CDX-backed providers — and the two CDX dialects disagree badly enough that a positive multi-value list (--archive-status 200,301) is unsatisfiable on pywb servers. The eight --meta-* filters run after collection instead, over one merged set of capture metadata per URL, so they apply to every provider uniformly.

…

URLs that carry no metadata — the non-CDX providers, --files input, cache hits — are split by the direction of the predicate: a positive predicate cannot be satisfied by an absent value, so the URL is dropped; an exclusion drops only what positively matches, so it survives. --verbose reports the split, and when missing metadata accounts for the whole result set urx says so even without -v, because a cache hit otherwise makes an empty run look like a target with nothing to find.

Collapsing Near-duplicates

An archive will happily hand back /post/1 through /post/99999. They are one endpoint, and --dedup-similar prints one line for them. A path segment is treated as data — not as part of the route — when it is entirely one of:

  • a run of digits (/post/1, /page/42)
  • a UUID (/u/550e8400-e29b-41d4-a716-446655440000)
  • a 32/40/64-character hex digest (md5, sha1, sha256)
  • a separated date (/blog/2024-01-02/)
  • a long mixed-case token with digits in it (session ids, signed blobs)

Segments that merely contain digits stay put, so /api/v1/ and /api/v2/ are still two endpoints, and a lower-case slug is prose rather than a token. Query strings are grouped by parameter names only: ?q=cats&page=1 and ?q=dogs&page=7 collapse, while ?q=cats alone does not — dropping a parameter changes the request.

The survivor of each group is its lexicographically smallest URL, so two runs over the same data print the same thing. --verbose reports how many URLs were collapsed. The option is independent of --normalize-url and --merge-endpoint and combines with either; all three need the complete result set, so none of them works with --stream.

Parameter and Fuzz Views

--show-only-param only cuts the query string off each URL, which cannot answer the first question a tester asks: what parameters does this target take? Three views answer it, built on the same grouping --dedup-similar uses.

$ urx example.com --params
page
q
ref
sort
utm_source

$ urx example.com --params-by-endpoint
https://example.com/post/{id} ref,utm_source
https://example.com/search page,q,sort

$ urx example.com --fuzz-placeholder FUZZ
https://example.com/post/1?ref=FUZZ
https://example.com/post/2?utm_source=FUZZ
https://example.com/search?q=FUZZ&page=FUZZ
https://example.com/search

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Rustosintosint-toolsecurityurl

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 18, 2026
Category安全
PricingOpen source

> Related tools

O
OWASP ZAP
开源 Web 应用安全扫描器
O
owasp-wstg-tracker
Simple web app to track OWASP WSTG security testing progress
H
homebridge-mi-gateway-security
XiaoMi Gateway Security plugin for HomeBridge.