Z-Sans controls scanning behavior through a YAML configuration file. The default path is breeding-config.yaml.

Configuration Loading Mechanism

Generating the Default Configuration

python main.py --init

If the target file does not exist, --init performs a full-file copy of templates/breeding-config.yaml (with complete Chinese comments); it falls back to dumping the built-in defaults only when the template is unavailable.

Configuration Merging Rules

The configuration file is merged with the built-in defaults using a recursive deep merge:

  • Dictionaries are merged recursively (write only the fields you need; the rest keep their defaults)
  • Lists and scalars are overwritten directly
  • Therefore you can write only the fields you need, e.g. asset_types.domain.priority

List Overwrite Pitfall

List fields such as plugins.disabled are fully replaced, not appended. If you write plugins.disabled: [a] in your config but the built-in default also contains b, then b will be lost during the merge. Merge order: built-in defaults → user config; the user config completely overwrites identically-named lists.

Configuration Structure Overview

strategy: priority_based        # Breeding strategy
asset_scope: {...}              # Scan scope
concurrency: {...}              # Concurrency
max_depth: 4                    # Maximum depth
resource_limits: {...}          # Asset limits
asset_types: {...}              # Per-type toggles and tools
output: {...}                   # Output
external_tools: {...}           # External tools
language: {...}                 # Language
exclusions: {...}               # Exclusion rules
http: {...}                     # HTTP behavior
plugins: {...}                  # Plugins (template only)
checkpoint: {...}               # Checkpoint (template only)
monitoring: {...}               # Monitoring (template only)

Global

strategy: priority_based   # priority_based | depth_first | breadth_first | time_based

max_depth: 4               # Maximum discovery depth (can be overridden by --depth)

asset_scope — Asset Scan Scope

asset_scope:
  restrict_to_seed_domains: true     # Restrict to seed domains only
  restrict_to_seed_ip_ranges: false  # Restrict to seed IP ranges only
  include_subdomains: true           # Include subdomains
  include_ip_ranges: true            # Include IP ranges
  seed_scope: registrable            # Seed scope expansion, see below

seed_scope — Seed Scope Expansion

Controls whether/how a seed domain is expanded for relevance matching (restrict_to_seed_domains: true):

Value Behavior Example
registrable (default) Expand to the registrable domain (eTLD+1) computed from the bundled Public Suffix List Seed www.example.com → also covers example.com and all its subdomains. Seed example.co.uk → stays example.co.uk, because co.uk is a public suffix and will not be matched against unrelated *.co.uk sites
exact No expansion at all — only the seed domain itself and its subdomains Seed www.example.com → covers *.www.example.com only; mail.example.com is out of scope

The Public Suffix List data is bundled at core/data/public_suffix_list.dat (ICANN + Private sections), so this works offline with no extra dependency; if that file is missing, Z-Sans falls back to an installed publicsuffixlist/publicsuffix2 package and finally to a built-in table of common multi-part suffixes.

Why not just take the last two labels?

Older versions expanded seeds by taking the last two labels (parts[-2:]). That works for www.example.comexample.com, but turns example.co.uk into the public suffix co.uk — making every third-party *.co.uk site look "seed-related" and dragging the scan off-scope. The PSL-based mode fixes both directions; use exact when you want zero expansion.

Seeds are also normalized (lowercase, trailing dot stripped) before matching.

concurrency — Concurrency

concurrency:
  max_tasks: 20       # Global maximum concurrent tasks (thread pool size)
  tools:              # Per-tool independent concurrency
    subfinder: 2
    naabu: 2
    jsfinder: 2

resource_limits — Asset Quantity Limits

Assets exceeding the limits are marked excluded:

resource_limits:
  max_domains: 2000
  max_ips: 2000
  max_urls: 5000
  max_ports: 5000
  max_js: 5000

asset_types — Asset Types and Tool Switches

Each type can be configured with: enabled state, depth limit, priority, and tool switches.

