This file is the working guide for coding agents in this repository. The goal is to make safe, accurate changes to the current Rust v3 Dalfox codebase.
Scope:
src/runtime logic (CLI, scanning engine, server API, MCP)tests/validation- config/default behavior consistency
skills/dalfox/— agent skill bundle (SKILL.md + references/) that must stay aligned with AGENTS.md invariants and code behavior
- Language: Rust (
edition = "2024") - Runtime:
tokio - CLI:
clap - HTTP:
reqwest - Server/API:
axum - MCP:
rmcp - AST/DOM analysis:
oxc_*crates
Primary modules:
src/main.rs: CLI entrypoint, global flags, config load/init, subcommand dispatchsrc/cmd/scan/: scan command, split into focused submodules —mod.rs(run_scanorchestrator +ScanArgs-independent glue),args.rs(ScanArgs+ default/cap constants + value parsers),validation.rs,preflight.rs,input.rs(target resolution),analysis.rs(preflight/param loop),scan_loop.rs(scanning loop),output.rs(dry-run/only-discovery/result rendering),poc.rs,postprocess.rs,logging.rssrc/cmd/mod.rs: sharederror_codesconstants +JobStatusenum (used by server + MCP)src/config.rs: config schema + precedence (apply_to_scan_args_if_default)src/scanning/: reflection/DOM checks, AST integration, payload execution pipeline, result modelssrc/parameter_analysis/: discovery + mining + parameter filteringsrc/payload/: canonical payloads, dynamic payload generation, remote providerssrc/encoding/: payload encoding pipeline (apply_encoders_to_payloads) + pre-encoding detectionsrc/target_parser/: URL/file/raw-HTTP target normalizationsrc/waf/: WAF fingerprinting + bypass strategiessrc/utils/: shared CLI helpers (banner, color, logging)src/cmd/server.rs: async scan API server + CORS/JSONP/API-key logicsrc/cmd/job.rs: shared async job lifecycle + progress + bounds validation (used by server + MCP)src/mcp/mod.rs: MCP stdio tool server (scan_with_dalfox,get_results_dalfox,list_scans_dalfox,cancel_scan_dalfox,delete_scan_dalfox,preflight_dalfox)
Top-level commands:
scanserverpayloadmcp- hidden compatibility commands:
url,file,pipe
Behavioral default:
- No subcommand => defaults to
scaninsrc/main.rs. - Banner is suppressed automatically for
mcpand for machine-readable formats (json,jsonl,sarif,toml) so stdout stays parseable.
CLI exit codes (ScanOutcome in src/cmd/scan/mod.rs):
0Clean — scan finished, no findings1Findings — scan finished, one or more findings2Error — input/configuration/runtime error
- Keep CLI/default constants centralized.
- Source of truth:
src/cmd/scan/args.rs(re-exported fromsrc/cmd/scan/mod.rs) - Examples:
DEFAULT_TIMEOUT_SECS,DEFAULT_WORKERS,DEFAULT_ENCODERS,DEFAULT_METHOD,DEFAULT_DELAY_MS,DEFAULT_MAX_CONCURRENT_TARGETS,DEFAULT_MAX_TARGETS_PER_HOST,DEFAULT_WAF_MIN_CONFIDENCE - CLI sanity caps also live here:
CLI_MAX_TIMEOUT_SECS,CLI_MAX_DELAY_MS,CLI_MAX_WORKERS - If a default changes, align all call sites that compare against defaults.
- Preserve config precedence semantics.
- Config application for scan path uses
Config::apply_to_scan_args_if_default. - CLI should win over config.
- When adding fields, update both:
- struct fields in
ScanConfig - mapping in
apply_to_scan_args_if_default
- struct fields in
- Preserve output contract.
- Output formats currently include:
plain,json,jsonl,markdown,sarif,toml. - Keep serialization behavior in
src/scanning/result.rsaligned with output routing insrc/cmd/scan/output.rs. include_requestandinclude_responseflags must remain opt-in.--include-allis a convenience that sets both (resolved insrc/main.rsbeforerun_scan).- JSON/JSONL envelope
metaincludestarget_summary(per-target status/findings/error_code). - All findings include
type_descriptionalongside the single-lettertypecode. --dry-runoutputs a preflight summary instead of scan results.- POC output type (
--poc-type):plain,curl,httpie,http-request.
- Respect concurrency boundaries.
- Scan pipeline uses worker and semaphore limits (
workers,max_concurrent_targets,max_targets_per_host). - Do not introduce unbounded async fan-out.
- Keep server and MCP behavior non-breaking.
- Server jobs are in-memory, async, and status-based (
queued/running/done/error/cancelled). - MCP is stdio/JSON-RPC; avoid stdout noise in MCP mode (banner/log behavior matters).
- Both server and MCP support real cancellation via
AtomicBoolflags checked in scan loops. - Both include progress tracking (params_total/tested, requests_sent, findings_so_far).
- Use shared error codes from
cmd::error_codesfor application-level errors.
- Remote resource initialization is process-cached.
- Remote payload/wordlist fetches use OnceLock cache.
- New behavior should remain idempotent in-process.
- Parse/normalize targets (
target_parser) - Optional preflight content-type/CSP check
- Parameter discovery + mining (
parameter_analysis) - Reflection + DOM + AST-assisted checks (
scanning) - Result aggregation
- Format-specific output rendering
-
New scan flag:
src/cmd/scan/args.rs: add the field toScanArgsand its default toimpl Default for ScanArgs. Construction sites use..Default::default(), so these two edits are all the plumbing there is — do not re-add exhaustive field lists at call sites.scanargs_default_matches_clap_defaultsfails if theDefaultentry disagrees with thedefault_valueyou declared.- behavior in
src/cmd/scan/mod.rs(run_scan) src/config.rs(ScanConfig, template, precedence mapping)- If relevant:
src/cmd/server.rsScanOptions - If relevant:
src/mcp/mod.rstool args parsing - Note:
--state-file's config hash coversScanArgsas a whole (a denylist over itsDebugrepr,cmd::scan::state_file::config_hash), so any new field changes the hash and resets existing state files on upgrade. That is the safe direction — never add a field to the neutralized list unless it genuinely cannot change what a completed target was tested with.
-
New payload primitive:
src/payload/xss_javascript.rs(canonical source)- Derived payload logic in
xss_html.rs/xss_event.rs - verify generation path in
src/scanning/xss_common.rs
-
New encoder:
src/encoding/mod.rs- encoder policy application path (
apply_encoders_to_payloads) - path PoC encoder logic in
src/cmd/scan/poc.rs(GLOBAL_ENCODERSusage) - CLI help/docs and tests
-
New output format:
- conversion in
src/scanning/result.rs - dispatch branch in
src/cmd/scan/output.rs - integration tests under
tests/integration/
- conversion in
-
Server API behavior:
src/cmd/server.rs(auth, CORS, JSONP, scan options mapping)- keep callback validation strict for JSONP
- Endpoints (axum path syntax
{id}):POST /scan— submit a scanGET /scan— submit via query params (JSONP-friendly)GET /scan/{id}— status + resultsDELETE /scan/{id}— cancelGET /scans— list jobsGET /result/{id}— alias ofGET /scan/{id}POST /preflight— parameter discovery onlyGET /health— health check
-
MCP tool behavior:
src/mcp/mod.rs- keep tool inputs minimal and deterministic
- Tools:
scan_with_dalfox,get_results_dalfox,list_scans_dalfox,cancel_scan_dalfox,delete_scan_dalfox,preflight_dalfox cancel_*flips the cancellation flag (job ends incancelled);delete_*removes the job record entirely.
-
New error code:
- Add constant to
src/cmd/mod.rserror_codesmodule - Use the constant in all three interfaces (CLI, server, MCP) plus the agent skill bundle (
skills/dalfox/references/results.md) - Existing codes:
NO_TARGETS,NO_FILE,INVALID_INPUT_TYPE,PARSE_ERROR,FILE_READ_ERROR,STDIN_ERROR,STDIN_NOT_PIPED,INPUT_TOO_LARGE,CONNECTION_FAILED,DNS_RESOLUTION_FAILED,TLS_HANDSHAKE_FAILED,REQUEST_TIMEOUT,CONTENT_TYPE_MISMATCH,TRUNCATED_PER_HOST_CAP
- Add constant to
Fast local loop:
cargo test
Broader validation:
cargo test -- --include-ignoredcargo test -- --nocapture
Targeted suites:
- unit + module-level tests in
src/**(#[cfg(test)]) - crate-level unit tests:
tests/unit/(encoding, target_parser, utils) - integration tests:
tests/integration/(markdown/sarif output, scanner pipeline) - functional mock-server tests:
tests/functional/(driven bytests/functional/mock_cases/) - e2e smoke:
tests/e2e/cli_smoke_test.rs,tests/e2e/config_path_smoke_test.rs - standalone harnesses:
tests/remote_payload_builder_test.rs,tests/remote_wordlist_builder_test.rs,tests/request_count_probe.rs,tests/scan_run_paths_test.rs
Handy task aliases (from justfile):
just test(aliasjust t) —cargo testjust test_all—cargo test -- --include-ignoredjust dev(aliasjust d) — debug buildjust build(aliasjust b) — release buildjust version-check(aliasjust vc) /just version-update(aliasjust vu) — keep version in lockstep acrossCargo.toml,Cargo.lock,flake.nix, snapjust docs-serve(aliasjust ds) — serve the docs site locally via hwarojust docs-dependencies— install docs tooling (hwaro) on macOSjust nix-update— update the Nix flake lockfile
When behavior changes, add or update tests near the touched module plus one higher-level test when the change crosses module boundaries.
Before finishing a change, verify:
- CLI/config consistency
- New or changed scan option is reflected in
ScanArgs, config mapping, and default path.
- Output compatibility
- Existing formats still render and parse as expected.
- Concurrency stability
- No new unbounded tasks or shared-state races.
- Request/response privacy controls
- Detailed request/response output only appears when explicitly requested.
- Tests
- Relevant tests pass locally for touched area.
- Prefer minimal, localized edits over broad refactors.
- Keep public behavior stable unless change explicitly requires a breaking shift.
- Reuse existing helpers (encoding/payload/target parsing) before adding new abstractions.
- Avoid
unwrap()in runtime paths where user input or network I/O is involved. - Keep logs user-readable in CLI mode and protocol-safe in MCP mode.
- The
skills/dalfox/bundle (SKILL.md + references/*.md) is published for agent consumers and must be updated when CLI flags, MCP tool schemas, error codes, or core invariants change.
If code and docs diverge, treat code as source of truth and update docs in the same change.