# How VulnClaw's TUI Workbench Validates Testing Scope Boundaries

> Learn how VulnClaw's TUI workbench validates testing scope boundaries using a three-layer system that parses user input, normalizes actions, and re-validates through the CLI for secure execution.

- Repository: [Unclecheng/VulnClaw](https://github.com/Unclecheng-li/VulnClaw)
- Tags: how-to-guide
- Published: 2026-06-30

---

**VulnClaw's TUI workbench validates testing scope boundaries through a three-layer validation system that parses user input via the `/scope` command, normalizes action lists and port ranges, applies mode-specific defaults, and re-validates through the CLI parser before execution.**

The Unclecheng-li/VulnClaw repository implements a defensive validation pipeline that prevents out-of-bounds targets or dangerous action combinations from reaching the penetration testing engine. This scope validation is centralized in the `TuiState` object and enforced through interactive parsing, mode-aware defaults, and CLI-level re-validation.

## Three-Layer Validation Architecture

VulnClaw's validation operates at three distinct layers to ensure testing scope boundaries are never violated during task execution.

### Interactive Input Parsing and Normalization

When an operator issues the `/scope` slash command, the TUI initiates a prompt-state machine that collects and validates fields before they enter the system state.

The `_cmd_scope` handler (lines 79-94 in [`vulnclaw/cli/tui.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/tui.py)) builds a list of scope fields including `target`, `only_host`, `only_port`, `blocked_host`, `blocked_path`, `allow_actions`, and `block_actions`. Each user response routes through `_handle_prompt_response`, which dispatches to specialized parsers:

- **Port validation**: The `_parse_optional_port` function (lines 629-638) converts input to an integer and enforces the range **1-65535**, raising `ValueError(_("tui.error_invalid_port"))` for out-of-bounds values.
- **Action list normalization**: The `_parse_action_csv` function (lines 221-226) splits comma-separated strings, trims whitespace, and filters empty items to guarantee a clean `list[str]`.

### Mode-Aware Default Application

If the operator leaves action lists empty, the TUI automatically applies safety defaults based on the selected `TuiMode` (quick, standard, deep, or continuous).

The `_effective_allow_actions` and `_effective_block_actions` methods (lines 613-618 in [`vulnclaw/cli/tui.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/tui.py)) query the mode configuration from [`vulnclaw/config/settings.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/config/settings.py). For example, `quick` mode defaults to `allow_actions=("recon",)` and `block_actions=("exploit", "persistent", "post_exploitation")`, ensuring high-risk actions are blocked even when the user specifies nothing.

### CLI-Level Re-Validation

Before launching any task, the TUI constructs a `TuiTaskDraft` via `_draft_from_state` (lines 442-456), which consolidates validated scope data into CLI arguments. When the user executes `/run` or presses **Start**, the `_cmd_start` handler triggers `_do_launch` (lines 331-349), passing the draft to the CLI runner in [`vulnclaw/cli/main.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/main.py).

The CLI entry point re-applies the same validation constraints independently, ensuring that bypassing the TUI (or manually editing generated commands) cannot violate scope boundaries.

## Core Validation Logic in vulnclaw/cli/tui.py

The primary validation implementation resides in [`vulnclaw/cli/tui.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/tui.py), where state management and boundary checking are tightly coupled.

**State Storage**: The `TuiState` dataclass maintains the canonical scope definition, tracking `target`, `only_*` filters, `blocked_*` exclusions, and action allow-lists/block-lists.

**Draft Generation**: The `_draft_from_state` function transforms the validated state into a `TuiTaskDraft` object, which `build_command_preview_args` converts into executable command-line strings. This draft serves as the immutable boundary specification passed to the execution engine.

**Error Handling**: All user-facing validation errors reference translation keys in [`vulnclaw/i18n/en.json`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/i18n/en.json) (and [`zh.json`](https://github.com/Unclecheng-li/VulnClaw/blob/main/zh.json)), such as `tui.error_invalid_port`, ensuring consistent localized feedback when boundaries are violated.

## Practical Usage Examples

### Setting a Valid Custom Scope

```text
/scope host=example.com port=443 allow=recon,scan block=exploit

```

- The `_cmd_scope` handler parses key-value pairs through `_parse_scope_args`.
- `port=443` passes `_parse_optional_port` validation (within 1-65535).
- `allow=recon,scan` and `block=exploit` are normalized by `_parse_action_csv` into clean lists.

The dashboard displays the effective actions:

```text
Allowed actions: recon, scan
Blocked actions: exploit

```

### Using Quick Mode Defaults

```text
/mode quick
/run

```

- The `quick` mode defines `allow_actions=("recon",)` and `block_actions=("exploit", "persistent", "post_exploitation")` in `TuiMode`.
- `_effective_allow_actions` and `_effective_block_actions` inject these defaults when the user omits explicit values.

The generated command preview becomes:

```bash
vulnclaw recon <target> --only-host example.com --only-port 443 --allow-actions recon --block-actions exploit,persistent,post_exploitation

```

### Handling Invalid Port Input

```text
/scope port=99999

```

- `_parse_optional_port` raises `ValueError` with the translated message `tui.error_invalid_port`.
- The TUI displays "Invalid port number" and prompts the user to retry, preventing the out-of-bounds value from entering `TuiState`.

### Inspecting the Command Draft Programmatically

```python
from vulnclaw.cli.tui import build_task_draft, build_state_from_options

state = build_state_from_options(
    target="10.0.0.5",
    mode="deep",
    only_host="10.0.0.5",
    only_port="443",
    allow_actions="recon,scan",
)
draft = build_task_draft(state)
print(draft.command_line)

# Output: vulnclaw scan 10.0.0.5 --only-host 10.0.0.5 --only-port 443 --allow-actions recon,scan

```

## Summary

- **Interactive validation** occurs immediately during `/scope` input parsing, enforcing valid port ranges (1-65535) and normalized action lists via `_parse_optional_port` and `_parse_action_csv`.
- **Mode-aware defaults** automatically populate empty allow/block action lists from `TuiMode` configurations (quick, standard, deep, continuous) through `_effective_allow_actions` and `_effective_block_actions`.
- **CLI re-validation** ensures the `TuiTaskDraft` created by `_draft_from_state` is checked again by [`vulnclaw/cli/main.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/main.py) before execution, preventing scope bypasses.
- **Localized error reporting** uses translation keys like `tui.error_invalid_port` stored in [`vulnclaw/i18n/en.json`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/i18n/en.json) to provide immediate feedback on boundary violations.

## Frequently Asked Questions

### How does VulnClaw validate port numbers entered in the TUI?

VulnClaw validates ports through the `_parse_optional_port` function in [`vulnclaw/cli/tui.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/tui.py) (lines 629-638). This function attempts to convert the input string to an integer and verifies it falls within the valid TCP/UDP port range of 1 to 65535. If the value is outside this range or not a valid integer, the function raises a `ValueError` with the translation key `tui.error_invalid_port`, which the TUI renders as a localized error message prompting the user to correct the input.

### What happens if I don't specify allow_actions or block_actions when setting scope?

When action lists are omitted, the TUI applies default values based on the currently selected `TuiMode` (quick, standard, deep, or continuous). The `_effective_allow_actions` and `_effective_block_actions` methods (lines 613-618) retrieve the appropriate defaults from the mode configuration in [`vulnclaw/config/settings.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/config/settings.py). For instance, `quick` mode automatically blocks high-risk actions like `exploit` and `persistent` while allowing only `recon`, ensuring safe defaults even without explicit user input.

### Can the TUI validation be bypassed by running VulnClaw commands directly?

No, the validation cannot be bypassed because the CLI entry point in [`vulnclaw/cli/main.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/main.py) re-applies the same scope validation constraints independently of the TUI. When the TUI launches a task via `_do_launch`, it passes a `TuiTaskDraft` to the CLI runner, which re-parses and validates all arguments—including targets, ports, and actions—before executing the penetration testing job. This dual-layer validation ensures consistency whether the operator uses the interactive workbench or command-line interface.

### Where are the error messages for validation failures defined?

All user-facing validation error messages are defined in the internationalization files located at [`vulnclaw/i18n/en.json`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/i18n/en.json) and [`zh.json`](https://github.com/Unclecheng-li/VulnClaw/blob/main/zh.json). The TUI references these messages via translation keys such as `tui.error_invalid_port` and `tui.invalid_choice`. When validation fails in functions like `_parse_optional_port`, the code raises exceptions with these keys, which the Textual UI front-end ([`vulnclaw/cli/tui_textual.py`](https://github.com/Unclecheng-li/VulnClaw/blob/main/vulnclaw/cli/tui_textual.py)) renders into the user's selected language.