Retour aux mises à jour
New releaseSep 19, 2026

urx v0.11.0

Extrait des URL d'archives OSINT pour des informations de sécurité

Partager
Urx Logo

Extrait les URL des archives OSINT pour des analyses de sécurité.

Urx est un outil en ligne de commande conçu pour collecter des URL à partir d'archives OSINT, telles que la Wayback Machine et Common Crawl. Développé en Rust pour plus d'efficacité, il exploite le traitement asynchrone pour interroger rapidement de multiples sources de données. Cet outil simplifie le processus de collecte d'informations sur les URL pour un domaine donné, en fournissant un jeu de données complet pouvant servir à diverses fins, notamment les tests et l'analyse de sécurité.

Fonctionnalités

  • Récupérer des URL depuis plusieurs sources en parallèle (Wayback Machine, Common Crawl, OTX, Arquivo.pt)
  • Brancher n'importe quel autre serveur d'index CDX — archives web nationales, pywb privé, OutbackCDX — avec --cdx-endpoint URL, sans modification de code
  • Sans clé par défaut : Wayback, Common Crawl, OTX, Arquivo.pt et URLScan (anonyme) fonctionnent tous sans clé API
  • Fournisseur BeVigil : URL extraites d'applications Android décompressées — des endpoints qu'aucune archive web n'a jamais explorés
  • Prise en charge de la rotation des clés API pour les fournisseurs VirusTotal et URLScan afin d'atténuer les limites de débit
  • Tests authentifiés : -H, --cookie et --user-agent s'appliquent à chaque requête qu'urx envoie à la cible (--check-status, --extract-links, --extract-js-endpoints, --expand-specs) et ne sont délibérément jamais envoyés à une archive
  • Filtrer les résultats par extensions de fichiers, motifs de sous-chaînes ou expressions régulières complètes (--match-regex / --filter-regex)
  • Préréglages prédéfinis, à la fois par famille de fichiers (« no-images », « only-js ») et par intérêt de sécurité (« only-secrets », « only-backup », « only-config », « only-api »)
  • Filtrage côté archive : pousser le code de statut, le type MIME et la plage de dates directement dans la requête CDX elle-même, afin que les captures filtrées ne traversent jamais le réseau
  • Filtrage des métadonnées côté client (--meta-*) : filtrer sur la date de première/dernière capture, le type MIME enregistré et le statut enregistré, uniformément sur tous les fournisseurs, après collecte
  • Cibles limitées à un chemin : urx example.com/shop pousse la portée directement dans la requête CDX (url=example.com/shop*), de sorte qu'un sous-arbre d'un grand site coûte une fraction de l'index entier au lieu d'être filtré côté client
  • Fichiers de portée bug-bounty (--scope-file) : la propre liste *.example.com / !admin.example.com d'un programme utilisée telle quelle, répétable et unie, les exclusions l'emportant toujours
  • Normalisation et déduplication des URL : trier les paramètres de requête, supprimer les barres obliques finales, fusionner les URL sémantiquement identiques et regrouper les quasi-doublons qui ne diffèrent que par des identifiants, des hachages ou des dates (--dedup-similar)
  • Prise en charge de plusieurs formats de sortie : texte brut, JSON, JSON Lines, CSV et wordlist — les segments de chemin et les noms de paramètres à partir desquels la cible est construite, en omettant les identifiants, les hachages et les dates
  • Vues paramètres et fuzz : --params (l'inventaire complet des paramètres de la cible), --params-by-endpoint (quel endpoint accepte quoi) et --fuzz-placeholder FUZZ (une URL modélisée par signature de paramètre, prête pour ffuf ou dalfox)
  • Métadonnées de capture d'archive : first_seen, last_seen, mime, archive_status et digest sont renvoyés avec chaque URL signalée par une archive CDX, sans coût réseau supplémentaire
  • Sortie en flux (--stream) : les URL sont écrites au fur et à mesure que chaque fournisseur les signale, de sorte qu'un pipeline commence à fonctionner immédiatement au lieu d'attendre l'archive la plus lente
  • Prise en charge de l'entrée directe de fichiers : lire les URL directement depuis des fichiers WARC, des fichiers compressés URLTeam et des fichiers texte
  • Sortir les résultats vers la console ou un fichier, ou diffuser via stdin pour l'intégration dans un pipeline
  • Test d'URL :
    • Filtrer et valider les URL en fonction des codes de statut HTTP et des motifs.
    • Extraire des liens supplémentaires à partir des URL collectées — ancres, scripts, feuilles de style, actions de formulaires, iframes, images, sources multimédias, objets, intégrations et cibles meta-refresh
    • Explorer les corps de réponse archivés des URL collectées (--archive-body), afin que les pages qui n'existent plus livrent encore les liens qu'elles contenaient — une requête par corps distinct, grâce à la déduplication par digest CDX
    • Avec --extract-js-endpoints, explorer aussi le JavaScript archivé : un bundle nommé par un hachage de build renvoie un 404 dès que le site est redéployé, et l'archive est le seul endroit où sa surface d'API existe encore
    • Conserver les corps rejoués (--archive-body-dir) comme corpus à fouiller pour ce qu'aucun extracteur de liens ne recherche — commentaires de développeurs, identifiants en ligne, noms d'hôtes internes — sans requêtes supplémentaires
    • Développer les spécifications d'API (--expand-specs) : documents OpenAPI 3.x, Swagger 2.0 et introspection GraphQL, JSON ou YAML, transformés en chaque route qu'ils décrivent — une requête achète toute la surface documentée
    • Métadonnées de réponse : --check-status enregistre aussi Location, Content-Length et Content-Type, et --check-title ajoute le <title> HTML
  • Découverte de robots.txt et sitemap.xml archivés (--archived-discovery) : chaque version distincte conservée par la Wayback Machine, de sorte qu'un Disallow: de 2015 nomme encore les chemins que le site a cessé de mentionner depuis
  • Mise en cache et analyse incrémentale :
    • Mise en cache locale SQLite ou distante Redis pour éviter de rescanner les domaines
    • Mode incrémental pour ne découvrir que les nouvelles URL depuis la dernière analyse
    • TTL de cache configurable et nettoyage automatique des entrées expirées
    • Sous-commande urx cache pour inspecter et maintenir le cache : stats, list, prune, drop <domain>, clear

Preview

Installation

Depuis Cargo```bash

https://crates.io/crates/urx

cargo install urx

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

Depuis la source```bash

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

Le binaire compilé sera disponible à l'emplacement `target/release/urx`.

### Depuis Docker

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

### Complétions Shell

`urx` génère son propre script de complétion, ce qui garantit qu'il correspond toujours aux options du binaire que vous avez réellement installé.```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 et elvish sont également pris en charge. Le flag n'a pas besoin de domaine cible.

Page de manuel```bash

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

## Utilisation

### Utilisation de base```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

Options```

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` lit chaque balise porteuse d'URL, pas seulement les ancres : `<a href>`,
`<script src>`, `<link href>`, `<form action>`, ``, ``,
`<source src>`, `<object data>`, `<embed src>`, et les cibles `<meta http-equiv="refresh">`.
Les URL relatives sont résolues par rapport à la page (en respectant `<base href>`),
les doublons sont fusionnés, et les liens découverts passent par les mêmes filtres
et la même validation d'hôte que le reste de l'exécution. Voir
[docs/content/guide/cli-options.md](https://github.com/hahwul/urx/blob/main/docs/content/guide/cli-options.md) pour le
tableau complet.

`--extract-js-endpoints` va plus loin et lit le JavaScript
lui-même : chaque URL collectée qui ressemble à un script est récupérée et ses
littéraux de chaîne sont exploités pour les chemins et URL que l'application appelle —
`fetch("/api/v2/users")`, `axios.post("/graphql")`, le préfixe statique de
`` `/api/orders/${id}` ``. Ce sont les endpoints qui n'apparaissent jamais dans le HTML.
La sortie est agressivement dé-bruitée (types MIME, spécificateurs de module, base64,
valeurs CSS, fragments de regex et plus encore sont supprimés), chaque corps est plafonné à
10 MiB, le nombre de fichiers récupérés est limité par `--max-js-files`, et les
endpoints découverts passent par les mêmes filtres et la même validation d'hôte que tout le
reste. La politique complète d'extraction et de suppression du bruit se trouve dans
[docs/content/guide/cli-options.md](https://github.com/hahwul/urx/blob/main/docs/content/guide/cli-options.md#javascript-endpoint-extraction).

`--archive-body` effectue la même extraction sur les corps que la Wayback Machine
*a stockés* plutôt que sur le site en direct, de sorte qu'une page supprimée il y a des années
fournit encore les liens qu'elle contenait. Voir
[Mining Archived Response Bodies](#mining-archived-response-bodies).

### Exemples```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

Délimiter une exécution à un chemin

Une cible peut désigner un chemin, et cela signifie ce qu'il dit : urx example.com/shop collecte la partie du site sous /shop.```bash urx example.com/shop urx https://example.com/api/v2 # a pasted URL works too

Ce n'est pas un filtre appliqué après coup. Un index CDX répond nativement
aux requêtes par préfixe, donc urx envoie `url=example.com/shop*` et l'archive
ne transmet jamais le reste du site sur le réseau — sur une cible volumineuse,
c'est la différence entre quelques centaines de lignes et quelques centaines de
milliers. Les fournisseurs qui ne peuvent pas exprimer un chemin dans leur
requête (OTX, VirusTotal, urlscan, GitHub, BeVigil, ZoomEye) sont interrogés sur
l'hôte et leurs réponses sont restreintes ensuite, tout comme les résultats
d'une exécution `--subs`, où la forme `*.host` et un préfixe de chemin ne
peuvent pas être combinés dans une seule requête CDX.

La portée signifie *au niveau ou en dessous* du chemin : `/shop` et
`/shop/cart` sont inclus, `/shopping` ne l'est pas. La casse est ignorée, car
un serveur CDX met toute l'URL en minuscules lorsqu'il construit la clé de son
index — `example.com/Shop*` et `example.com/shop*` renvoient les mêmes lignes,
toutes orthographiées en minuscules, donc une vérification sensible à la casse
rejetterait tout ce que l'archive vient de renvoyer. Une chaîne de requête ou un
fragment dans la cible est supprimé — ceux-ci restreignent une requête, pas une
portée.

> Remarque : urx supprimait auparavant le chemin d'une cible, donc
> `urx https://example.com/shop` scannait tout `example.com`. Il scanne
> désormais `/shop`. Passez uniquement l'hôte pour l'ancien comportement ; une
> exécution dont la cible porte un chemin le signale sur stderr.

### Filtrage par expression régulière

`--patterns` / `--exclude-patterns` sont de simples tests de sous-chaîne : les
deux côtés sont mis en minuscules, et chaque métacaractère est littéral.
`--match-regex` / `--filter-regex` sont les équivalents regex, et ils diffèrent
de trois manières qu'il vaut la peine de retenir :

| | `--patterns` | `--match-regex` |
|---|---|---|
| Correspondance | sous-chaîne | [syntaxe regex](https://docs.rs/regex/latest/regex/#syntax) complète |
| Casse | insensible (les deux côtés en minuscules) | **sensible** — utilisez `(?i)` pour désactiver |
| Valeurs multiples | un seul flag séparé par des virgules | répétez le flag ; les virgules ne sont jamais découpées |

Les deux flags regex sont évalués contre la **chaîne d'URL complète** telle que
collectée (schéma, hôte, chemin et requête), donc `^https://` et `\.js$`
fonctionnent tous les deux. L'exclusion l'emporte : une URL correspondant à
`--filter-regex` est rejetée même si `--match-regex` y correspondait aussi. Une
expression malformée fait échouer l'exécution au démarrage, avant que toute
archive ne soit interrogée.

### Fichiers de portée

La portée d'un programme de bug bounty est une liste d'hôtes, et chaque
plateforme l'écrit de la même manière. `--scope-file` prend cette liste
textuellement au lieu de vous obliger à la traduire à la main en alternances
regex ancrées — où une erreur d'ancrage *élargit* silencieusement la portée au
lieu d'échouer.```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

I don't see any content to translate. Please provide the Markdown chunk you'd like me to translate from English to French.```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` correspond à l'apex ainsi qu'à tout ce qui se trouve en dessous (la lecture bug-bounty, ce que signifie la table de périmètre d'une plateforme) ; un hôte nu correspond exactement à cet hôte ; un `*` seul fait du fichier une pure deny-list ; les exclusions l'emportent toujours ; `#` démarre un commentaire. Tout ce qu'urx ne peut pas honorer — un port, un chemin, un joker au milieu — est une erreur au démarrage nommant le fichier et la ligne plutôt qu'un périmètre silencieusement plus large. Le filtre s'applique à chaque fournisseur et aux liens extraits, et il se combine avec `--strict` plutôt que de le remplacer, donc une ligne de périmètre `*.example.com` nécessite toujours `--subs`.

### Filtres de métadonnées d'archive

`--from`/`--to` et les prédicats `--archive-*` sont poussés dans la requête propre à l'archive, ce qui les rend gratuits et les limite aussi aux fournisseurs adossés à CDX — et les deux dialectes CDX divergent suffisamment pour qu'une liste positive multi-valeurs (`--archive-status 200,301`) soit insatisfiable sur les serveurs pywb. Les huit filtres `--meta-*` s'exécutent *après* la collecte, sur un ensemble fusionné de métadonnées de capture par URL, de sorte qu'ils s'appliquent uniformément à chaque fournisseur.```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

Les URLs qui ne portent aucune métadonnée — les fournisseurs non-CDX, l'entrée --files, les hits de cache — sont réparties selon la direction du prédicat : un prédicat positif ne peut pas être satisfait par une valeur absente, donc l'URL est écartée ; une exclusion ne supprime que ce qui correspond positivement, donc elle survit. --verbose rapporte la répartition, et lorsque les métadonnées manquantes représentent l'ensemble du jeu de résultats, urx le signale même sans -v, car un hit de cache ferait autrement passer une exécution vide pour une cible sans rien à trouver.

Regroupement des quasi-doublons

Une archive renverra volontiers /post/1 jusqu'à /post/99999. Ils constituent un seul endpoint, et --dedup-similar n'affiche qu'une ligne pour eux. Un segment de chemin est traité comme une donnée — et non comme faisant partie de la route — lorsqu'il est entièrement l'un des éléments suivants :

  • une suite de chiffres (/post/1, /page/42)
  • un UUID (/u/550e8400-e29b-41d4-a716-446655440000)
  • un condensé hexadécimal de 32/40/64 caractères (md5, sha1, sha256)
  • une date séparée (/blog/2024-01-02/)
  • un long jeton à casse mixte contenant des chiffres (identifiants de session, blobs signés)

Les segments qui contiennent simplement des chiffres restent en place, donc /api/v1/ et /api/v2/ demeurent deux endpoints, et un slug en minuscules est de la prose plutôt qu'un jeton. Les chaînes de requête sont regroupées uniquement par noms de paramètres : ?q=cats&page=1 et ?q=dogs&page=7 fusionnent, tandis que ?q=cats seul ne le fait pas — supprimer un paramètre change la requête.

Le survivant de chaque groupe est son URL lexicographiquement la plus petite, de sorte que deux exécutions sur les mêmes données affichent la même chose. --verbose rapporte combien d'URLs ont été fusionnées. L'option est indépendante de --normalize-url et --merge-endpoint et se combine avec l'une ou l'autre ; les trois nécessitent le jeu de résultats complet, donc aucune ne fonctionne avec --stream.

Vues des paramètres et du fuzzing

--show-only-param ne fait que couper la chaîne de requête de chaque URL, ce qui ne peut pas répondre à la première question que se pose un testeur : quels paramètres cette cible accepte-t-elle ? Trois vues y répondent, construites sur le même regroupement que celui utilisé par --dedup-similar.```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` réduit les segments de chemin ressemblant à des id à `{id}` exactement comme le fait `--dedup-similar`, et épelle l'endpoint en entier car urx scanne régulièrement plusieurs hôtes en une seule exécution. `--fuzz-placeholder` conserve une URL par signature de paramètre et garde son chemin réel — un `{id}` ne serait pas routé — de sorte que la sortie alimente directement un fuzzer :```bash
urx example.com --fuzz-placeholder FUZZ | ffuf -w - -u FUZZ
urx example.com --fuzz-placeholder FUZZ | dalfox pipe

Les trois ont besoin du jeu de résultats complet, ils sont donc uniquement par lots et mutuellement exclusifs entre eux et avec les vues --show-only-*.

Sortie de liste de mots

-f wordlist transforme une exécution en une liste de mots spécifique à la cible : chaque segment de chemin et nom de paramètre de requête qu'il a vus, dédupliqués sur l'ensemble de l'exécution et triés, un terme par ligne.```bash urx example.com --subs -f wordlist -o words.txt ffuf -w words.txt -u https://example.com/FUZZ

Les segments qui ressemblent à des données plutôt qu'à des noms de route sont omis, en réutilisant les groupes de test `--dedup-similar` — une wordlist remplie de `4711`, d'UUID, de dates et de jetons de session est pire que pas de wordlist du tout, puisque chacun de ces mots n'existe que sur une seule cible. Un segment dont la racine est un identifiant est également écarté (`article-1234.html`). La casse est préservée : les segments de chemin sont sensibles à la casse sur la plupart des origines, donc mettre en minuscules `WebResource.axd` produirait un mot qui renvoie un 404 partout où il est essayé. L'union doit être prise sur l'ensemble complet, donc le format est batch uniquement.

### Sortie en flux

Par défaut, urx collecte tout, puis filtre, trie et affiche une seule fois. Sur une grande cible, cela signifie aucune sortie tant que l'archive la plus lente n'a pas terminé. `--stream` écrit chaque URL au moment où le fournisseur qui la rapporte répond :```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'

Les URLs diffusées en streaming passent exactement les mêmes filtres qu'une exécution par lots et sont toujours dédupliquées. Deux choses diffèrent :

  • L'ordre. Les résultats arrivent dans l'ordre d'achèvement des fournisseurs, donc la sortie n'est pas triée. Passez par sort si vous avez besoin d'un ordre.
  • La portée. Les options qui nécessitent l'ensemble complet des résultats sont rejetées d'emblée (avec un message nommant chacune d'elles) : --merge-endpoint, --dedup-similar, --check-status / --include-status / --exclude-status, --extract-links, --extract-js-endpoints, --archive-body, --expand-specs, --incremental, --show-sources, --show-meta, les filtres --meta-*, --params, --params-by-endpoint, --fuzz-placeholder, --output-dir, et --files. La mise en cache est contournée ; --format json est refusé au profit de jsonl car un tableau JSON doit savoir quelle entrée est la dernière, et --format wordlist car aucun terme ne peut être connu comme nouveau avant que chaque URL ne soit arrivée.

Comme la table de résultats par lots n'est jamais remplie dans ce mode, une exécution en streaming occupe également beaucoup moins de mémoire — seulement l'ensemble de déduplication des URLs déjà écrites.

Métadonnées de capture d'archive

Un index CDX enregistre plus que l'URL : chaque capture porte un horodatage, le type MIME et le statut HTTP que l'archive a vus, et un condensé du corps. urx conserve tout cela, donc les fournisseurs adossés à CDX — wayback, cc, arquivo, et tout --cdx-endpoint — rapportent chaque URL avec :

ChampSignification
first_seenHorodatage de la capture la plus ancienne, forme CDX à 14 chiffres (YYYYMMDDhhmmss)
last_seenHorodatage de la capture la plus récente
mimeType MIME de la capture la plus récente qui en a enregistré un
archive_statusStatut HTTP que l'archive a enregistré au moment de la capture
digestUn condensé de contenu représentatif parmi les captures

archive_status n'est pas status : status n'apparaît que sous --check-status, qui redemande l'URL en direct maintenant, alors que archive_status est ce que le crawler a obtenu lorsqu'il a capturé la page. Une URL peut parfaitement avoir un archive_status 200 et être morte aujourd'hui.

Lorsque la même URL provient de plusieurs captures ou de plusieurs archives, les valeurs sont fusionnées : first_seen est l'horodatage le plus ancien rapporté par quiconque, last_seen le plus récent, et mime/archive_status proviennent de la capture la plus récente qui les possédait. Les fournisseurs sans index de capture (otx, vt, urlscan, zoomeye, github, bevigil, robots, sitemap, et l'entrée --files) rapportent l'URL seule — aucune valeur n'est inventée pour eux.

La façon dont les métadonnées apparaissent dépend du format :

  • json / jsonl — chaque champ apparaît comme une clé lorsqu'il a une valeur et est entièrement omis lorsqu'il n'en a pas, exactement comme sources.
  • csv — une colonne n'est ajoutée que lorsqu'au moins une ligne a une valeur pour elle, donc une exécution sans métadonnées produit toujours une seule colonne url.
  • texte brut — inchangé par défaut, une URL nue par ligne, afin que les pipelines existants continuent de fonctionner. Passez --show-meta pour ajouter les champs.```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

Le streaming (`--stream`) ne rapporte que les URLs. Une URL est affichée dès sa première observation, avant que les captures qui élargiraient sa plage `first_seen`/`last_seen` ne soient arrivées, donc `--show-meta` y est rejeté pour la même raison que `--show-sources`.

Un hit de cache ne porte pas non plus de métadonnées : le cache stocke les URLs, donc un domaine servi depuis le cache rapporte ses URLs sans les champs de capture. Utilisez `--no-cache` (ou attendez l'expiration du TTL) pour une exécution qui les repeuple.

### Métadonnées de réponse en direct

`--check-status` envoie déjà une requête et attend l'en-tête de réponse, donc ce que cet en-tête transporte vient gratuitement : `Location`, `Content-Length` et `Content-Type` sont enregistrés aux côtés du code de statut. Les redirections ne sont toujours jamais suivies, donc un statut rapporté appartient toujours à l'URL qui a été demandée et `location` indique simplement où le 3xx pointait.

`--check-title` ajoute le `<title>` HTML. C'est le seul champ qui n'est pas gratuit — un titre nécessite le corps de la réponse — donc il se trouve derrière son propre drapeau. La lecture est bornée deux fois (au plus 64 KiB, et elle s'arrête à la balise fermante) et entièrement ignorée pour un corps que le serveur a déclaré comme non-HTML, donc une API JSON ou une image ne coûte rien. Le titre est condensé en espaces, décodé des entités et coupé à 200 caractères. `--check-title` implique `--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'

L'exposition suit la règle déjà établie par les métadonnées de l'archive : json/jsonl/csv portent toujours les champs (les clés absentes sont omises, et les colonnes CSV sont ajoutées après celles existantes), tandis que le texte brut reste une URL nue par ligne sauf si --show-meta demande le contraire. En sortie brute, le titre est mis entre guillemets, puisqu'il s'agit de la seule valeur qui contient régulièrement des espaces.

Requêtes authentifiées et personnalisées

--check-status, --extract-links, --extract-js-endpoints et --expand-specs redemandent tous les URL collectées à la cible elle-même. -H fournit à ces requêtes tous les en-têtes dont elles ont besoin :```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` est répétable, prend `Name: value`, et un en-tête mal formé arrête l'exécution
plutôt que de passer inaperçu — un argument silencieusement abandonné laisse
un scan anonyme se lire comme un scan authentifié. `--cookie` et
`--user-agent` sont des raccourcis pour les en-têtes correspondants.

**Ces en-têtes n'atteignent jamais une archive.** Ils ne sont envoyés que par les composants
qui communiquent avec la cible : les quatre testeurs ci-dessus, plus les fournisseurs `robots` et
`sitemap`, qui récupèrent aussi depuis la cible. Tous les autres fournisseurs
interrogent web.archive.org, index.commoncrawl.org ou une API tierce, et il en va de même
pour `--archive-body` lorsqu'il rejoue une capture ; leur transmettre le cookie de session de la cible
reviendrait à envoyer un identifiant à un service qui conserve ce qu'il
reçoit, sans aucun bénéfice. Les requêtes d'archive conservent le User-Agent propre à urx, que
`--random-agent` fait toujours tourner.

### Extraction des corps de réponse archivés

`--extract-links` récupère chaque URL collectée depuis le site en direct, ce qui est
exactement le mauvais endroit pour chercher les pages qui intéressent le plus une campagne OSINT :
celles qui n'existent plus. `--archive-body` récupère à la place les corps que la Wayback
Machine a stockés. Pour chaque URL collectée portant un horodatage de capture, urx rejoue
cette capture sous sa forme brute
(`https://web.archive.org/web/<timestamp>id_/<url>` — le drapeau `id_` désactive la
barre d'outils Wayback et la réécriture des liens, de sorte que le corps correspond aux octets d'origine) et
exécute la même extraction de liens que celle utilisée par `--extract-links` sur celui-ci.```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

Pourquoi cela nécessite beaucoup moins de requêtes que waymore. Chaque ligne CDX porte un condensé de contenu, et deux captures ayant le même condensé ont un corps identique octet pour octet. Les archives en sont remplies : chaque variante ?utm_source= d'une page, chaque /index.html à côté de son /, chaque permutation de paramètre de suivi sert des octets identiques, de sorte qu'une liste de dizaines de milliers d'URL se réduit régulièrement à quelques milliers de corps distincts. waymore n'a aucune notion de cela — il télécharge une réponse par URL et gère le volume via un plafond brutal -l 5000, ce qui martèle l'archive et tronque la couverture. urx revendique chaque condensé la première fois qu'il est vu et ignore chaque URL ultérieure qui rejouerait les mêmes octets, de sorte que la même couverture coûte une requête par corps distinct. --archive-body-limit (par défaut 500) borne les corps distincts, pas les URL ; les doublons ne sont jamais comptés contre cette limite, et --verbose indique combien ont été ignorés.

Exploration du JavaScript archivé. La surface d'API d'une application moderne réside dans ses bundles sous forme de littéraux de chaîne, et --extract-js-endpoints les récupère depuis le site en ligne — où ils ont souvent disparu. Les bundles sont nommés par hash de build, donc app.a3f9c2.js renvoie un 404 dès que le site est redéployé, et les endpoints qu'il nommait disparaissent avec lui. Lancez les deux flags ensemble et urx explore la copie archivée à la place, ainsi que les blocs <script> en ligne d'une page archivée aux côtés de ses liens :```bash urx example.com --archive-body --extract-js-endpoints

**Conserver les corps.** Les requêtes sont déjà effectuées, donc écrire les corps sur disque ne coûte rien de plus et répond aux questions qu'aucun extracteur de liens ne pose : le commentaire `<!-- staging.internal -->`, le jeton qu'un build de 2019 a intégré, la trace de pile nommant une version de framework.```bash
urx example.com --archive-body --archive-body-dir ./corpus
grep -ri "api[_-]key" ./corpus

Chaque fichier est nommé d'après son URL plus un hash de celle-ci, et corpus/index.jsonl associe chaque fichier à son URL, son horodatage de capture, son digest et son type de contenu. Seuls les corps de type texte sont stockés — HTML, script, JSON, XML, CSS, texte brut — afin que le répertoire ne se remplisse pas avec les images et les polices du site. Comme la récupération est dédupliquée par digest, le corpus couvre bien plus de la cible par requête qu'une réponse par URL ne le ferait.

Détails à connaître :

  • Seules les URL disposant d'un horodatage de capture sont éligibles. Les fournisseurs CDX (wayback, cc, arquivo) en fournissent un ; l'entrée --files, les fournisseurs non-CDX et les résultats mis en cache (le cache ne stocke que les URL) n'en ont aucun. urx le signale lorsqu'il n'y a rien à rejouer — passez --no-cache pour obtenir des captures fraîches.
  • La capture la plus récente de chaque URL est rejouée. Un horodatage rapporté par une autre archive est rattaché à la capture Wayback la plus proche ; une URL que la Wayback Machine n'a jamais vue répond 404 et est ignorée. Les captures que l'archive a enregistrées comme erreurs ne sont pas exploitées, exactement comme --extract-links ignore les pages d'erreur en direct.
  • Les liens découverts passent par les mêmes filtres, la même validation d'hôte et les mêmes transformations de sortie que tout le reste, et chaque corps est plafonné à 10 MiB.
  • --rate-limit, --rate-limit-by wayback=N, --parallel, --proxy, --timeout et --retries s'appliquent tous aux requêtes de rejeu.
  • Incompatible avec --stream, comme toute option qui s'exécute après la collecte.

Développer les spécifications d'API

Un balayage -p only-api trouve /swagger.json, /openapi.yaml et /v3/api-docs puis ne les ouvre jamais : --extract-links analyse le HTML, --extract-js-endpoints écarte les corps application/json, et --archive-body exécute l'analyseur HTML sur tout ce que l'archive renvoie. --expand-specs les lit et développe chaque route qu'ils décrivent dans l'ensemble de résultats — une requête achète toute la surface documentée, exacte et déjà paramétrée.```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

Ce qui est développé :

* **OpenAPI 3.x** — `servers[].url` (absolu, relatif au document et templatisé,
  avec `{var}` résolu depuis `variables[var].default` ou la première valeur de `enum`)
  croisé avec chaque clé de `paths` ; les `servers` propres à un élément de chemin
  remplacent ceux du document.
* **Swagger 2.0** — `schemes` × `host` + `basePath`, chaque partie se rabattant sur
  la partie correspondante de l'URL du document lui-même. `ws`/`wss` sont abandonnés.
* **Introspection GraphQL** — une URL par champ de requête, de mutation et
  d'abonnement, écrite comme le point de terminaison plus `?query=…`. Un schéma
  enregistré sous forme de fichier se résout vers son point de terminaison
  (`/graphql/schema.json` → `/graphql`).

JSON et YAML sont tous deux lus. Les cibles sont choisies d'abord par nom et
gratuitement (une sous-chaîne marqueur de spécification — `swagger`, `openapi`,
`api-docs`, `graphql`, `introspection` — plus une extension `json`/`yaml`/`yml`
lorsqu'il y en a une, de sorte que `swagger-ui.html` ne coûte aucune requête),
puis par le `Content-Type` de la réponse. Les modèles de chemin sont émis tels
que le document les écrit (`/users/{id}`, et non `/users/%7Bid%7D`). Les corps
sont plafonnés à 10 MiB, et un document YAML comportant plus de 32 références
d'alias est refusé avant l'analyse pour écarter les bombes d'expansion.
`--max-spec-files` (par défaut 50) borne les documents récupérés. Avec
`--archive-body` également activé, une spécification archivée est lue comme
telle sans coût de requête supplémentaire — le corps était déjà en cours de
récupération.

### robots.txt et sitemap.xml archivés

Les fournisseurs `robots` et `sitemap` lisent les fichiers *actuels*, qui ne
disent que ce qu'un site cache ou liste aujourd'hui. `--archived-discovery` lit
aussi chaque version distincte de ces fichiers que la Wayback Machine a
stockée. Un `Disallow:` de 2015 nomme des chemins que le site a cessé de
mentionner depuis — souvent parce qu'ils étaient censés être oubliés, non parce
qu'ils ont disparu — et un ancien sitemap liste tout ce que le site voulait
autrefois voir exploré.```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

Fonctionnement, et pourquoi c'est économique :

  • Les versions d'un document sont listées avec une requête CDX par fichier (robots.txt, sitemap.xml, sitemap_index.xml, sitemap.txt), en utilisant collapse=digest afin que les captures consécutives ayant servi les mêmes octets soient regroupées en une seule ligne. Seules les lignes enregistrées comme un succès sont demandées : l'index fusionne www. et l'apex en une seule liste, et leurs lignes 301/200 entrelacées empêchent sinon le collapse — pour github.com/robots.txt cela représente 325k lignes sans le filtre et 14k avec, pour les mêmes 107 versions distinctes.
  • Chaque version distincte est rejouée sous forme brute (/web/<timestamp>id_/…) et transmise au même parseur que le fichier en direct. Pas de second parseur : un robots.txt de 2015 est lu par exactement les mêmes règles que l'actuel, y compris les garde-fous de chemin absolu et de saut de motif. Un <sitemapindex> archivé est suivi dans ses enfants tels qu'ils étaient à ce même moment.
  • Les captures que l'archive a enregistrées comme erreurs (le robots.txt de github.com était un 401 pendant une partie de 2007) sont ignorées sans requête et signalées sous --verbose uniquement.
  • --archived-discovery-limit (par défaut 50) plafonne les documents récupérés par domaine par chaque fournisseur archivé, versions les plus récentes en premier ; les sitemaps imbriqués comptent. --verbose indique quand le plafond a tronqué la liste.
  • Les variantes archivées s'exécutent comme leurs propres instances de fournisseur — « Robots.txt (archived) » et « Sitemap (archived) » dans --stats et --show-sources — mais sous les ids existants robots / sitemap, de sorte que --exclude-robots, --exclude-sitemap et --rate-limit-by robots=N régissent à la fois les lectures en direct et archivées. --from / --to restreignent les versions considérées.
  • Fonctionne avec --stream ; c'est un fournisseur comme un autre.

Filtrage côté archive

--archive-status, --archive-mime, --from et --to sont évalués par l'index CDX de l'archive plutôt que par urx. Deux conséquences méritent d'être connues :

  • Ils ne s'appliquent qu'aux fournisseurs adossés à CDX — wayback, cc, arquivo et tout --cdx-endpoint. Les autres fournisseurs les ignorent ; urx avertit quand aucun n'est activé.
  • Les archives ne partagent pas un même dialecte de filtre. Wayback Machine (et tout endpoint --cdx-dialect classic) traite les valeurs comme des expressions régulières, donc --archive-status "30." correspond à tout 3xx. Common Crawl, Arquivo.pt et les endpoints pywb correspondent exactement, et leur index combine les filtres répétés par AND — ainsi une liste positive à valeurs multiples comme --archive-status 200,301 est insatisfiable là-bas. urx ignore ce filtre pour ces fournisseurs (avec un avertissement) au lieu d'envoyer une requête qui reviendrait vide. Les exclusions à valeurs multiples signifient « ni ceci ni cela » et fonctionnent partout.

Utilisez --archive-status lorsque vous voulez ce que l'archive a enregistré au moment du crawl et --check-status / --include-status lorsque vous voulez le statut de la cible maintenant ; ce dernier redemande chaque URL.

Endpoints CDX personnalisés

Chaque archive web construite sur pywb, OutbackCDX ou le serveur CDX de l'Internet Archive expose la même API de requête. Plutôt que de coder en dur un fournisseur par archive, --cdx-endpoint URL transforme n'importe quel tel serveur en fournisseur à la volée :```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

* L'identifiant du fournisseur est `cdx:<host>` (`cdx:vefsafn.is`), ce que
  `--exclude-providers`, `--rate-limit-by`, `--stats` et `--show-sources` utilisent.
  Nommer un endpoint l'active ; aucune entrée `--providers` n'est nécessaire, et
  `--providers cdx:vefsafn.is` l'exécute seul. `--list-providers` affiche les
  endpoints nommés sur la même ligne de commande avec les ids sous lesquels ils s'exécuteront.
* Tout ce que les fournisseurs CDX intégrés respectent s'applique ici aussi : `--subs`,
  `--from`/`--to`, les filtres `--archive-*`, la pagination, `--rate-limit`, et
  les métadonnées de capture décrites ci-dessus.
* `--cdx-dialect classic|pywb` nomme le dialecte du serveur (noms de champs, sémantique des filtres,
  format des lignes et schéma de pagination en découlent tous — voir
  « Filtrage côté archive »). Non défini, urx sonde l'endpoint une fois par exécution
  et se rabat sur `pywb`, le dialecte le plus courant ; définissez-le explicitement lorsque la
  sonde ne peut pas le déterminer (une réponse vide pour un domaine inconnu, par exemple).
* Peut aussi être défini dans le fichier de configuration (`cdx_endpoint = [...]`, `cdx_dialect`).

**Endpoints vérifiés.** À l'heure où nous écrivons, le seul endpoint public confirmé
fonctionner à bout en bout est `https://vefsafn.is/cdx` (l'archive web islandaise de Landsbókasafn, dialecte pywb). Deux choses à savoir à son sujet : il ignore `limit`, `page`
et `showNumPages` et renvoie l'ensemble complet des résultats pour chaque requête, ce que
urx gère ; et après une poignée de requêtes, il peut commencer à répondre avec une
page de protection anti-bot de style Anubis (« Session Verification »). urx détecte une réponse HTML
à la place des lignes CDX et la signale comme une erreur de fournisseur nommant
l'endpoint — elle n'est jamais comptée comme « aucune URL ». Si vous la rencontrez, ralentissez avec
`--rate-limit-by cdx:vefsafn.is=1` ou réessayez plus tard.

**Connus pour ne pas fonctionner.** Le UK Web Archive (`webarchive.org.uk`), l'archive web de la Library of
Congress (`webarchive.loc.gov`), Bibliotheca Alexandrina, et la
National Library of Australia (`web.archive.org.au`) se trouvent tous derrière une protection anti-bot ou des redirections qui bloquent leurs API CDX depuis un client en ligne de commande.
urx ne tente pas de contourner cela, donc pointer `--cdx-endpoint` vers eux
produit l'erreur de réponse HTML ci-dessus.

### Mise en cache et analyse incrémentale

Urx prend en charge la mise en cache pour améliorer les performances des analyses répétées et l'analyse incrémentale pour ne découvrir que les nouvelles URL.```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

Gestion du cache

urx cache inspecte et maintient le cache sans toucher à la base de données à la main. Chaque sous-commande respecte les mêmes --cache-type, --cache-path, --redis-url et --cache-ttl qu'un scan, et les cinq fonctionnent avec les deux 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'

La correspondance de domaine est insensible à la casse et **exacte**, sauf si le motif contient
`*` — une correspondance par sous-chaîne par défaut aurait permis à `drop example.com` de supprimer
`notexample.com` également. `clear` demande confirmation avant de supprimer et refuse un
stdin non interactif plutôt que de supposer une réponse, `drop` nomme tout motif
qui n'a rien matché, consulter le cache n'en crée jamais, et Redis est parcouru
avec `SCAN` plutôt que le bloquant `KEYS` (avec tout mot de passe dans `--redis-url`
masqué avant d'être affiché).

#### Cas d'usage du cache```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

Notifications par Webhook

--notify <URL> envoie en POST un résumé de l'exécution à un webhook lorsque l'exécution se termine, ce qui transforme --incremental en un moniteur : placez-le dans cron et le webhook ne se déclenche que lorsqu'un nouvel élément apparaît.```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` vaut `new` par défaut : rien n'est envoyé lorsque l'exécution n'émet aucune URL, donc une exécution cron silencieuse reste silencieuse. `always` envoie dans tous les cas ; `never` conserve la configuration mais désactive l'envoi.
- `--notify-format json` (par défaut) envoie le schéma d'urx : `domains`, `incremental`, `url_count`, `new_url_count`, `elapsed_ms`, une liste `providers` par fournisseur (les mêmes chiffres que ceux affichés par `--stats`), et un `sample` allant jusqu'à 20 URLs émises avec `sample_truncated` défini lorsque davantage ont été trouvées. `slack` envoie `{"text": ...}` et `discord` envoie `{"content": ...}` avec un court message lisible par un humain ; les messages plus longs que ce que le service autorise sont coupés sur une limite de ligne et se terminent par `[truncated: N lines cut ...]`.
- La livraison ne modifie jamais le code de sortie. Les URLs sont déjà sur stdout ou dans `--output` au moment où le webhook est appelé, donc un webhook mort est un avertissement sur stderr et l'exécution se termine quand même avec le code 0. `--verbose` affiche le statut de la réponse.
- L'URL du webhook est un identifiant. urx n'affiche jamais plus que son schéma et son hôte — ni dans `--verbose`, ni dans les avertissements, ni dans `--stats`. Pour la garder hors d'une configuration versionnée, placez-la dans `URX_NOTIFY_URL` ou comme `notify_url` dans le fichier de configuration du fournisseur ; `[notify].url` dans la configuration principale fonctionne aussi. La priorité est CLI/env > configuration du fournisseur > configuration principale.
- La requête respecte `--proxy`, `--proxy-auth`, `--timeout` et `--insecure`. `--network-scope` ne s'applique pas : il partitionne le trafic destiné à la cible et aux archives, et le webhook est votre propre point de terminaison.
- `--silent` envoie quand même (c'est le cas d'usage principal) ; il ne fait que masquer les diagnostics.

## Intégration avec d'autres outils

Urx fonctionne bien dans des pipelines avec d'autres outils de sécurité et de reconnaissance :```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 a été inspiré par gau (GetAllUrls), un outil qui récupère les URL connues depuis AlienVault's Open Threat Exchange, la Wayback Machine et Common Crawl. Bien qu'il partage des fonctionnalités de base similaires, Urx a été construit à partir de zéro en Rust avec un accent sur la performance, la concurrence et des capacités de filtrage étendues.

Contribuer

Urx est un projet open-source et a été fait avec ❤️ si vous souhaitez contribuer à ce projet, veuillez consulter CONTRIBUTING.md et faire une Pull-Request avec vos contenus sympas.

Catégories