asset_types:
  domain:
    enabled: true
    depth_limit: 3        # Maximum mining depth for this type
    priority: 10          # Higher value = processed first
    tools:
      subfinder: true     # Subdomain discovery
      free_subfinder: false  # Free passive-source aggregation
      crtsh: true         # CRT.sh certificate transparency logs
      dns_brute: true     # Built-in DNS brute force enumeration
      dnsx: true          # DNS resolution verification
  ip:
    enabled: true
    depth_limit: 4
    priority: 8
    tools:
      naabu: true             # Port scanning
      reverse_dns: true       # Reverse DNS
      port_range: '1-1024,3306,3389,5432,5900,6379,7001,8000-8500,8888,9000-9100,9200,27017,11211'  # (template only, not in this file)
  url:
    enabled: true
    depth_limit: 5
    priority: 10
    tools:
      jsfinder: true      # JS extraction
      link_extract: true  # Hyperlink extraction
      fingerprint: true   # Site fingerprinting
    title_extraction:     # Title extraction
      enabled: true
      max_length: 50      # Maximum length; longer titles are truncated
      show_in_report: true
      show_in_csv: true
  port:
    enabled: true
    depth_limit: 5
    priority: 7
    tools:
      service_identify: true  # Service identification
  js:
    enabled: true
    depth_limit: 4
    priority: 6
    tools:
      jsfinder: true

Default Priorities

If priority is not configured, the built-in defaults are domain=5, url=4, ip=3, port=2, js=1.

output — Output

output:
  dir: output                    # Output root directory (can be overridden by -o)
  graph_format: json             # Reserved field, actually controlled by formats
  asset_report: json             # Reserved field
  keep_eliminated_assets: true   # Keep eliminated assets in the report
  formats:
    json: true      # JSON asset graph
    csv: true       # Two CSVs (assets + relations)
    graphml: true   # GraphML topology
    html: true      # HTML report
  auto_open: true   # Automatically open the report when the scan finishes
  output_prefix: zsans   # Output file prefix (template only)

external_tools — External Tools

external_tools:
  paths:                 # Custom paths; if empty, tools are located via the probe order
    subfinder: null      # e.g. /usr/bin/subfinder
    naabu: null          # e.g. D:\naabu\naabu.exe
    ehole: null          # EHole fingerprint tool
    whatweb: null        # WhatWeb fingerprint tool
  fingerprint:              # Fingerprint recognition
    enabled: true           # Use the local multi-architecture EHole
    engine: auto            # auto | ehole | whatweb | both | none
  jsfinder_timeout: 30      # JSfinder timeout (seconds, template only)

Tool probe order (see Tool Integration):

  1. external_tools.paths.<name> from the configuration
  2. Built-in directories tools/<name>/... / assets/<name>
  3. System PATH

language — Internationalization

language:
  default_language: en      # zh_CN or en
  supported_languages:
    - zh_CN
    - en
  locale_dir: i18n          # Language files directory

See Internationalization for details.

exclusions — Exclusion Rules

Assets matching exclusion rules are marked excluded and trigger on_asset_excluded.

exclusions:
  domains:        # Excluded domains (exact match or its suffix .<domain>)
    - example.com
    - test.local
  ips:            # Excluded IPs (exact match)
    - 127.0.0.1
    - 0.0.0.0
  urls:           # URLs containing a keyword are excluded
    - login
    - logout
  ports: []       # Excluded ports
  patterns:       # Regex exclusions (common static asset suffixes)
    - \.(css|jpg|jpeg|png|gif|svg|woff|woff2|ttf|eot)$

http — HTTP Behavior

http:
  timeout: 10              # Per-request timeout (seconds)
  retries: 3               # Number of retries (retries on 429/5xx)
  user_agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
  verify_ssl: false        # Verify SSL certificates (set to false for self-signed sites)
  proxy: null              # HTTP proxy
  follow_redirects: true   # Follow redirects
  redirect_as_new_asset: true  # Record the redirect target as a new asset
  max_redirects: 5         # Maximum redirects per link

plugins — Plugins (provided by the template)

plugins:
  dir: null       # Plugin directory; when null, uses plugins/ at the project root
  disabled: []    # List of plugin names to disable

checkpoint — Resumable Scanning (provided by the template)

checkpoint:
  enabled: true   # Enable checkpoint saving
  interval: 50    # Save once every 50 processed assets
  file: null      # Checkpoint file path; when null, uses <output_dir>/checkpoint.json

monitoring — Monitoring (provided by the template)

monitoring:
  enabled: false   # Whether it is enabled (actual effect is determined by --watch)
  interval: 3600   # Polling interval (seconds)
  webhook_url: null # Change-alert Webhook (POST JSON)

monitoring.enabled is not actually consulted

Entering monitoring mode is decided by the CLI flag --watch; the code only reads interval and webhook_url.

Top-Level Priority Chain

Configuration Source Priority
CLI flags (--depth, -o) Highest (overrides configuration)
breeding-config.yaml user configuration Medium
Built-in DEFAULT_CONFIG Lowest (fallback)