# How to Customize Scan Profiles in user-scanner: A Complete Pattern Syntax Guide

> Customize user-scanner scan profiles using pattern syntax with square brackets, curly braces, and backslashes. Learn the complete syntax for powerful custom scans.

- Repository: [Kaif/user-scanner](https://github.com/kaifcodec/user-scanner)
- Tags: how-to-guide
- Published: 2026-08-30

---

**To customize scan profiles in user-scanner, construct a pattern string using square brackets for character sets, curly braces for length repetition, and backslashes for literal escaping, then supply it via the `-p` CLI flag or the `expand_patterns()` API.**

The `kaifcodec/user-scanner` repository implements a domain-specific pattern language that defines which usernames or handles to probe during reconnaissance. By mastering this syntax, you can customize scan profiles to target specific naming conventions, ranges, or character subsets without modifying the core engine code.

## Understanding the Pattern Engine Architecture

`user-scanner` processes every scan profile through a four-stage pipeline implemented in [`user_scanner/core/patterns.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/patterns.py). When you supply a pattern, the tool executes these steps:

1. **Lexical analysis** – The `Lexer` class tokenizes the raw pattern string (`user_scanner/core/patterns.py:L16-L29`).
2. **Parsing** – The `_parse_patterns` function converts tokens into a list of blocks, representing either plain strings or `PatternBlock` objects that contain character sets and length sets (`L23-L52`).
3. **Expansion** – The `expand_patterns` function iterates through blocks to yield every possible username combination (`L78-L93`). This generator feeds directly into the HTTP request scheduler.
4. **Counting** – The `count_patterns` function calculates total permutations beforehand (`L25-L38`), enabling the CLI to display progress indicators like "Scanning X of Y permutations."

The engine consumes these expanded strings via [`user_scanner/core/engine.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/engine.py), which creates a **Job** for each handle and respects global flags such as concurrency (`-C`), timeout (`-t`), and `--allow-loud` as documented in [`docs/FLAGS.md`](https://github.com/kaifcodec/user-scanner/blob/main/docs/FLAGS.md).

## Core Pattern Syntax for Custom Profiles

A scan profile is simply a pattern string that supports three primary customization mechanisms:

### Character Sets (Square Brackets)

Define allowed characters at specific positions using square brackets. Ranges like `a-z` or `0-9` are expanded internally by the `_char_range` helper.

- **`[a-c]`** expands to `a`, `b`, `c`
- **`john[a-c]`** generates `johna`, `johnb`, `johnc`

### Length Control (Curly Braces)

Attach a length set to a character set to control repetition. The parser builds a `lenset` (e.g., `{0-2}` translates to lengths 0, 1, and 2).

- **`[0-9]{2}`** requires exactly two digits
- **`john[0-9]{0-2}`** produces `john`, `john0` through `john9`, and `john00` through `john99`

### Escaping Special Characters

Prepend a backslash to treat `[`, `]`, or `\` literally in your pattern.

- **`\\[`** produces the literal character `[`
- **`"hello\\[world\\]"`** generates exactly `hello[world]`

## Implementing Custom Scan Profiles

You can deploy custom profiles through either the command-line interface or the Python library.

### CLI Method

Pass your pattern directly using the `-p` or `--pattern` flag defined in [`user_scanner/__main__.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/__main__.py):

```bash
user-scanner -p "admin[0-9]{0-2}" -t 5 -C 10

```

This command scans `admin`, `admin0` through `admin99`, using a 5-second timeout and 10 concurrent workers.

### Python API Method

For programmatic control, import the expansion utilities and engine directly:

```python
from user_scanner.core.engine import Engine
from user_scanner.core.patterns import expand_patterns

# Define a profile checking john0-john9 and jane[a-c]

profile = "john[0-9]{1} jane[a-c]"

# Generate handles manually (or let Engine handle expansion internally)

handles = list(expand_patterns(profile))

engine = Engine()
results = engine.scan(handles)  # Returns iterator of Result objects

for r in results:
    print(r.handle, r.status, r.extra)

```

### Counting Permutations Before Scanning

Use `count_patterns` to preview scan scope:

```bash
python -c "import user_scanner.core.patterns as p; print(p.count_patterns('user[0-9]{3}'))"

```

Output: `1000`

This confirms the scan will generate exactly 1,000 usernames before consuming bandwidth.

## How the Engine Processes Your Profile

Once expanded, the list of handles flows into [`user_scanner/core/engine.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/engine.py), where each string becomes a **Job** instance. The engine respects your CLI flags for rate limiting and timeout configurations, then outputs structured `Result` objects defined in [`user_scanner/core/result.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/result.py). The entire pipeline—from pattern parsing in [`user_scanner/core/patterns.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/patterns.py) to final status reporting—operates as a lazy iterator, ensuring memory efficiency even when your custom profile generates millions of permutations.

## Summary

- **Pattern strings** are the core mechanism to customize scan profiles in `user-scanner`, parsed by the `Lexer` and `_parse_patterns` functions in [`user_scanner/core/patterns.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/patterns.py).
- **Square brackets** define character sets, **curly braces** control repetition length, and **backslashes** escape special characters.
- Use `expand_patterns()` to generate handles programmatically or the `-p` CLI flag for direct execution.
- Call `count_patterns()` before scanning to predict total permutation counts and resource requirements.
- The engine processes expanded handles via [`user_scanner/core/engine.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/engine.py), creating Job instances that respect global concurrency and timeout flags.

## Frequently Asked Questions

### What is the pattern syntax for user-scanner scan profiles?

Scan profiles use a custom DSL where square brackets define character sets (e.g., `[a-z]`), curly braces specify repetition counts (e.g., `{2}`), and backslashes escape literal characters. This syntax is parsed by classes in [`user_scanner/core/patterns.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/patterns.py) and fully documented in the repository's [`docs/PATTERNS.md`](https://github.com/kaifcodec/user-scanner/blob/main/docs/PATTERNS.md).

### How do I count how many usernames a pattern will generate?

Import `count_patterns` from `user_scanner.core.patterns` and pass your pattern string. This function, implemented between lines 25-38 of [`user_scanner/core/patterns.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/patterns.py), calculates the Cartesian product of all character and length sets without expanding them into memory.

### Can I use multiple character sets in a single pattern?

Yes. The `_parse_patterns` function (lines 23-52) tokenizes complex patterns containing multiple blocks. For example, `"admin[0-9][a-c]{2}"` combines numeric and alphabetic sets with length control, generating combinations like `admin0aa`, `admin0ab`, through `admin9cc`.

### Where does user-scanner process the pattern string internally?

The pattern string enters the pipeline in [`user_scanner/core/patterns.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/patterns.py), where the `Lexer` class performs tokenization (lines 16-29) and `_parse_patterns` builds block representations. The expanded results then flow to [`user_scanner/core/engine.py`](https://github.com/kaifcodec/user-scanner/blob/main/user_scanner/core/engine.py), which orchestrates the actual HTTP scanning via the `Engine` class.