Zurück zu den Updates
New releaseSep 19, 2026

urx v0.11.0

Extrahiert URLs aus OSINT-Archiven für Sicherheitseinblicke

Teilen
Urx Logo

Extrahiert URLs aus OSINT-Archiven für Sicherheitserkenntnisse.

Urx ist ein Kommandozeilen-Tool, das URLs aus OSINT-Archiven wie der Wayback Machine und Common Crawl sammelt. Es wurde in Rust auf Effizienz ausgelegt und nutzt asynchrone Verarbeitung, um mehrere Datenquellen schnell abzufragen. Dieses Tool vereinfacht den Prozess der Sammlung von URL-Informationen für eine bestimmte Domain und liefert einen umfassenden Datensatz, der für verschiedene Zwecke genutzt werden kann, einschließlich Sicherheitstests und -analysen.

Funktionen

  • URLs aus mehreren Quellen parallel abrufen (Wayback Machine, Common Crawl, OTX, Arquivo.pt)
  • Jeden anderen CDX-Indexserver einbinden — nationale Webarchive, ein privates pywb, OutbackCDX — mit --cdx-endpoint URL, ohne Codeänderung
  • Standardmäßig ohne Schlüssel: Wayback, Common Crawl, OTX, Arquivo.pt und URLScan (anonym) funktionieren alle ohne API-Schlüssel
  • BeVigil-Provider: URLs, die aus entpackten Android-Apps extrahiert wurden — Endpunkte, die kein Webarchiv jemals gecrawlt hat
  • Unterstützung für API-Schlüsselrotation bei den Providern VirusTotal und URLScan, um Ratenlimits zu mildern
  • Authentifiziertes Testen: -H, --cookie und --user-agent gelten für jede Anfrage, die urx an das Ziel stellt (--check-status, --extract-links, --extract-js-endpoints, --expand-specs) und werden bewusst niemals an ein Archiv gesendet
  • Ergebnisse nach Dateiendungen, Teilstring-Mustern oder vollständigen regulären Ausdrücken filtern (--match-regex / --filter-regex)
  • Vordefinierte Presets, sowohl nach Dateifamilie ("no-images", "only-js") als auch nach Sicherheitsinteresse ("only-secrets", "only-backup", "only-config", "only-api")
  • Archivseitige Filterung: Statuscode, MIME-Typ und Datumsbereich direkt in die CDX-Abfrage einbeziehen, sodass herausgefilterte Captures niemals über das Netzwerk gehen
  • Clientseitige Metadatenfilterung (--meta-*): Filterung nach erstem/letztem Capture-Datum, aufgezeichnetem MIME-Typ und aufgezeichnetem Status einheitlich über jeden Provider, nach der Sammlung
  • Pfadbezogene Ziele: urx example.com/shop schiebt den Geltungsbereich direkt in die CDX-Abfrage (url=example.com/shop*), sodass ein Teilbaum einer großen Website nur einen Bruchteil des gesamten Index kostet, statt clientseitig herausgefiltert zu werden
  • Bug-Bounty-Scope-Dateien (--scope-file): die eigene *.example.com / !admin.example.com-Liste eines Programms wird wörtlich verwendet, wiederholbar und vereinigt, Ausschlüsse gewinnen immer
  • URL-Normalisierung und Deduplizierung: Abfrageparameter sortieren, abschließende Schrägstriche entfernen, semantisch identische URLs zusammenführen und Fast-Duplikate zusammenfassen, die sich nur in IDs, Hashes oder Datumsangaben unterscheiden (--dedup-similar)
  • Unterstützung für mehrere Ausgabeformate: Klartext, JSON, JSON Lines, CSV und wordlist — die Pfadsegmente und Parameternamen, aus denen das Ziel aufgebaut ist, ohne IDs, Hashes und Datumsangaben
  • Parameter- und Fuzz-Ansichten: --params (das gesamte Parameterinventar des Ziels), --params-by-endpoint (welcher Endpunkt was annimmt) und --fuzz-placeholder FUZZ (eine templatisierte URL pro Parametersignatur, bereit für ffuf oder dalfox)
  • Archiv-Capture-Metadaten: first_seen, last_seen, mime, archive_status und digest kommen mit jeder URL zurück, die ein CDX-Archiv gemeldet hat, ohne zusätzliche Netzwerkkosten
  • Streaming-Ausgabe (--stream): URLs werden geschrieben, sobald jeder Provider sie meldet, sodass eine Pipeline sofort mit der Arbeit beginnt, statt auf das langsamste Archiv zu warten
  • Unterstützung für direkte Dateieingabe: URLs direkt aus WARC-Dateien, URLTeam-komprimierten Dateien und Textdateien lesen
  • Ergebnisse auf der Konsole oder in einer Datei ausgeben oder über stdin für die Pipeline-Integration streamen
  • URL-Testing:
    • URLs anhand von HTTP-Statuscodes und Mustern filtern und validieren.
    • Zusätzliche Links aus gesammelten URLs extrahieren — Anker, Skripte, Stylesheets, Formularaktionen, Iframes, Bilder, Medienquellen, Objekte, Embeds und Meta-Refresh-Ziele
    • Die archivierten Antwortkörper gesammelter URLs durchsuchen (--archive-body), sodass Seiten, die nicht mehr existieren, noch die Links preisgeben, die sie enthielten — eine Anfrage pro unterschiedlichem Body, dank CDX-Digest-Deduplizierung
    • Mit --extract-js-endpoints auch das archivierte JavaScript durchsuchen: Ein Bundle, das nach Build-Hash benannt ist, liefert 404, sobald die Website neu deployt wird, und das Archiv ist der einzige Ort, an dem seine API-Oberfläche noch existiert
    • Die wiedergegebenen Bodies (--archive-body-dir) als Korpus behalten, um nach dem zu greppen, wonach kein Link-Extraktor sucht — Entwicklerkommentare, eingebettete Zugangsdaten, interne Hostnamen — ohne zusätzliche Anfragen
    • API-Spezifikationen erweitern (--expand-specs): OpenAPI 3.x-, Swagger 2.0- und GraphQL-Introspection-Dokumente, JSON oder YAML, in jede Route umgewandelt, die sie beschreiben — eine Anfrage kauft die gesamte dokumentierte Oberfläche
    • Antwort-Metadaten: --check-status zeichnet auch Location, Content-Length und Content-Type auf, und --check-title fügt den HTML-<title> hinzu
  • Archivierte robots.txt- und sitemap.xml-Erkennung (--archived-discovery): jede unterschiedliche Version, die die Wayback Machine besitzt, sodass ein Disallow: aus 2015 noch die Pfade nennt, die die Website seither nicht mehr erwähnt
  • Caching und inkrementelles Scannen:
    • Lokales SQLite- oder entferntes Redis-Caching, um erneutes Scannen von Domains zu vermeiden
    • Inkrementeller Modus, um nur neue URLs seit dem letzten Scan zu entdecken
    • Konfigurierbare Cache-TTL und automatische Bereinigung abgelaufener Einträge
    • urx cache-Unterbefehl zum Inspizieren und Pflegen des Caches: stats, list, prune, drop <domain>, clear

Preview

Installation

Aus Cargo```bash

https://crates.io/crates/urx

cargo install urx

### Über Homebrew```bash
# https://formulae.brew.sh/formula/urx
brew install urx

Aus der Quelle```bash

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

Das kompilierte Binary ist unter `target/release/urx` verfügbar.

### Aus Docker

[ghcr.io/hahwul/urx](https://github.com/hahwul/urx/pkgs/container/urx)

### Shell-Vervollständigungen

`urx` generiert sein eigenes Vervollständigungsskript, sodass es immer mit den Flags
des Binaries übereinstimmt, das Sie tatsächlich installiert haben.```bash
# 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 und elvish werden ebenfalls unterstützt. Das Flag benötigt keine Zieldomain.

Man-Page```bash

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

## Verwendung

### Grundlegende Verwendung```bash
# Scan a single domain
urx example.com

# Scan multiple domains
urx example.com example.org

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

