How to Create Custom YAML Addons for the LazyOwn Framework: A Complete Development Guide

LazyOwn extends its capabilities by pairing a Lua implementation file with a YAML metadata descriptor in the plugins/ directory, enabling automatic discovery, permission validation, and CLI registration without modifying core framework code.

The LazyOwn framework by grisuno uses a modular plugin architecture that allows security researchers to add functionality through custom YAML addons. Each addon consists of two files—a Lua script containing the logic and a YAML file supplying metadata—that reside in the plugins/ directory. This guide explains how to structure these descriptors and implement the corresponding Lua functions to extend LazyOwn for Red Team engagements.

How LazyOwn Discovers and Loads Custom Addons

According to the grisuno/lazyown source code, the framework initializes its plugin system by scanning the plugins/ directory at startup. The utils.load_plugins() function iterates through all *.yaml files, parsing each with yaml.safe_load to extract metadata into a Plugin object.

When a user executes lazyown <plugin_name>, the framework:

  1. Locates the YAML descriptor matching the command name
  2. Validates required system capabilities and permissions
  3. Imports the corresponding Lua file (same base name as the YAML)
  4. Invokes the registered function and handles declared outputs

This auto-discovery mechanism ensures that adding functionality requires no changes to lazyc2.py or other core loader files.

Structure of a YAML Addon Descriptor

The YAML file supplies critical metadata that controls how LazyOwn exposes and executes the plugin. The descriptor must follow strict indentation rules and include specific fields to pass validation.

Required Metadata Fields

Every YAML addon must define these core properties:

  • name – The CLI identifier used to invoke the command (e.g., ping_host)
  • description – A multiline explanation using the > folded style scalar
  • author and version – Attribution and semantic versioning
  • enabled – Boolean flag determining if the plugin is active
  • tags – Categorization labels for search and autocompletion

Permission and Dependency Declarations

Security-sensitive operations require explicit capability flags:

  • permissions – List of capability flags such as needs_file_read, needs_file_write, or needs_network
  • requires_root – Boolean indicating if elevated privileges are mandatory
  • dependencies – External binaries or Python packages that must exist on the system
  • outputs – Declared return types (console_output, file paths, or binary data)

The params field defines the plugin's interface, listing expected arguments with name, description, and required boolean flags.

Step-by-Step: Building Your First Custom Addon

Creating a functional addon requires two files with identical base names placed in plugins/.

Step 1: Write the Lua Implementation

Create a Lua file that implements the core logic and registers the command. In plugins/ping.lua, the function accesses parameters through app.params and returns a string:

function ping_host()
    local target = app.params["target"]
    if not target then
        return "Error: 'target' parameter missing."
    end

    local cmd = "ping -c 1 " .. target
    local result = io.popen(cmd):read("*a")
    return result
end

register_command("ping_host", ping_host)

Step 2: Create the Matching YAML File

The descriptor plugins/ping.yaml must share the same base name (ping) and define the metadata:

name: ping_host
description: >
  Sends a single ICMP ping to the supplied target and returns the raw output.
author: "LazyOwn RedTeam"
version: "1.0"
enabled: true
tags:
  - network
  - recon
params:
  - name: target
    description: IP address or hostname to ping
    required: true
permissions:
  - needs_file_read
requires_root: false
dependencies: []
outputs:
  - console_output
notes: >
  Useful for quick reachability checks during a penetration test.

Step 3: Validate and Test

After placing both files in the plugins/ directory, launch LazyOwn and execute:

lazyown ping_host --target 8.8.8.8

The framework validates the needs_file_read permission, loads ping.lua, and prints the command output.

Real-World Reference: Complex Payload Generation

For advanced use cases, examine the existing generate_reverse_shell implementation in the repository. The Lua logic in plugins/generate_reverse_shell.lua handles parameter parsing and payload construction, while plugins/generate_reverse_shell.yaml declares multiple parameters (lhost, lport) and binary output types. This pattern demonstrates how to handle complex inputs and declare external tool dependencies in the YAML descriptor.

Summary

  • LazyOwn uses paired files: Every addon requires a Lua implementation and a YAML descriptor with matching base names in plugins/.
  • YAML drives the framework: The descriptor controls auto-discovery via utils.load_plugins(), permission validation, and CLI exposure through register_command().
  • Security is declarative: Fields like permissions, requires_root, and dependencies allow LazyOwn to validate system capabilities before executing foreign code.
  • Documentation is automatic: The framework generates plugins/README.md directly from YAML metadata fields.

Frequently Asked Questions

What file naming convention must I follow for LazyOwn addons?

The Lua file and YAML descriptor must share identical base names (e.g., myaddon.lua and myaddon.yaml) and reside in the plugins/ directory. LazyOwn pairs these files automatically based on the basename during the discovery phase.

Can I create addons that require root privileges?

Yes. Set requires_root: true in the YAML descriptor and include appropriate permission flags like needs_file_write or needs_network. The framework checks these declarations before invoking the Lua function to ensure the execution context meets security requirements.

How does LazyOwn handle missing dependencies?

The dependencies field in the YAML descriptor lists required external tools or Python packages. While the analysis shows this field is parsed during plugin registration, you should verify that any declared binaries exist on the target system, as the framework uses this metadata for pre-execution validation.

Where can I find a template to start building addons?

The repository includes plugins/01 - template_plugins_yaml.yaml, which provides the minimal skeleton structure required for valid descriptors. Additionally, plugins/README.md contains the official development guide and checklist for creating compliant addons.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →