CLI Apps

How Noir maps the command-line attack surface of CLI applications — subcommands, flags, positional arguments, and consumed environment variables — across 21 languages.

Beyond web frameworks and API specifications, Noir extracts the command-line interface of CLI applications as endpoints. A CLI program's argument parser is an attack surface too: externally supplied flags, positional arguments, and environment variables flow into the program and can reach a shell, an SQL query, a file path, or a network call.

Noir models each (sub)command as an endpoint and records the inputs that command accepts.

Endpoint model

CLI entry points are endpoints with method = "CLI" and protocol = "cli". The URL addresses the command:

URL shape meaning
cli://<binary> the root command (the program invoked with no subcommand)
cli://<binary>/<subcommand> a subcommand (git commit, tool serve, …)

The binary name comes from the project manifest when one is present (go.mod, Cargo.toml, package.json bin/name, *.csproj, argparse(prog=...), …); otherwise it falls back to the source file / directory name.

Inputs are parameters, distinguished by param_type:

param_type meaning example
flag a named option / switch --port, -v, --config
argument a positional argument arg1, source, files
env an environment variable the command reads API_TOKEN, DATABASE_URL

In plain output these render under flags / arguments / env sections:

CLI cli://mytool/serve
  ○ flags: port, verbose
  ○ arguments: config
  ○ env: API_TOKEN

Supported languages and libraries

Noir detects the built-in argv / flag / environment mechanisms of each language plus its major CLI libraries. Raw environment reads are gated: they are only surfaced for genuine CLI entry points, so a web server that reads config from the environment does not leak spurious cli:// endpoints.

Language Built-in Libraries
Go os.Args, flag, os.Getenv/LookupEnv cobra (+ viper env), urfave/cli, pflag, go-arg, go-flags
Python sys.argv, argparse, getopt, os.environ/getenv click, typer, fire, docopt
Rust std::env::args/var clap (derive), structopt, argh
JavaScript / TypeScript process.argv, util.parseArgs, Deno.args, Bun.argv, process.env commander, yargs, cac, meow, minimist
Ruby ARGV, OptionParser, ENV Thor, GLI, Slop, TTY::Option, commander
C# / F# Main(string[]), GetCommandLineArgs, GetEnvironmentVariable System.CommandLine, CommandLineParser, CliFx, Spectre.Console.Cli
Java main(String[]), System.getenv picocli, args4j, JCommander, commons-cli, airline
Kotlin main(Array<String>), System.getenv clikt (+ envvar), kotlinx-cli
PHP $argv, getopt(), $_ENV, getenv() Symfony Console, CLImate, Minicli
C++ main(argc, argv), getenv CLI11, getopt/getopt_long, cxxopts, boost::program_options, gflags
Swift CommandLine.arguments, ProcessInfo.environment swift-argument-parser
Crystal ARGV, OptionParser, ENV clim, admiral, commander
Elixir System.argv, OptionParser, System.get_env (stdlib)
Dart main(List<String>), Platform.environment args (ArgParser / CommandRunner), dcli
Haskell getArgs, getEnv/lookupEnv optparse-applicative
Scala args, sys.env scopt, decline
Zig std.process.args, getEnvVarOwned zig-clap, zig-cli
Clojure *command-line-args*, System/getenv clojure.tools.cli, cli-matic
Lua arg, os.getenv argparse
Perl @ARGV, Getopt::Long/Getopt::Std, %ENV (stdlib)
Groovy args, System.getenv CliBuilder, picocli

Output behavior

CLI endpoints stay in the structured inventory — JSON, JSONL, YAML, TOML, SARIF, Markdown, mermaid, HTML — because they are part of the application's surface. They are excluded from HTTP-shaped output and delivery — cURL, HTTPie, PowerShell, OpenAPI 2.0 / 3.0, Postman, and active probe / proxy delivery — because a command invocation is not an HTTP request you send. The HUNT tagger, which classifies HTTP parameter vulnerabilities, also skips CLI inputs.

Notes and limitations

  • Detection is line-scan based (no full parse), so deeply nested or heavily metaprogrammed command trees may be partially resolved. Flags, arguments, and env reads scattered across files are merged onto one command by URL.
  • Some builder-style APIs are recognized as a CLI signal but not fully parsed into individual arguments (e.g. the clap builder API in Rust); the derive/annotation styles are parsed in full.
  • Subcommands are flattened to a single level (cli://tool/serve); deeper nesting is not yet modeled.