Optionen```

Usage: urx [OPTIONS] [DOMAINS]... [COMMAND]

Commands: cache Inspect and maintain the URL cache: stats, list, prune, drop ..., clear

Arguments: [DOMAINS]... Domains to fetch URLs for

Options: -c, --config Config file to load --provider-config Separate provider config file holding only API keys (default: $XDG_CONFIG_HOME/urx/provider-config.toml). CLI/env > provider-config > main config. --completions Print a shell completion script (bash, zsh, fish, powershell, elvish) to stdout and exit --manpage Print the roff man page to stdout and exit -h, --help Print help -V, --version Print version

Input Options: --files ... Read URLs directly from files (supports WARC, URLTeam compressed, and text files) --domain-list File of newline-separated domains to scan (repeatable; merged with positional DOMAINS and stdin; # comments allowed)

Output Options: -o, --output Output file to write results --output-dir Write one file per domain into this directory (extension matches --format). Coexists with --output / stdout. -f, --format Output format: "plain", "json" (one array), "jsonl" (one JSON object per line), "csv", "wordlist" (path segments and parameter names, deduplicated and sorted) [default: plain] --stream Write URLs as each provider reports them instead of once at the end (unsorted; bypasses cache; rejects options needing the full result set) --merge-endpoint Merge endpoints with the same path and merge URL parameters --normalize-url Normalize URLs for better deduplication (sorts query parameters, removes trailing slashes) --dedup-similar Collapse URLs that differ only in variable data (numeric ids, UUIDs, hashes, dates, query values) --params Replace the URL list with every query parameter name the run saw, once each --params-by-endpoint One line per endpoint: the endpoint and the comma-separated union of the parameter names seen on it (id-looking path segments collapse to {id}) --fuzz-placeholder Replace every query parameter value with VALUE, keeping one URL per parameter signature — output you can feed straight to ffuf or dalfox

Provider Options: --providers Providers to use (comma-separated, e.g., "wayback,cc,otx,arquivo,vt,urlscan") [default: wayback,cc,otx] --exclude-providers <EXCLUDE_PROVIDERS> Providers to exclude (comma-separated). Wins on conflict with --providers / --all-providers. --all-providers Enable every supported provider. API-keyed providers only activate when a key is available. --list-providers List every supported provider then exit. --subs Include subdomains when searching --cc-index <CC_INDEX> Common Crawl index to use; accepts comma-separated list to query multiple indexes in parallel (e.g. CC-MAIN-2026-17,CC-MAIN-2025-51). latest (the default) resolves the newest via collinfo.json. [default: latest] --cdx-endpoint Query an additional CDX index server (any pywb, OutbackCDX, or classic Internet-Archive-style CDX API) by its full API URL, e.g. https://vefsafn.is/cdx. Repeatable. Each endpoint becomes a provider with id cdx:<host> and honours --subs, --from/--to and the --archive-* filters. See "Custom CDX Endpoints" below --cdx-dialect Which CDX dialect the --cdx-endpoint servers speak: pywb or classic. Unset: urx probes each endpoint once and falls back to pywb when the answer is ambiguous --from Restrict every CDX-backed provider (wayback, cc, arquivo, --cdx-endpoint) to captures at or after DATE (YYYY/YYYYMM/YYYYMMDD/YYYYMMDDhhmmss). Alias: --wayback-from --to Restrict every CDX-backed provider to captures at or before DATE (same format as --from). Alias: --wayback-to --archive-status Keep only captures the archive recorded with this HTTP status code (e.g. "200"). Applied by the CDX index itself, so unlike --include-status it costs no extra requests. A multi-value list works on wayback only — see "Archive-side Filtering" below --archive-exclude-status Drop captures the archive recorded with these HTTP status codes (comma-separated, e.g. "404,500"). Multi-value works on every CDX provider --archive-mime Keep only captures with this recorded MIME type (e.g. "application/json"). Catches endpoints with no file extension, which -e/--extensions cannot --archive-exclude-mime Drop captures with these recorded MIME types (comma-separated, e.g. "text/html,image/png") --vt-api-key <VT_API_KEY> API key for VirusTotal (can be used multiple times for rotation, can also use URX_VT_API_KEY environment variable with comma-separated keys) --urlscan-api-key <URLSCAN_API_KEY> Optional API key for Urlscan; the provider also works anonymously (rate-limited ~30 req/min per IP). Can be used multiple times for rotation, or via URX_URLSCAN_API_KEY (comma-separated keys) --github-api-key <GITHUB_API_KEY> Personal access token for the GitHub Code Search provider (also reads URX_GITHUB_API_KEY, comma-separated for rotation) --bevigil-api-key <BEVIGIL_API_KEY> API key for BeVigil, which returns URLs extracted from unpacked Android apps (also reads URX_BEVIGIL_API_KEY, comma-separated for rotation). Required for the bevigil provider

Discovery Options: --exclude-robots Exclude robots.txt discovery --exclude-sitemap Exclude sitemap.xml discovery --archived-discovery Also read every distinct archived version of robots.txt and sitemap.xml the Wayback Machine holds --archived-discovery-limit Maximum archived documents fetched per domain by each archived provider (nested sitemaps count) [default: 50]

Display Options: -v, --verbose Show verbose output --silent Silent mode (no output) --no-progress No progress bar --no-color Disable ANSI color in the progress UI and output (NO_COLOR is also honored) --show-sources Annotate output URLs with the providers that returned them --show-meta Annotate plain-text URLs with the archive capture metadata --stats Print a per-provider summary to stderr at end of run

Filter Options: -p, --preset Filter Presets (e.g., "no-resources,no-images,no-audio,only-js,only-style,only-secrets,only-backup,only-config,only-api") -e, --extensions Filter URLs to only include those with specific extensions (comma-separated, e.g., "js,php,aspx") --exclude-extensions <EXCLUDE_EXTENSIONS> Filter URLs to exclude those with specific extensions (comma-separated, e.g., "html,txt") --patterns Filter URLs to only include those containing specific patterns (comma-separated) --exclude-patterns <EXCLUDE_PATTERNS> Filter URLs to exclude those containing specific patterns (comma-separated) --match-regex Keep only URLs matching this regular expression (repeatable, ORed; case-sensitive; never comma-split) --filter-regex Drop URLs matching this regular expression (repeatable; one match is enough) --show-only-host Only show the host part of the URLs --show-only-path Only show the path part of the URLs --show-only-param Only show the parameters part of the URLs --min-length <MIN_LENGTH> Minimum URL length to include --max-length <MAX_LENGTH> Maximum URL length to include --strict Enforce exact host validation (default) --no-strict Disable host validation (keep URLs on any host a provider returns). Wins over --strict. A target's path scope still applies: only the host check is waived --scope-file Bug-bounty scope file: one host pattern per line, ! to exclude, *.example.com for a wildcard (which covers the apex too), # for a comment. Repeatable and unioned; exclusions always win. See "Scope Files" below --meta-first-seen-after Keep URLs whose oldest archived capture is on or after DATE (YYYY/YYYYMM/YYYYMMDD/YYYYMMDDhhmmss) --meta-first-seen-before Keep URLs whose oldest archived capture is on or before DATE --meta-last-seen-after Keep URLs whose newest archived capture is on or after DATE — "still alive as of" --meta-last-seen-before Keep URLs whose newest archived capture is on or before DATE — "dead since" --meta-mime Keep only URLs whose archived MIME type is one of these (comma-separated; image/* matches any subtype) --meta-exclude-mime Drop URLs whose archived MIME type is one of these --meta-status Keep only URLs whose archived status code matches (comma-separated; 20x / 5xx patterns) --meta-exclude-status Drop URLs whose archived status code matches

Network Options: --network-scope <NETWORK_SCOPE> Control which components network settings apply to (all, providers, testers, or providers,testers) [default: all] --proxy Use proxy for HTTP requests (format: http://proxy.example.com:8080) --proxy-auth <PROXY_AUTH> Proxy authentication credentials (format: username:password) --insecure Skip SSL certificate verification (accept self-signed certs) --random-agent Use a random User-Agent for HTTP requests -H, --header <NAME: VALUE> Extra request header, repeatable; sent only on requests urx makes to the target, never to an archive --cookie Cookie header for requests to the target; shorthand for -H "Cookie: ..." --user-agent User-Agent for requests to the target, overriding the default and --random-agent --timeout Request timeout in seconds [default: 120] --retries Number of retries for failed requests [default: 2] --parallel Maximum domains fetched concurrently per provider (and concurrent URL tests); a provider's --rate-limit is shared across them [default: 5] --rate-limit <RATE_LIMIT> Rate limit (requests per second) --rate-limit-by Per-provider rate overrides (e.g. vt=1,wayback=10); falls back to --rate-limit for unlisted providers --max-time <MAX_TIME> Global ceiling on provider enumeration time in seconds (0 = unlimited) [default: 0]

Testing Options: --check-status Check HTTP status code of collected URLs [aliases: ----cs] --check-title Also record each response's HTML while checking statuses; implies --check-status --include-status <INCLUDE_STATUS> Include URLs with specific HTTP status codes or patterns (e.g., --is=200,30x) [aliases: ----is] --exclude-status <EXCLUDE_STATUS> Exclude URLs with specific HTTP status codes or patterns (e.g., --es=404,50x,5xx) [aliases: ----es] --extract-links Extract additional links from collected URLs (requires HTTP requests) --extract-js-endpoints Fetch collected JavaScript files and extract the endpoint paths and URLs found in their string literals (requires HTTP requests); with --archive-body this also mines the archived copy of each script --max-js-files Maximum number of files --extract-js-endpoints will fetch (0 = unlimited) [default: 500] --archive-body Fetch the archived body of each collected URL from the Wayback Machine and extract the links inside it (works for pages that no longer exist) --archive-body-limit Maximum number of archived bodies --archive-body fetches per run; bounds distinct bodies, not URLs [default: 500] --archive-body-dir

Keep every body --archive-body replays in DIR, with an index.jsonl mapping each file back to its URL, capture and content type --expand-specs Fetch the API specification documents among the collected URLs (OpenAPI, Swagger, GraphQL introspection; JSON or YAML) and expand every route they document into a URL. See "Expanding API Specifications" below --max-spec-files Maximum number of specification documents --expand-specs will fetch (0 = unlimited) [default: 50]

Cache Options: --incremental Enable incremental scanning mode (only return new URLs compared to previous scans) --cache-type Cache backend: sqlite or redis [default: sqlite] --cache-path Path for the SQLite cache database --redis-url Redis connection URL for remote caching --cache-ttl Cache time-to-live in seconds [default: 86400] --no-cache Disable caching entirely

Notification Options: --notify POST a run summary to this webhook when the run ends (repeatable; also URX_NOTIFY_URL, provider-config notify_url, or [notify].url) --notify-on <NOTIFY_ON> When to send: new (only if URLs were emitted), always, or never [default: new] --notify-format <NOTIFY_FORMAT> Payload shape: json (urx summary), slack ({"text"}), or discord ({"content"}) [default: json]

`--extract-links` liest jedes Tag mit URL, nicht nur Anker: `<a href>`,
`<script src>`, `<link href>`, `<form action>`, ``, ``,
`<source src>`, `<object data>`, `<embed src>` und `<meta http-equiv="refresh">`
-Ziele. Relative URLs werden gegen die Seite aufgelöst (unter Berücksichtigung von `<base href>`),
Duplikate werden zusammengefasst, und entdeckte Links durchlaufen dieselben Filter
und Host-Validierungen wie der Rest des Durchlaufs. Siehe
[docs/content/guide/cli-options.md](https://github.com/hahwul/urx/blob/main/docs/content/guide/cli-options.md) für die
vollständige Tabelle.

`--extract-js-endpoints` geht einen Schritt weiter und liest das JavaScript
selbst: jede gesammelte URL, die wie ein Skript aussieht, wird abgerufen und ihre
String-Literale werden nach den Pfaden und URLs durchsucht, die die App aufruft —
`fetch("/api/v2/users")`, `axios.post("/graphql")`, das statische Präfix von
`` `/api/orders/${id}` ``. Dies sind die Endpunkte, die nie im HTML erscheinen.
Die Ausgabe wird aggressiv entrauscht (MIME-Typen, Modul-Spezifizierer, Base64,
CSS-Werte, Regex-Fragmente und mehr werden verworfen), jeder Body ist auf
10 MiB begrenzt, die Anzahl der abgerufenen Dateien wird durch `--max-js-files` begrenzt, und die
entdeckten Endpunkte durchlaufen dieselben Filter und Host-Validierungen wie alles
andere. Die vollständige Extraktions- und Rauschunterdrückungsrichtlinie finden Sie in
[docs/content/guide/cli-options.md](https://github.com/hahwul/urx/blob/main/docs/content/guide/cli-options.md#javascript-endpoint-extraction).

`--archive-body` führt dieselbe Extraktion über die Bodies durch, die die Wayback Machine
*gespeichert* hat, statt über die Live-Seite, sodass eine Seite, die vor Jahren gelöscht wurde,
immer noch die enthaltenen Links liefert. Siehe
[Mining Archived Response Bodies](#mining-archived-response-bodies).

### Beispiele```bash
# Save results to a file
urx example.com -o results.txt

