Skip to main content
Flows orchestrate multiple modules with dependencies and conditional execution.

Basic Flow

kind: flow
name: basic-recon
description: Basic reconnaissance flow

params:
  - name: target
    required: true

modules:
  - name: subdomain-enum
    path: modules/subdomain-enum.yaml

  - name: http-probe
    path: modules/http-probe.yaml
    depends_on:
      - subdomain-enum

  - name: screenshot
    path: modules/screenshot.yaml
    depends_on:
      - http-probe

Module Reference Fields

modules:
  - name: module-name           # Required: reference name
    path: path/to/module.yaml   # Required: module file path
    depends_on:                 # Optional: dependency list
      - other-module
    condition: 'expression'     # Optional: skip condition
    params:                     # Optional: parameter overrides
      key: value

name

Unique identifier for this module reference within the flow.
- name: subdomain-enum      # Used in depends_on references

path

Path to the module YAML file (relative to workflow folder).
- name: nuclei
  path: modules/nuclei-scan.yaml

depends_on

List of module names that must complete before this module runs.
- name: vuln-scan
  path: modules/vuln.yaml
  depends_on:
    - subdomain-enum
    - http-probe        # Both must complete first

condition

JavaScript expression evaluated before module execution. Module is skipped if false.
- name: screenshot
  path: modules/screenshot.yaml
  depends_on: [http-probe]
  condition: 'fileLength("{{Output}}/live-hosts.txt") > 0'
Common conditions:
# File has content
condition: 'fileLength("{{Output}}/data.txt") > 0'

# File exists
condition: 'fileExists("{{Output}}/targets.txt")'

# Parameter check
condition: '{{enable_vuln_scan}} == "true"'

params

Override module parameters.
- name: nuclei-fast
  path: modules/nuclei-scan.yaml
  params:
    threads: "100"
    severity: "critical,high"

Dependency Graph

Flows create a directed acyclic graph (DAG):
modules:
  - name: A
    path: modules/a.yaml

  - name: B
    path: modules/b.yaml
    depends_on: [A]

  - name: C
    path: modules/c.yaml
    depends_on: [A]

  - name: D
    path: modules/d.yaml
    depends_on: [B, C]
Execution:
    A           # Step 1: A runs
   / \
  B   C         # Step 2: B and C run in parallel
   \ /
    D           # Step 3: D runs after B and C

Complex Flow Example

kind: flow
name: full-assessment
description: Complete security assessment

params:
  - name: target
    required: true
  - name: enable_active
    default: "false"
    description: Enable active scanning

modules:
  # Passive reconnaissance
  - name: subdomain-enum
    path: modules/subdomain-enum.yaml

  - name: dns-enum
    path: modules/dns-enum.yaml

  # Both can run in parallel, both depend on nothing
  # Execution: subdomain-enum and dns-enum run together

  - name: http-probe
    path: modules/http-probe.yaml
    depends_on:
      - subdomain-enum
      - dns-enum
    # Waits for both to complete

  - name: screenshot
    path: modules/screenshot.yaml
    depends_on: [http-probe]
    condition: 'fileLength("{{Output}}/live.txt") > 10'

  - name: content-discovery
    path: modules/content-discovery.yaml
    depends_on: [http-probe]

  # Active scanning (conditional)
  - name: port-scan
    path: modules/port-scan.yaml
    depends_on: [subdomain-enum]
    condition: '{{enable_active}} == "true"'

  - name: vuln-scan
    path: modules/vuln-scan.yaml
    depends_on:
      - http-probe
      - port-scan
    condition: '{{enable_active}} == "true" && fileExists("{{Output}}/live.txt")'

  # Reporting
  - name: generate-report
    path: modules/report.yaml
    depends_on:
      - screenshot
      - content-discovery
      - vuln-scan

Running Flows

# Basic execution
osmedeus run -f full-assessment -t example.com

# With parameters
osmedeus run -f full-assessment -t example.com -p 'enable_active=true'

# Exclude specific modules
osmedeus run -f full-assessment -t example.com -x vuln-scan -x port-scan

# Dry run (preview)
osmedeus run -f full-assessment -t example.com --dry-run

Module Exclusion

Skip specific modules:
osmedeus run -f full-assessment -t target -x screenshot -x port-scan
Excluded modules are treated as completed (dependencies are satisfied).

Flow-Level vs Module-Level Params

# Flow definition
kind: flow
name: my-flow
params:
  - name: target
    required: true
  - name: threads
    default: "50"           # Flow-level default

modules:
  - name: scan
    path: modules/scan.yaml
    params:
      threads: "{{threads}}"   # Use flow param
      wordlist: "/custom.txt"  # Module-specific override
Resolution order:
  1. Module reference params (highest priority)
  2. Flow-level params
  3. Module’s own default params (lowest priority)

Error Handling

By default, if a module fails:
  • Dependent modules are skipped
  • Other independent branches continue
modules:
  - name: A
    path: modules/a.yaml

  - name: B
    path: modules/b.yaml
    depends_on: [A]
    # If A fails, B is skipped

  - name: C
    path: modules/c.yaml
    # C runs regardless of A or B

Best Practices

  1. Group related modules
    # Passive recon group
    - name: subdomain-enum
    - name: dns-enum
    
    # Active scan group
    - name: port-scan
    - name: vuln-scan
    
  2. Use conditions for optional modules
    - name: active-scan
      condition: '{{enable_active}} == "true"'
    
  3. Check file existence before processing
    - name: process-results
      condition: 'fileLength("{{Output}}/data.txt") > 0'
    
  4. Parameterize module behavior
    - name: nuclei
      params:
        threads: "{{threads}}"
        severity: "{{severity}}"
    
  5. Add a final reporting module
    - name: report
      depends_on: [all, other, modules]
    

Next Steps