# Output in JSON format
urx example.com -f json -o results.json

# Filter for JavaScript files only
urx example.com -e js

# Exclude HTML and text files
urx example.com --exclude-extensions html,txt

# Filter for API endpoints
urx example.com --patterns api,v1,graphql

# Exclude specific patterns
urx example.com --exclude-patterns static,images

# Use Fileter Preset (similar to --exclude-extensions=png,jpg,.....)
urx example.com -p no-images

# Use specific providers
urx example.com --providers wayback,otx

# Add the keyless Arquivo.pt (Portuguese web archive) provider
urx example.com --providers wayback,cc,otx,arquivo

# Query another CDX index server alongside the defaults (id: cdx:vefsafn.is)
urx example.is --cdx-endpoint https://vefsafn.is/cdx

# ...or on its own, rate-limited, with the archive-side filters it shares with wayback/cc
urx example.is --cdx-endpoint https://vefsafn.is/cdx --providers cdx:vefsafn.is \
  --rate-limit-by cdx:vefsafn.is=1 --from 2020 --archive-status 200

# URLScan works without a key (anonymous, rate-limited); a key just raises limits
urx example.com --providers urlscan

# BeVigil: endpoints pulled out of unpacked Android apps (key required; auto-enables the provider)
URX_BEVIGIL_API_KEY=*** urx example.com

# Using VirusTotal and URLScan providers
# 1. Explicitly add to providers (with API keys via command line)
urx example.com --providers=vt,urlscan --vt-api-key=*** --urlscan-api-key=***

# 2. Using environment variables for API keys
URX_VT_API_KEY=*** URX_URLSCAN_API_KEY=*** urx example.com --providers=vt,urlscan

# 3. Auto-enabling: providers are automatically added when API keys are provided
urx example.com --vt-api-key=*** --urlscan-api-key=*** # No need to specify in --providers

# 4. Multiple API key rotation (to mitigate rate limits)
# Using repeated flags for multiple keys
urx example.com --vt-api-key=key1 --vt-api-key=key2 --vt-api-key=key3

# Using environment variables with comma-separated keys
URX_VT_API_KEY=key1,key2,key3 URX_URLSCAN_API_KEY=ukey1,ukey2 urx example.com

# Combining CLI flags and environment variables (CLI keys are used first)
URX_VT_API_KEY=env_key1,env_key2 urx example.com --vt-api-key=cli_key1 --vt-api-key=cli_key2

# URLs from robots.txt and sitemap.xml are included by default

# Exclude URLs from robots.txt files
urx example.com --exclude-robots

# Exclude URLs from sitemap
urx example.com --exclude-sitemap

# Also read every archived version of robots.txt and sitemap.xml, so paths the
# site once listed and has since removed come back
urx example.com --archived-discovery

# Only the versions captured in a given era
urx example.com --archived-discovery --from 2014 --to 2016 --exclude-sitemap

# Include subdomains
urx example.com --subs

# Check status of collected URLs
urx example.com --check-status

# Read URLs directly from a text file
urx --files urls.txt

# Combine file input with filtering
urx --files urls.txt --patterns api,admin -f json

# Extract additional links from collected URLs
# (anchors, scripts, stylesheets, form actions, iframes, images, media
#  sources, objects, embeds, and meta-refresh targets)
urx example.com --extract-links

# Discovered links go through the same filters as everything else, so this
# keeps only the JavaScript the pages reference
urx example.com --extract-links -e js

# Read the collected JavaScript and pull out the API paths it calls
urx example.com --extract-js-endpoints --patterns api

# Chain them: collect the site's bundles, then mine those for endpoints
urx example.com --extract-links --extract-js-endpoints --max-js-files 100

# Mine the links inside the *archived* bodies instead — dead pages included.
# One request per distinct body; the limit bounds bodies, not URLs
urx example.com --archive-body --archive-body-limit 200 --rate-limit 5

# Network configuration
urx example.com --proxy http://localhost:8080 --timeout 60 --parallel 10 --insecure

# Advanced filtering
urx example.com -e js,php --patterns admin,login --exclude-patterns logout,static --min-length 20

# HTTP Status code based filtering (live requests: urx re-fetches each URL)
urx example.com --include-status 200,30x,405 --exclude-status 20x

# Archive-side filtering (free: the CDX index already knows these)
# Skip everything the archive recorded as a 404 — no extra requests
urx example.com --archive-exclude-status 404

# Only captures the archive served as JSON — finds extensionless API endpoints
urx example.com --archive-mime application/json

# Drop HTML to leave assets and endpoints behind
urx example.com --archive-exclude-mime text/html

# Restrict the crawl window across wayback, cc, arquivo, and any --cdx-endpoint alike
urx example.com --from 2023 --to 2024

# Disable host validation
urx example.com --strict false

# URL normalization and deduplication
# Normalize URLs by sorting query parameters and removing trailing slashes
urx example.com --normalize-url

# Combine normalization with endpoint merging for comprehensive deduplication
urx example.com --normalize-url --merge-endpoint

# URL normalization with file input
urx --files urls.txt --normalize-url

# Collapse /post/1, /post/2, /post/99999 ... into a single representative line
urx example.com --dedup-similar

# Regular-expression filtering (repeat either flag; they are never comma-split)
urx example.com --match-regex '/api/v[0-9]+/'
urx example.com --match-regex '\.php$' --match-regex '\.aspx$'
urx example.com --filter-regex '/(assets|static)/'

# Regexes are case-sensitive; ask for insensitivity explicitly
urx example.com --match-regex '(?i)admin'

# Security presets: match by path shape as well as by extension
urx example.com -p only-secrets   # /.env, /.git/config, id_rsa, *.pem
urx example.com -p only-backup    # *.bak, *.sql, /backup/, index.php~
urx example.com -p only-config    # *.yaml, web.config, .htaccess, Dockerfile
urx example.com -p only-api       # /api/, /v1/, /graphql, /swagger, *.wsdl

# Scope files: a bug bounty program's own host list, used verbatim
urx example.com --subs --scope-file scope.txt

# Metadata filters, applied after collection so every provider is covered
urx example.com --providers wayback --meta-last-seen-after 2024 --meta-exclude-mime 'image/*'
urx example.com --providers wayback --meta-mime application/json --meta-status 200

# What parameters does this target take, and where?
urx example.com --params
urx example.com --params-by-endpoint

# One templated URL per parameter signature, straight into a fuzzer
urx example.com --fuzz-placeholder FUZZ | ffuf -w - -u FUZZ

# A target-specific wordlist instead of a URL list
urx example.com --subs -f wordlist -o words.txt

# Open the API specifications the sweep found and expand every route in them
urx example.com -p only-api --expand-specs

# Status checks also keep the response head; --check-title adds the <title>
urx example.com --check-status -f jsonl
urx example.com --check-title --show-meta

# Inspect and maintain the cache
urx cache stats
urx cache drop example.com

Einen Lauf auf einen Pfad beschränken

Ein Ziel kann einen Pfad angeben, und es bedeutet, was es sagt: urx example.com/shop sammelt den Teil der Website unter /shop.```bash urx example.com/shop urx https://example.com/api/v2 # a pasted URL works too

Das ist kein Filter, der nachträglich angewendet wird. Ein CDX-Index beantwortet Präfixabfragen nativ, also sendet urx `url=example.com/shop*` und das Archiv überträgt den Rest der Website nie über das Netzwerk — bei einem großen Ziel ist das der Unterschied zwischen ein paar hundert Zeilen und ein paar hunderttausend. Anbieter, die einen Pfad nicht in ihrer Abfrage ausdrücken können (OTX, VirusTotal, urlscan, GitHub, BeVigil, ZoomEye), werden nach dem Host gefragt und ihre Antworten werden anschließend eingegrenzt, ebenso wie die Ergebnisse eines `--subs`-Laufs, bei dem die `*.host`-Form und ein Pfadpräfix nicht in einer CDX-Abfrage kombiniert werden können.

Scope bedeutet *auf oder unter* dem Pfad: `/shop` und `/shop/cart` sind enthalten, `/shopping` nicht. Groß-/Kleinschreibung wird ignoriert, weil ein CDX-Server die gesamte URL in Kleinbuchstaben umwandelt, wenn er seinen Indexschlüssel erstellt — `example.com/Shop*` und `example.com/shop*` liefern dieselben Zeilen, alle in Kleinbuchstaben geschrieben, sodass eine groß-/kleinschreibungssensitive Prüfung alles verwerfen würde, was das Archiv gerade zurückgegeben hat. Ein Query-String oder Fragment im Ziel wird verworfen — diese schränken eine Anfrage ein, nicht einen Scope.

> Hinweis: urx hat früher den Pfad aus einem Ziel verworfen, sodass
> `urx https://example.com/shop` die gesamte Domain `example.com` scannte. Jetzt
> wird `/shop` gescannt. Übergeben Sie nur den Host für das alte Verhalten; ein Lauf, dessen Ziel
> einen Pfad enthält, gibt dies auf stderr aus.

### Filterung mit regulären Ausdrücken

`--patterns` / `--exclude-patterns` sind einfache Teilstring-Tests: beide Seiten werden
in Kleinbuchstaben umgewandelt, und jedes Metazeichen ist ein Literal. `--match-regex` /
`--filter-regex` sind die Regex-Gegenstücke, und sie unterscheiden sich in drei Punkten, die
es wert sind, in Erinnerung zu bleiben:

| | `--patterns` | `--match-regex` |
|---|---|---|
| Übereinstimmung | Teilstring | vollständige [Regex-Syntax](https://docs.rs/regex/latest/regex/#syntax) |
| Groß-/Kleinschreibung | insensitive (beide Seiten in Kleinbuchstaben) | **sensitive** — verwenden Sie `(?i)`, um dies zu deaktivieren |
| Mehrere Werte | ein kommagetrennter Schalter | den Schalter wiederholen; Kommas werden nie aufgeteilt |

Beide Regex-Schalter werden gegen die **gesamte URL-Zeichenkette** ausgewertet, wie sie gesammelt wurde
(Schema, Host, Pfad und Query), sodass sowohl `^https://` als auch `\.js$` funktionieren.
Ausschluss gewinnt: eine URL, die auf `--filter-regex` passt, wird verworfen, selbst wenn
`--match-regex` ebenfalls darauf gepasst hat. Ein fehlerhafter Ausdruck lässt den Lauf beim
Start fehlschlagen, bevor ein Archiv abgefragt wird.

### Scope-Dateien

Der Scope eines Bug-Bounty-Programms ist eine Liste von Hosts, und jede Plattform schreibt sie
auf die gleiche Weise. `--scope-file` nimmt diese Liste wörtlich entgegen, anstatt Sie
sie manuell in verankerte Regex-Alternationen zu übersetzen — wobei eine falsche
Verankerung den Scope stillschweigend *erweitert*, anstatt fehlzuschlagen.```text
# 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

Ihre Antwort ist leer. Bitte geben Sie den zu übersetzenden Inhalt an.```bash 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` trifft sowohl den Apex als auch alles darunter (die
Bug-Bounty-Lesart, die eine Scope-Tabelle einer Plattform meint); ein bloßer Host
trifft genau diesen Host; ein einzelnes `*` macht die Datei zu einer reinen Deny-Liste;
Ausschlüsse gewinnen immer; `#` beginnt einen Kommentar. Alles, was urx nicht
berücksichtigen kann — ein Port, ein Pfad, ein Wildcard in der Mitte — ist ein
Startfehler, der die Datei und Zeile benennt, statt einen stillschweigend
erweiterten Scope. Der Filter gilt für jeden Provider und für extrahierte Links,
und er kombiniert sich mit `--strict`, statt es zu ersetzen, sodass eine
`*.example.com`-Scope-Zeile weiterhin `--subs` benötigt.

### Archiv-Metadaten-Filter

`--from`/`--to` und die `--archive-*`-Prädikate werden in die eigene Abfrage des
Archivs geschoben, was sie kostenlos macht und sie zugleich auf CDX-gestützte
Provider beschränkt — und die beiden CDX-Dialekte unterscheiden sich so stark,
dass eine positive Mehrwertliste (`--archive-status 200,301`) auf pywb-Servern
nicht erfüllbar ist. Die acht `--meta-*`-Filter laufen stattdessen *nach* der
Sammlung, über eine zusammengeführte Menge von Capture-Metadaten pro URL, sodass
sie einheitlich für jeden Provider gelten.```bash
# Endpoints still being captured recently, with HTML and images out of the way
urx example.com --providers wayback --meta-last-seen-after 2024 --meta-exclude-mime 'text/html,image/*'

# Pages that died: nothing captured since 2019
urx example.com --providers wayback --meta-last-seen-before 2019

# JSON the archive served successfully
urx example.com --providers wayback --meta-mime application/json --meta-status 200

# First archived during 2020 (partial dates pad to the start / end of the period)
urx example.com --providers wayback --meta-first-seen-after 2020 --meta-first-seen-before 2020

URLs ohne Metadaten — die Nicht-CDX-Provider, --files-Eingabe, Cache-Treffer — werden nach der Richtung des Prädikats aufgeteilt: Ein positives Prädikat kann nicht durch einen fehlenden Wert erfüllt werden, also wird die URL verworfen; eine Ausschlussbedingung verwirft nur, was positiv übereinstimmt, also überlebt sie. --verbose meldet die Aufteilung, und wenn fehlende Metadaten die gesamte Ergebnismenge ausmachen, sagt urx dies auch ohne -v, weil ein Cache-Treffer sonst einen leeren Lauf wie ein Ziel ohne Fund erscheinen lässt.

Kollabieren von Fast-Duplikaten

Ein Archiv gibt bereitwillig /post/1 bis /post/99999 zurück. Sie sind ein Endpunkt, und --dedup-similar gibt eine Zeile für sie aus. Ein Pfadsegment wird als Daten — nicht als Teil der Route — behandelt, wenn es vollständig eines der folgenden ist:

  • eine Folge von Ziffern (/post/1, /page/42)
  • eine UUID (/u/550e8400-e29b-41d4-a716-446655440000)
  • ein 32/40/64-stelliger Hex-Digest (md5, sha1, sha256)
  • ein getrenntes Datum (/blog/2024-01-02/)
  • ein langes Token mit gemischter Groß-/Kleinschreibung und Ziffern darin (Session-IDs, signierte Blobs)

Segmente, die lediglich Ziffern enthalten, bleiben bestehen, sodass /api/v1/ und /api/v2/ weiterhin zwei Endpunkte sind, und ein Slug in Kleinbuchstaben ist Prosa und kein Token. Query-Strings werden nur nach Parameter-Namen gruppiert: ?q=cats&page=1 und ?q=dogs&page=7 kollabieren, während ?q=cats allein dies nicht tut — das Weglassen eines Parameters ändert die Anfrage.

Der Überlebende jeder Gruppe ist ihre lexikografisch kleinste URL, sodass zwei Läufe über dieselben Daten dasselbe ausgeben. --verbose meldet, wie viele URLs kollabiert wurden. Die Option ist unabhängig von --normalize-url und --merge-endpoint und kombiniert sich mit beiden; alle drei benötigen die vollständige Ergebnismenge, sodass keine von ihnen mit --stream funktioniert.

Parameter- und Fuzz-Ansichten

--show-only-param schneidet lediglich den Query-String von jeder URL ab, was die erste Frage eines Testers nicht beantworten kann: Welche Parameter nimmt dieses Ziel entgegen? Drei Ansichten beantworten sie, aufgebaut auf derselben Gruppierung, die --dedup-similar verwendet.```console $ 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?q=FUZZ&sort=FUZZ

`--params-by-endpoint` fasst id-artige Pfadsegmente zu `{id}` zusammen, genau wie
`--dedup-similar` es tut, und schreibt den Endpunkt vollständig aus, weil urx
routinemäßig mehrere Hosts in einem Durchlauf scannt. `--fuzz-placeholder` behält eine URL pro
Parametersignatur und behält ihren echten Pfad bei – ein `{id}` würde nicht geroutet werden –,
sodass die Ausgabe direkt in einen Fuzzer eingespeist werden kann:```bash
urx example.com --fuzz-placeholder FUZZ | ffuf -w - -u FUZZ
urx example.com --fuzz-placeholder FUZZ | dalfox pipe

Alle drei benötigen das vollständige Ergebnisset, daher sind sie nur im Batch-Modus verfügbar und schließen sich gegenseitig sowie mit den --show-only-*-Ansichten aus.

Wordlist-Ausgabe

-f wordlist verwandelt einen Lauf in eine zielspezifische Wordlist: jedes gesehene Pfadsegment und jeder Query-Parameter-Name, über den gesamten Lauf dedupliziert und sortiert, ein Begriff pro Zeile.```bash urx example.com --subs -f wordlist -o words.txt ffuf -w words.txt -u https://example.com/FUZZ

Segmente, die eher wie Daten als wie Routennamen aussehen, werden weggelassen, wobei die Testgruppen `--dedup-similar` wiederverwendet werden — eine Wortliste voller `4711`, UUIDs, Daten und Session-Tokens ist schlechter als gar keine Wortliste, da jedes dieser Wörter auf genau einem Ziel existiert. Ein Segment, dessen Stamm ein Identifier ist, entfällt ebenfalls
(`article-1234.html`). Groß-/Kleinschreibung bleibt erhalten: Pfadsegmente sind auf den meisten Origins case-sensitive, sodass die Kleinschreibung von `WebResource.axd` ein Wort erzeugen würde, das überall, wo es versucht wird, 404 liefert. Die Vereinigung muss über die vollständige Menge gebildet werden, daher ist das Format nur im Batch-Modus möglich.

### Streaming-Ausgabe

Standardmäßig sammelt urx alles, filtert dann, sortiert und gibt einmal aus. Bei einem großen Ziel bedeutet das gar keine Ausgabe, bis das langsamste Archiv fertig ist.
`--stream` schreibt jede URL in dem Moment, in dem der Provider, der sie meldet, zurückkommt:```bash
# Matches start appearing immediately instead of after the slowest provider
urx big-target.com --stream | grep admin

# Line-delimited JSON stays valid while it is still being written
urx big-target.com --stream -f jsonl | jq -r 'select(.url | test("/api/")) | .url'

Gestreamte URLs durchlaufen exakt dieselben Filter wie ein Batch-Lauf und werden weiterhin dedupliziert. Zwei Dinge unterscheiden sich:

  • Reihenfolge. Ergebnisse treffen in der Reihenfolge des Abschlusses der Provider ein, daher ist die Ausgabe unsortiert. Leite sie durch sort, wenn du eine Sortierung benötigst.
  • Umfang. Optionen, die das vollständige Ergebnisset benötigen, werden vorab abgelehnt (mit einer Meldung, die jede einzelne benennt): --merge-endpoint, --dedup-similar, --check-status / --include-status / --exclude-status, --extract-links, --extract-js-endpoints, --archive-body, --expand-specs, --incremental, --show-sources, --show-meta, die --meta-*-Filter, --params, --params-by-endpoint, --fuzz-placeholder, --output-dir und --files. Caching wird umgangen; --format json wird zugunsten von jsonl abgelehnt, weil ein JSON-Array wissen muss, welcher Eintrag der letzte ist, und --format wordlist, weil kein Begriff als neu bekannt sein kann, bis jede URL eingetroffen ist.

Da die Batch-Ergebnismap in diesem Modus nie befüllt wird, hält ein gestreamter Lauf auch deutlich weniger im Speicher — nur das Dedup-Set der bereits geschriebenen URLs.

Archiv-Capture-Metadaten

Ein CDX-Index zeichnet mehr als die URL auf: Jeder Capture trägt einen Zeitstempel, den MIME-Typ und HTTP-Status, den das Archiv gesehen hat, sowie einen Digest des Bodys. urx behält all das, sodass die CDX-gestützten Provider — wayback, cc, arquivo und jedes --cdx-endpoint — jede URL zusammen mit Folgendem melden:

FeldBedeutung
first_seenÄltester Capture-Zeitstempel, 14-stellige CDX-Form (YYYYMMDDhhmmss)
last_seenNeuester Capture-Zeitstempel
mimeMIME-Typ des jüngsten Captures, der einen aufgezeichnet hat
archive_statusHTTP-Status, den das Archiv zum Zeitpunkt des Captures aufgezeichnet hat
digestEin repräsentativer Inhalts-Digest über die Captures hinweg

archive_status ist nicht status: status erscheint nur unter --check-status, was die URL jetzt live erneut anfragt, wohingegen archive_status das ist, was der Crawler erhielt, als er die Seite erfasste. Eine URL kann durchaus archive_status 200 sein und heute tot sein.

Wenn dieselbe URL aus mehreren Captures oder mehreren Archiven stammt, werden die Werte zusammengeführt: first_seen ist der älteste Zeitstempel, den jemand gemeldet hat, last_seen der neueste, und mime/archive_status stammen aus dem jüngsten Capture, der sie hatte. Provider ohne Capture-Index (otx, vt, urlscan, zoomeye, github, bevigil, robots, sitemap und --files-Eingabe) melden nur die URL — für sie werden keine Werte erfunden.

Wie die Metadaten an die Oberfläche gelangen, hängt vom Format ab:

  • json / jsonl — jedes Feld erscheint als Schlüssel, wenn es einen Wert hat, und wird vollständig weggelassen, wenn nicht, genau wie sources.
  • csv — eine Spalte wird nur hinzugefügt, wenn mindestens eine Zeile einen Wert dafür hat, sodass ein Lauf ohne Metadaten weiterhin eine einzelne url-Spalte erzeugt.
  • Klartext — standardmäßig unverändert, eine bloße URL pro Zeile, sodass bestehende Pipelines weiter funktionieren. Übergib --show-meta, um die Felder anzuhängen.```bash

Rich records: when the URL was alive, and what it served

urx example.com --providers wayback -f jsonl

{"url":"https://example.com/old.php","first_seen":"20040112093000",

"last_seen":"20180722140311","mime":"text/html","archive_status":"200",

"digest":"HT2DYGA5UKZCPBSFVCV3JOBXGW2G5UUA"}

Triage by age: everything last captured before 2010

urx example.com -f jsonl | jq -r 'select(.last_seen < "20100101000000") | .url'

Opt plain output into the metadata

urx example.com --providers wayback --show-meta

Streaming (`--stream`) meldet nur URLs. Eine URL wird beim ersten Auftreten ausgegeben,
bevor die Captures eintreffen, die ihren `first_seen`/`last_seen`-Bereich erweitern würden,
daher wird `--show-meta` dort aus demselben Grund abgelehnt wie
`--show-sources`.

Ein Cache-Treffer trägt ebenfalls keine Metadaten: Der Cache speichert URLs, sodass eine Domain,
die aus dem Cache bedient wird, ihre URLs ohne Capture-Felder meldet. Verwenden Sie `--no-cache` (oder warten Sie
auf die TTL) für einen Lauf, der sie neu befüllt.

### Live-Response-Metadaten

`--check-status` sendet bereits eine Anfrage und wartet auf den Response-Head, sodass
das, was dieser Head trägt, kostenlos mitgeliefert wird: `Location`, `Content-Length` und
`Content-Type` werden zusammen mit dem Statuscode aufgezeichnet. Redirects werden weiterhin nie
verfolgt, sodass ein gemeldeter Status immer zu der URL gehört, die angefragt wurde, und
`location` einfach angibt, wohin der 3xx zeigte.

`--check-title` fügt den HTML-`<title>` hinzu. Es ist das einzige Feld, das nicht kostenlos ist –
ein Titel benötigt den Response-Body –, daher steht es hinter seinem eigenen Flag. Das Lesen wird
zweifach begrenzt (höchstens 64 KiB, und es stoppt am schließenden Tag) und für einen Body, den der
Server als Nicht-HTML deklariert hat, vollständig übersprungen, sodass eine JSON-API oder ein Bild
nichts kostet. Der Titel wird auf Leerraum reduziert, Entity-dekodiert und auf 200
Zeichen gekürzt. `--check-title` impliziert `--check-status`.```bash
urx example.com --check-status -f jsonl
urx example.com --check-title --show-meta
urx example.com --check-status --is 30x -f jsonl | jq -r '.url + " -> " + .location'

Die Offenlegung folgt der Regel, die die Archiv-Metadaten bereits festgelegt haben: json/jsonl/csv enthalten immer die Felder (fehlende Schlüssel werden weggelassen, und die CSV-Spalten werden nach den vorhandenen angehängt), während reiner Text eine bloße URL pro Zeile bleibt, es sei denn, --show-meta verlangt etwas anderes. In der reinen Textausgabe wird der Titel in Anführungszeichen gesetzt, da er der eine Wert ist, der regelmäßig Leerzeichen enthält.

Authentifizierte und benutzerdefinierte Anfragen

--check-status, --extract-links, --extract-js-endpoints und --expand-specs fordern alle gesammelten URLs erneut vom Ziel selbst an. -H gibt diesen Anfragen die Header, die sie benötigen:```bash urx example.com --check-status -H "Authorization: Bearer $TOKEN" urx example.com --extract-links --cookie "session=abc; role=admin" urx example.com --check-status --user-agent "acme-security-scan/1.0"

`-H` ist wiederholbar, nimmt `Name: value` entgegen, und ein fehlerhaftes beendet den Lauf,
anstatt unbemerkt hinauszugehen — ein Argument, das stillschweigend verworfen wird, lässt
einen anonymen Scan als authentifizierten erscheinen. `--cookie` und
`--user-agent` sind Kurzformen für die entsprechenden Header.

**Diese Header erreichen niemals ein Archiv.** Sie werden nur von den Komponenten
gesendet, die mit dem Ziel kommunizieren: den vier oben genannten Testern sowie den
`robots`- und `sitemap`-Providern, die ebenfalls vom Ziel abrufen. Jeder andere Provider
fragt web.archive.org, index.commoncrawl.org oder eine Drittanbieter-API ab, und
`--archive-body` tut dies ebenfalls, wenn es eine Aufzeichnung wiedergibt; ihnen das
Session-Cookie des Ziels zu übergeben, würde eine Anmeldeinformation an einen Dienst
senden, der behält, was er empfängt, ohne Nutzen. Archivabfragen behalten urx' eigenen
User-Agent, den `--random-agent` weiterhin rotiert.

### Archivierte Antwort-Bodies durchsuchen

`--extract-links` ruft jede gesammelte URL von der Live-Seite ab, was genau der
falsche Ort ist, um nach den Seiten zu suchen, die bei einem OSINT-Sweep am meisten
zählen: diejenigen, die nicht mehr existieren. `--archive-body` ruft stattdessen die
Bodies ab, die die Wayback Machine gespeichert hat. Für jede gesammelte URL, die einen
Aufzeichnungs-Zeitstempel trägt, gibt urx diese Aufzeichnung in ihrer Rohform wieder
(`https://web.archive.org/web/<timestamp>id_/<url>` — das `id_`-Flag schaltet die
Wayback-Toolbar und die Link-Umschreibung ab, sodass der Body die Originalbytes sind) und
führt dieselbe Link-Extraktion darauf aus, die `--extract-links` verwendet.```bash
# Links from the archived bodies of everything the CDX providers found
urx example.com --archive-body

# Bound the run and pace it; the archive is one host no matter how many URLs
urx example.com --archive-body --archive-body-limit 200 --rate-limit 5

# Only the JavaScript those pages referenced back then
urx example.com --archive-body -e js

Warum dies weit weniger Anfragen als waymore erfordert. Jede CDX-Zeile trägt einen Content-Digest, und zwei Captures mit demselben Digest sind byte-für-byte derselbe Body. Archive sind voll davon: jede ?utm_source=-Variante einer Seite, jede /index.html neben ihrem /, jede Tracking-Parameter-Permutation liefert identische Bytes, sodass eine Liste mit Zehntausenden von URLs routinemäßig auf ein paar Tausend verschiedene Bodies kollabiert. waymore hat keine Vorstellung davon — es lädt eine Antwort pro URL herunter und bewältigt das Volumen durch eine stumpfe -l 5000-Obergrenze, die sowohl das Archiv belastet als auch die Abdeckung abschneidet. urx beansprucht jeden Digest beim ersten Auftreten und überspringt jede spätere URL, die dieselben Bytes wiedergeben würde, sodass dieselbe Abdeckung eine Anfrage pro verschiedenem Body kostet. --archive-body-limit (Standard 500) begrenzt verschiedene Bodies, nicht URLs; Duplikate zählen nie dagegen, und --verbose berichtet, wie viele übersprungen wurden.

Archiviertes JavaScript abbauen. Die API-Oberfläche einer modernen App lebt in ihren Bundles als String-Literale, und --extract-js-endpoints holt diese von der Live- Seite — wo sie häufig nicht mehr existieren. Bundles werden nach Build-Hash benannt, sodass app.a3f9c2.js in dem Moment 404 liefert, in dem die Seite neu deployt wird, und die Endpunkte, die es nannte, verschwinden mit ihm. Führe die beiden Flags zusammen aus und urx baut stattdessen die archivierte Kopie ab, und die Inline-<script>-Blöcke einer archivierten Seite zusammen mit ihren Links:```bash urx example.com --archive-body --extract-js-endpoints

**Die Bodies behalten.** Die Anfragen werden ohnehin bereits gestellt, sodass das Schreiben der Bodies auf die Festplatte nichts zusätzlich kostet und die Fragen beantwortet, die kein Link-Extraktor stellt: der `<!-- staging.internal -->`-Kommentar, das Token, das ein Build von 2019 inline eingebettet hat, der Stack-Trace, der eine Framework-Version nennt.```bash
urx example.com --archive-body --archive-body-dir ./corpus
grep -ri "api[_-]key" ./corpus

Jede Datei ist nach ihrer URL plus einem Hash davon benannt, und corpus/index.jsonl ordnet jede Datei ihrer URL, dem Aufnahmezeitpunkt, dem Digest und dem Inhaltstyp zu. Nur textähnliche Inhalte werden gespeichert — HTML, Skript, JSON, XML, CSS, reiner Text — damit das Verzeichnis nicht mit den Bildern und Schriftarten der Website vollläuft. Da der Abruf nach Digest dedupliziert wird, deckt das Korpus pro Anfrage weit mehr des Ziels ab, als es eine Antwort pro URL tun würde.

Wissenswerte Details:

  • Nur URLs mit einem Aufnahmezeitpunkt qualifizieren sich. Die CDX-Anbieter (wayback, cc, arquivo) liefern einen; --files-Eingabe, Nicht-CDX-Anbieter und zwischengespeicherte Ergebnisse (der Cache speichert nur URLs) haben keinen. urx sagt es, wenn es nichts zum Wiedergeben gibt — übergib --no-cache, um frische Aufnahmen zu erhalten.
  • Die neueste Aufnahme jeder URL wird wiedergegeben. Ein von einem anderen Archiv gemeldeter Zeitstempel landet auf der nächstgelegenen Wayback-Aufnahme; eine URL, die die Wayback Machine nie gesehen hat, antwortet mit 404 und wird übersprungen. Aufnahmen, die das Archiv als Fehler verzeichnet hat, werden nicht ausgewertet, genau wie --extract-links Live-Fehlerseiten ignoriert.
  • Entdeckte Links durchlaufen dieselben Filter, Host-Validierung und Ausgabe-Transformationen wie alles andere, und jeder Inhalt ist auf 10 MiB begrenzt.
  • --rate-limit, --rate-limit-by wayback=N, --parallel, --proxy, --timeout und --retries gelten alle für die Wiedergabeanfragen.
  • Inkompatibel mit --stream, wie jede Option, die nach der Sammlung ausgeführt wird.

Erweitern von API-Spezifikationen

Ein -p only-api-Durchlauf findet /swagger.json, /openapi.yaml und /v3/api-docs und öffnet sie dann nie: --extract-links parst HTML, --extract-js-endpoints verwirft application/json-Inhalte, und --archive-body führt den HTML-Parser über das aus, was das Archiv zurückgibt. --expand-specs liest sie und erweitert jede Route, die sie beschreiben, in die Ergebnismenge — eine Anfrage kauft die gesamte dokumentierte Oberfläche, exakt und bereits parametrisiert.```bash urx example.com -p only-api --expand-specs urx example.com --expand-specs --max-spec-files 10 --rate-limit 2

Recover an API the live host no longer serves: read the archived document

urx example.com --archive-body --expand-specs

Was erweitert wird:

* **OpenAPI 3.x** — `servers[].url` (absolut, dokumentrelativ und templatisiert,
  wobei `{var}` aus `variables[var].default` oder dem ersten `enum`-Wert
  aufgelöst wird) gekreuzt mit jedem `paths`-Schlüssel; die eigenen `servers`
  eines Path Items überschreiben die des Dokuments.
* **Swagger 2.0** — `schemes` × `host` + `basePath`, wobei jeder Teil auf den
  entsprechenden Teil der URL des Dokuments selbst zurückfällt. `ws`/`wss`
  werden verworfen.
* **GraphQL-Introspektion** — eine URL pro Query-, Mutation- und
  Subscription-Feld, geschrieben als der Endpunkt plus `?query=…`. Ein als
  Datei gespeichertes Schema wird zu seinem Endpunkt aufgelöst
  (`/graphql/schema.json` → `/graphql`).

JSON und YAML werden beide gelesen. Ziele werden zuerst nach Namen und
kostenlos gewählt (ein Spec-Marker-Substring — `swagger`, `openapi`,
`api-docs`, `graphql`, `introspection` — plus eine `json`/`yaml`/`yml`-Erweiterung,
falls vorhanden, sodass `swagger-ui.html` keine Anfrage kostet), dann nach dem
`Content-Type` der Antwort. Pfadtemplates werden so ausgegeben, wie das Dokument
sie schreibt (`/users/{id}`, nicht `/users/%7Bid%7D`). Bodies sind auf 10 MiB
begrenzt, und ein YAML-Dokument mit mehr als 32 Alias-Referenzen wird vor dem
Parsen abgelehnt, um Expansion Bombs auszuschließen. `--max-spec-files`
(Standard 50) begrenzt die abgerufenen Dokumente. Mit ebenfalls aktiviertem
`--archive-body` wird eine archivierte Spezifikation ohne zusätzliche
Anfragekosten als eine gelesen — der Body wurde ohnehin bereits abgerufen.

### Archivierte robots.txt und sitemap.xml

Die Provider `robots` und `sitemap` lesen die *Live*-Dateien, die nur aussagen,
was eine Website heute verbirgt oder auflistet. `--archived-discovery` liest
zusätzlich jede unterschiedliche Version dieser Dateien, die die Wayback Machine
gespeichert hat. Ein `Disallow:` aus dem Jahr 2015 benennt Pfade, die die Website
seither nicht mehr erwähnt — oft, weil sie vergessen werden sollten, nicht weil
sie verschwunden sind — und eine alte Sitemap listet alles auf, was die Website
einst gecrawlt haben wollte.```bash
# Every archived version of robots.txt and sitemap.xml, alongside the live ones
urx example.com --archived-discovery

# Bound it and pace it; both archived providers answer to --rate-limit-by
urx example.com --archived-discovery --archived-discovery-limit 20 --rate-limit-by robots=2,sitemap=2

# Only the versions captured in a given era
urx example.com --archived-discovery --from 2014 --to 2016

So funktioniert es und warum es günstig ist:

  • Die Versionen eines Dokuments werden mit einer CDX-Abfrage pro Datei aufgelistet (robots.txt, sitemap.xml, sitemap_index.xml, sitemap.txt), wobei collapse=digest verwendet wird, sodass aufeinanderfolgende Captures, die dieselben Bytes ausgeliefert haben, zu einer Zeile zusammengefasst werden. Es werden nur Zeilen abgefragt, die als Erfolg verzeichnet sind: Der Index fasst www. und die Apex-Domain zu einem Eintrag zusammen, und ihre verschachtelten 301/200-Zeilen würden andernfalls das Collapse vereiteln — für github.com/robots.txt sind das 325k Zeilen ohne den Filter und 14k mit ihm, für dieselben 107 verschiedenen Versionen.
  • Jede verschiedene Version wird in Rohform (/web/<timestamp>id_/…) wiedergegeben und dem selben Parser wie die Live-Datei übergeben. Kein zweiter Parser: Eine robots.txt von 2015 wird nach genau denselben Regeln gelesen wie die aktuelle, einschließlich der Guards für absolute Pfade und übersprungene Muster. Ein archivierter <sitemapindex> wird in seine Kindelemente verfolgt, wie sie zu jenem Zeitpunkt waren.
  • Captures, die das Archiv als Fehler verzeichnet hat (github.coms robots.txt war einen Teil des Jahres 2007 über ein 401), werden ohne Anfrage übersprungen und nur unter --verbose gemeldet.
  • --archived-discovery-limit (Standard 50) begrenzt die pro Domain von jedem archivierten Provider abgerufenen Dokumente, neueste Versionen zuerst; verschachtelte Sitemaps zählen mit. --verbose gibt an, wann das Limit die Liste verkürzt hat.
  • Die archivierten Varianten laufen als eigene Provider-Instanzen — „Robots.txt (archived)" und „Sitemap (archived)" in --stats und --show-sources — aber unter den bestehenden IDs robots / sitemap, sodass --exclude-robots, --exclude-sitemap und --rate-limit-by robots=N sowohl die Live- als auch die archivierten Lesevorgänge steuern. --from / --to schränken ein, welche Versionen berücksichtigt werden.
  • Funktioniert mit --stream; es ist ein Provider wie jeder andere.

Filterung auf der Archivseite

--archive-status, --archive-mime, --from und --to werden vom CDX-Index des Archivs ausgewertet und nicht von urx. Zwei Konsequenzen sind wissenswert:

  • Sie gelten nur für CDX-gestützte Provider — wayback, cc, arquivo und jedes --cdx-endpoint. Andere Provider ignorieren sie; urx warnt, wenn keiner aktiviert ist.
  • Die Archive teilen sich nicht einen Filterdialekt. Wayback Machine (und jeder --cdx-dialect classic-Endpunkt) behandelt Werte als reguläre Ausdrücke, sodass --archive-status "30." auf jedes 3xx passt. Common Crawl, Arquivo.pt und pywb-Endpunkte stimmen exakt überein, und ihr Index verknüpft wiederholte Filter mit AND — eine mehrwertige Positivliste wie --archive-status 200,301 ist dort also unerfüllbar. urx überspringt diesen Filter für jene Provider (mit einer Warnung), anstatt eine Abfrage zu senden, die leer zurückkäme. Mehrwertige Ausschlüsse bedeuten „nicht dies und nicht das" und funktionieren überall.

Verwenden Sie --archive-status, wenn Sie das wollen, was das Archiv zum Crawl-Zeitpunkt verzeichnet hat, und --check-status / --include-status, wenn Sie den Status des Ziels jetzt wollen; Letzteres fragt jede URL erneut ab.

Benutzerdefinierte CDX-Endpunkte

Jedes Webarchiv, das auf pywb, OutbackCDX oder dem CDX-Server des Internet Archive aufbaut, stellt dieselbe Abfrage-API bereit. Anstatt einen Provider pro Archiv fest zu codieren, macht --cdx-endpoint URL jeden solchen Server sofort zu einem Provider:```bash

The Icelandic web archive, alongside the default providers

urx example.is --cdx-endpoint https://vefsafn.is/cdx

Several at once; each gets its own progress line, stats row and rate limit

urx example.com --cdx-endpoint https://vefsafn.is/cdx --cdx-endpoint http://localhost:8080/cdx
--rate-limit-by cdx:vefsafn.is=1

* Die Provider-ID ist `cdx:<host>` (`cdx:vefsafn.is`), die von
  `--exclude-providers`, `--rate-limit-by`, `--stats` und `--show-sources` verwendet wird.
  Das Benennen eines Endpunkts aktiviert ihn; es ist kein `--providers`-Eintrag erforderlich, und
  `--providers cdx:vefsafn.is` führt ihn allein aus. `--list-providers` zeigt die
  Endpunkte an, die in derselben Befehlszeile benannt sind, mit den IDs, unter denen sie ausgeführt werden.
* Alles, was die integrierten CDX-Provider berücksichtigen, gilt auch hier: `--subs`,
  `--from`/`--to`, die `--archive-*`-Filter, Paginierung, `--rate-limit` und
  die oben beschriebenen Capture-Metadaten.
* `--cdx-dialect classic|pywb` benennt den Dialekt des Servers (Feldnamen, Filter-
  Semantik, Zeilenformat und Paginierungsschema folgen alle daraus — siehe
  „Archive-side Filtering"). Bleibt es ungesetzt, sondiert urx den Endpunkt einmal pro Lauf
  und fällt auf `pywb` zurück, den häufigeren Dialekt; setzen Sie es explizit, wenn die
  Sondierung es nicht erkennen kann (z. B. eine leere Antwort für eine unbekannte Domain).
* Kann auch in der Konfigurationsdatei gesetzt werden (`cdx_endpoint = [...]`, `cdx_dialect`).

**Verifizierte Endpunkte.** Zum Zeitpunkt dieses Schreibens ist der einzige öffentliche Endpunkt, der
bestätigt von Anfang bis Ende funktioniert, `https://vefsafn.is/cdx` (Landsbókasafns isländisches Web-
Archiv, pywb-Dialekt). Zwei Dinge sind darüber zu wissen: Er ignoriert `limit`, `page`
und `showNumPages` und gibt für jede Abfrage die vollständige Ergebnismenge zurück, was
urx handhabt; und nach einer Handvoll Anfragen kann er beginnen, mit einer
Bot-Schutzseite im Anubis-Stil zu antworten („Session Verification"). urx erkennt eine HTML-
Antwort anstelle von CDX-Zeilen und meldet sie als Provider-Fehler unter Nennung des
Endpunkts — sie wird niemals als „no URLs" gezählt. Wenn Sie darauf stoßen, verlangsamen Sie mit
`--rate-limit-by cdx:vefsafn.is=1` oder versuchen Sie es später erneut.

**Bekanntlich nicht funktionierend.** Das UK Web Archive (`webarchive.org.uk`), das Webarchiv der Library of
Congress (`webarchive.loc.gov`), die Bibliotheca Alexandrina und die
National Library of Australia (`web.archive.org.au`) befinden sich alle hinter Bot-
Schutz oder Weiterleitungen, die ihre CDX-APIs von einem Kommandozeilen-Client aus blockieren.
urx versucht nicht, das zu umgehen, sodass das Richten von `--cdx-endpoint` auf sie den
oben genannten HTML-Antwort-Fehler ergibt.

### Caching und inkrementelles Scannen

Urx unterstützt Caching, um die Leistung bei wiederholten Scans zu verbessern, sowie inkrementelles Scannen, um nur neue URLs zu entdecken.```bash
# Enable caching with SQLite (default)
urx example.com --cache-type sqlite --cache-path ~/.urx/cache.db

# Use Redis for distributed caching
urx example.com --cache-type redis --redis-url redis://localhost:6379

# Incremental scanning - only show new URLs since last scan
urx example.com --incremental

# Set cache TTL (time-to-live) to 12 hours
urx example.com --cache-ttl 43200

# Disable caching entirely
urx example.com --no-cache

# Combine incremental scanning with filters
urx example.com --incremental -e js,php --patterns api

# Configuration file with caching settings
urx -c example/config.toml example.com

Cache-Verwaltung

urx cache untersucht und pflegt den Cache, ohne die Datenbank von Hand anzufassen. Jeder Unterbefehl berücksichtigt dieselben --cache-type, --cache-path, --redis-url und --cache-ttl wie ein Scan, und alle fünf funktionieren mit beiden Backends.```bash urx cache stats # entries, domains, URLs, age span, size, expired count urx cache list # per-domain counts, last scan, TTL remaining urx cache list --domain '*.example.com' urx cache prune # delete only what --cache-ttl has expired urx cache drop example.com # rescan one target without clearing the rest urx cache clear --yes # delete everything

machine-readable

urx cache stats -f json | jq '.expired_entries'

Domain-Abgleich ist unabhängig von Groß-/Kleinschreibung und **exakt**, es sei denn, das Muster enthält
`*` — ein Teilstring-Standard hätte zugelassen, dass `drop example.com` auch
`notexample.com` entfernt. `clear` fragt vor dem Löschen nach und verweigert
eine nicht-interaktive stdin, anstatt eine Antwort anzunehmen, `drop` benennt jedes Muster,
das nichts getroffen hat, das Betrachten des Caches erstellt nie einen, und Redis wird
mit `SCAN` durchsucht statt mit dem blockierenden `KEYS` (wobei jedes Passwort in `--redis-url`
vor der Ausgabe redigiert wird).

#### Caching-Anwendungsfälle```bash
# Daily monitoring - only alert on new URLs (built-in webhook, see below)
urx target.com --incremental --silent --notify https://hooks.slack.com/services/... --notify-format slack

# ...or hand the new URLs to an external notifier
urx target.com --incremental --silent | notify-tool

# Efficient domain lists processing
cat domains.txt | urx --incremental --cache-ttl 3600 > new_urls.txt

# Distributed team scanning with Redis
urx example.com --cache-type redis --redis-url redis://shared-cache:6379

# Fast re-scans during development
urx test-domain.com --cache-ttl 300  # 5-minute cache for rapid iterations

Webhook-Benachrichtigungen

--notify <URL> sendet eine Zusammenfassung des Durchlaufs per POST an einen Webhook, wenn der Durchlauf endet, wodurch --incremental zu einem Monitor wird: In cron eingetragen, wird der Webhook nur ausgelöst, wenn etwas Neues auftaucht.```bash

Slack incoming webhook, only when the run finds new URLs (the default)

urx target.com --incremental --silent
--notify https://hooks.slack.com/services/T000/B000/XXXX --notify-format slack

Discord, and send even when nothing is new

urx target.com --incremental --notify "$DISCORD_HOOK" --notify-format discord --notify-on always

Several receivers, urx's own JSON schema (the default format)

urx target.com --incremental --notify https://n8n.example/hook --notify https://ntfy.example/urx

Keep the webhook out of the shell history

export URX_NOTIFY_URL=https://hooks.slack.com/services/... urx target.com --incremental --notify-format slack

- `--notify-on` ist standardmäßig `new`: Es wird nichts gesendet, wenn der Lauf null
  URLs ausgibt, sodass ein ruhiger Cron-Lauf ruhig bleibt. `always` sendet unabhängig davon; `never`
  behält die Konfiguration bei, deaktiviert aber das Senden.
- `--notify-format json` (Standard) sendet das Schema von urx: `domains`,
  `incremental`, `url_count`, `new_url_count`, `elapsed_ms`, eine `providers`-Liste
  pro Provider (dieselben Zahlen, die `--stats` ausgibt), und ein `sample` von bis zu
  20 ausgegebenen URLs mit gesetztem `sample_truncated`, wenn mehr gefunden wurden.
  `slack` sendet `{"text": ...}` und `discord` sendet `{"content": ...}` mit einer
  kurzen, für Menschen lesbaren Nachricht; Nachrichten, die länger sind als der Dienst erlaubt, werden
  an einer Zeilengrenze abgeschnitten und enden mit `[truncated: N lines cut ...]`.
- Die Zustellung ändert niemals den Exit-Code. Die URLs stehen bereits auf stdout oder in
  `--output`, wenn der Webhook aufgerufen wird, sodass ein toter Webhook eine Warnung
  auf stderr ist und der Lauf trotzdem mit 0 endet. `--verbose` zeigt den Antwortstatus.
- Die Webhook-URL ist ein Credential. urx gibt niemals mehr als ihr Schema und
  ihren Host aus — nicht in `--verbose`, nicht in Warnungen, nicht in `--stats`. Um sie aus
  einer eingecheckten Konfiguration herauszuhalten, lege sie in `URX_NOTIFY_URL` oder als
  `notify_url` in der Provider-Konfigurationsdatei ab; `[notify].url` in der Hauptkonfiguration
  funktioniert ebenfalls. Die Priorität ist CLI/Env > Provider-Konfiguration > Hauptkonfiguration.
- Die Anfrage berücksichtigt `--proxy`, `--proxy-auth`, `--timeout` und `--insecure`.
  `--network-scope` gilt nicht: Es partitioniert den Verkehr, der auf das Ziel
  und die Archive gerichtet ist, und der Webhook ist dein eigener Endpunkt.
- `--silent` sendet trotzdem (das ist der Hauptanwendungsfall); es verbirgt nur die
  Diagnosen.

## Integration mit anderen Tools

Urx funktioniert gut in Pipelines mit anderen Sicherheits- und Reconnaissance-Tools:```bash
# Find domains, then discover URLs
echo "example.com" | urx | grep "login" > potential_targets.txt

# Combine with other tools
cat domains.txt | urx --patterns api | other-tool

Inspiration

Urx wurde von gau (GetAllUrls) inspiriert, einem Tool, das bekannte URLs von AlienVaults Open Threat Exchange, der Wayback Machine und Common Crawl abruft. Obwohl es ähnliche Kernfunktionen bietet, wurde Urx von Grund auf in Rust entwickelt, mit Fokus auf Leistung, Nebenläufigkeit und erweiterte Filterfunktionen.

Mitwirken

Urx ist ein Open-Source-Projekt und wurde mit ❤️ erstellt. Wenn du zu diesem Projekt beitragen möchtest, lies bitte CONTRIBUTING.md und reiche einen Pull-Request mit deinen coolen Inhalten ein.

Kategorien