Documentation

Platforms & Operations

Android is Rutken's flagship target, but the same analysis layer reaches Linux ELF binaries, container images, and CI/CD pipeline definitions — with Windows PE actively building and macOS (Mach-O) on the roadmap — and the engine ships several ways to operate it: a terminal CLI, a localhost REST API, a desktop GUI, and device-backed dynamic analysis. This page is the end-to-end CLI reference for each of those operational surfaces. For install, the quickstart, and editions, see the main docs.

Install & editions

Everything on this page runs from the same single binary you install once with the launcher. If you haven't installed Rutken yet, follow the install section in the main docs, then come back here. In short:

curl -fsSL https://www.rutken.com/install.sh | bash
rutken --help

Rutken ships as one engine with capability tiers on top. Community (free) is the full static analysis (SAST) pipeline plus SCA/CVE matching and a taste of live capture. Several surfaces on this page sit behind paid-tier Cargo features that are compiled into the distributed builds for the relevant editions — notably the REST API (rest-api), the device capture/intervene verbs (intercept / unpinned-capture / offense), and the bespoke hooking engine (bespoke-agent). The editions section explains what each tier is for; the pricing page lists the plans. This page describes the commands, not who can run them.

Two commands answer "what can I run, and against what?":

# every verb and its flags
rutken <target> <verb> --help

# the machine-checked verb-vs-target support matrix
rutken capabilities --format json

Several runtime verbs change a live app's behavior and are gated behind explicit, verbatim authorization phrases plus a target-hash match — they fail closed (exit 2) without them. Only operate against targets you own or are explicitly authorized to test.

Containers — image scan

rutken image scan scans a container image offline: either an OCI layout directory or a docker save tarball, auto-detected. It takes no APK argument (it's a top-level, pre-dispatched verb like sca update), and it reuses every existing report renderer — no new output format to learn.

# save a running image to a tarball, then scan it
docker save my-image:latest -o image.tar
rutken image scan ./image.tar --fail-on high

What it looks at

Two independent finding sources are always combined into one report:

  • Container rule pack (the container rule pack, 11 rules): an image-only config pack (root user, missing healthcheck, broad exposed port, credential-shaped env var, leftover package-manager cache), a per-layer secret pack, an opt-in Dockerfile pack (--dockerfile <path>), and a coverage rule that renders every scan limitation as an Info finding — an unscanned image is never reported "clean."
  • OS-package vulnerability matching: reads dpkg/apk inventories off the squashed image view and matches them against the same locally cached dataset rutken sca update manages, using identical --db/--cache-dir/ --auto-update/--max-age-days flags. Disable with --no-packages.

Key flags

  • --dockerfile <path> — unlock the Dockerfile rule pack (absence of a Dockerfile is recorded as a coverage limitation, never a pass).
  • --framework cis-docker — render the scan as a CIS Docker Benchmark v1.7.0 assessment (control-id mapped; text/json only).
  • --format — text (default), json, sarif, markdown, html, pdf, gitlab-codequality, junit.
  • --only <id> / --skip <id> — select container rule ids (mutually exclusive; neither affects the SCA presence finding).
  • --fail-on <severity> — CI gating; exit 2 when tripped.
  • --list-rules — print the registered catalog instead of scanning.

Examples

rutken image scan ./my-image-oci-layout --no-packages
rutken image scan ./image.tar --dockerfile ./Dockerfile --format json
rutken image scan ./image.tar --db datasets/sample-os-package-advisories \
    --cache-dir ./.rutken-cache --auto-update --fail-on high
rutken image scan ./image.tar --framework cis-docker --format json

Expected output & exit codes

stdout (or --out <path>) contains only the rendered report. Dataset provenance (version, cache age, skipped records) and the coverage-limitation count always go to stderr — same discipline as rutken <apk> sca. Exit 0 is a clean scan (including zero findings), 1 an operational error (not a valid image, empty dataset cache with packages enabled, failed fetch, write failure), and 2 a tripped --fail-on gate.

Local image sources only — there is no registry pull. The dpkg/apk version comparator refuses -/+ version strings, so most OS-package matches land as exact-version but Low severity rather than range-confirmed. The checked-in sample dataset is illustrative only (a few hand-picked real CVE ids), not an authoritative feed.

Multi-platform parity

Android is the flagship — the deepest, most battle-tested surface — and the other platforms are real but deliberately not at that proof depth. The one architectural principle that makes this work: every layer above the rule engine is written against a single finding model, so a finding from any branch flows through the same compliance, correlation, reporting, and gating machinery.

Platform status

  • Flagship Android (APK/DEX) — the complete pipeline, from parsing through taint, call-graph chains, compliance, and remediation PRs, out to the full verb surface, every report format, the REST API, the GUI, and MCP.
  • Actively building Linux/ELF — a real vertical slice: parse → native IR → rule packs → runtime → capture → patch → correlation. Supports info, rules, compliance, sca, patch, run, verify, correlate, serve, and mcp. The analysis foundation is section flags and symbol tables rather than full instruction semantics (lifting is a separate, AArch64-first effort).
  • Actively building Container and CI/CD — each is one scanning verb (image scan, cicd scan) that emits findings and stops; both are complete within their own scope. They also expose serve/mcp; run/verify/correlate are permanently not-applicable — a saved image and a pipeline definition are static targets with nothing to observe at runtime.
  • Actively building Windows/PE — PE binary analysis shares the native pipeline and verb surface; the full workspace compiles today and validation is underway. It does not yet carry Android's proof depth.
  • Coming soon macOS/Mach-O — on the roadmap. A Mach-O target is recognized today but deliberately fail-closed.

The sniffer routes any non-APK file to the native pipeline automatically, so on supported targets the same verbs just work:

# native binary — functions/CFG recovered so linkage rules are reachability-qualified
rutken libfoo.so rules --lift --format json

# same verb surface across native kinds (the dispatcher never branches on file kind)
rutken libfoo.so rules --format sarif

# CI/CD pipeline definitions (GitHub Actions / GitLab CI / Azure Pipelines)
rutken cicd scan .github/workflows --fail-on medium

APK-only flags (interprocedural analysis, chains, signature verification) are rejected with a named error on native targets rather than silently ignored, and a tripped lifting budget yields a partial result with the uncovered area recorded, never a hard error.

Compliance framework by target — SSDF vs CIS

The compliance axis resolves to a different standard per branch, and one of them carries a licensing constraint worth knowing:

  • Android — MASVS and CERT-In.
  • Native binaries (ELF, and PE as it lands) — NIST SP 800-218 (SSDF). The build-hardening controls (PW.6) are exactly what Rutken's -no-pie/-no-aslr/-no-dep/-relro-weak rule families evidence. Run it as a verb: rutken libfoo.so compliance --framework ssdf.
  • Container images — CIS Docker Benchmark v1.7.0, as a rollup flag on the scan: rutken image scan ... --framework cis-docker.
  • CI/CD — SLSA v1.0 plus SSDF, likewise a rollup flag on cicd scan.

The framing difference is not cosmetic. SSDF (public domain), MASVS (CC BY-SA), and SLSA (CC BY) control text may be reproduced verbatim in reports. The CIS Benchmark terms of use restrict redistribution, so Rutken's CIS output maps control ids and taxonomy only — it embeds no benchmark prose. A cis-docker report cites the control, not CIS's words.

To see the authoritative, machine-checked map of which verb works on which target kind (with a reason recorded for every not-applicable cell), run rutken capabilities.

REST API — serve

rutken <target> serve exposes one already-analyzed target as a localhost HTTP API, backed by the service/api crates and an axum router. It opens the target once through the same analysis path every other verb uses, then serves synchronous request/response routes until the process is killed — pinned to that one target for the life of the process (no multi-tenant routing, no job queue, no streaming).

rutken app.apk serve                       # binds 127.0.0.1:8787
rutken app.apk serve --bind 127.0.0.1:9000
rutken app.apk serve --max-concurrency 4

Endpoints

  • GET /v1/health — liveness; body ok.
  • GET /v1/meta — package, min/target SDK, sha256, size, DEX file count.
  • GET /v1/rules — the rule catalog (same JSON as rules --list-rules --format json).
  • GET /v1/verify-signature — signature integrity and trust.
  • POST /v1/analyze — run the rules; JSON body selects rules/format ({} means every rule, JSON output).
  • POST /v1/compliance and POST /v1/sca — the compliance and SCA surfaces.
  • POST /v1/correlate — unified static+dynamic report over supplied sessions.

Unknown paths return 404. Errors are {"error":{"code":"...","message":"..."}} with appropriate HTTP status (400 bad selection, 413 body over 8 MiB, 422 unprocessable session set, 500 internal). A key design invariant: POST /v1/analyze?format=json is byte-identical to rutken app.apk rules --format json for the same selection — the HTTP response and the CLI's stdout are interchangeable.

curl example

curl http://127.0.0.1:8787/v1/health
curl http://127.0.0.1:8787/v1/meta
curl -X POST http://127.0.0.1:8787/v1/analyze \
    -H 'content-type: application/json' \
    -d '{"rule": ["weak-crypto-algorithm"], "format": "json"}'

Key flags

  • --bind <addr:port> — default 127.0.0.1:8787.
  • --allow-remote — lifts the loopback-only refusal so --bind may be non-loopback. Adds no auth or TLS; prints a loud stderr warning first.
  • --max-concurrency <N> — concurrent analysis calls (default: available parallelism).

This is a localhost developer service with no authentication and no TLS. Binding to a non-loopback address is refused outright unless you pass --allow-remote, and even then nothing protects it — do not expose it to an untrusted network. The same serve surface is available on native, container, and CI/CD targets (with correlate refused on the static-only ones); it is compiled only into builds with the rest-api feature.

Terminal UI

There is no terminal UI. Rutken is GUI + CLI only. An earlier rutken tui command (and the matching image tui / cicd tui forms and the internal TUI capability) was removed outright — the crates/tui crate, its CLI command, and the capability variant were all deleted together.

If you want a terminal-friendly, non-interactive workflow, the CLI verbs on this page are fully scriptable (every one takes --format json and friends), and headless live traffic capture runs over SSH with no UI via rutken capture record. For an interactive, visual workspace, use the desktop GUI instead.

Desktop GUI

The GUI is a separate binary, rutken-gui (package gui) — a peer of the rutken CLI, not a verb dispatched by it. It opens straight into a desktop security workspace built on egui.

cargo run -p gui
cargo run --bin rutken-gui

Neither form takes a target path as an argument: the workspace opens empty, and you load a target from inside the running session via File → Open…, which shows a native OS file dialog. The dialog is the only way to open a target — there is no typed-path field and no CLI flag for it.

Panels

A three-pane frame — APK tree | call-graph canvas | Findings — over a six-tab bottom bar (IR · Disassembly · Dataflow · Runtime · Network · Console), plus two rail modes: Deps (a vulnerable-components table with an advisory detail drawer) and CI/CD (a baseline delta with a PASS/FAIL gate verdict at a selectable severity).

  • Call-graph canvas — five live scopes (current method callers/callees, N-hop neighbourhood, finding-centred, path between A → B, custom filtered subgraph). An over-budget selection is refused with a count and advice to narrow, never silently truncated; "path between" is a directed search and tells you whether it hit a cap, so "no path within N hops" is never presented as "no path exists."
  • Network tab — populated with recorded .rcap capture-bundle flows when the GUI is built with the intercept feature (cargo run -p gui --features intercept). The offense feature likewise populates a read-only, plan-only Offense window.
  • Console tab — a diagnostics surface (a bounded activity log plus a coverage section of skipped DEX files and native-recovery limitations), not a REPL. Nothing is typed into it.

AI chat — bring your own model

A docked chat panel — toggled from the sparkle button in the title bar — lets you converse with an AI agent that drives Rutken's own analysis against the loaded target by calling its MCP tools (analyze, explain_finding, finding_code, remediate_plan, and the rest). It is strictly bring-your-own-model: Rutken bundles no model and ships no key. You point it at your own endpoint and pay for your own inference — which is why it is a free capability: the cost is entirely yours.

  • Providers — Anthropic (Claude models) or OpenAI (GPT models), connected directly over TLS with just your key; or Custom for your own self-hosted endpoint (ollama, LM Studio, vLLM, or any OpenAI-compatible server, e.g. http://127.0.0.1:11434).
  • Model & effort — a clickable, per-provider model list (fetched from the endpoint, with a curated fallback) and a reasoning-effort control, in the chat's bottom bar.
  • Your key — held in memory for the session by default. Tick Save key in OS secret store to persist it in your OS keyring (Secret Service / Keychain / Credential Manager), with a Forget button to remove it; the key is never written to disk in plaintext and never logged.
  • Transparent — the transcript shows each tool call and its result inline, so you see exactly which Rutken tool the agent ran and what it returned.

The same tools are available to an external agent: the MCP tab sets up Rutken's MCP server so Claude Desktop, Claude Code, or VS Code can drive the analysis instead of the in-GUI chat.

Gotchas

A default build (no features) is a fully working static-analysis GUI; the Offense and Network menu items still render, greyed, with a hover explanation rather than vanishing. The GUI has no persistent projects/sessions, no live capture, and no run/verify instrumentation — it is an interactive desktop tool only, with no CLI flags and no scripted use case.

There is one dev/test-only exception to "no headless mode," and it is not an operator-facing flag: setting RUTKEN_GUI_OPEN=<target path> preloads a target the way File → Open would, RUTKEN_GUI_VIEW=<view id> selects a rail view, and RUTKEN_GUI_SCREENSHOT=<png path> renders a few frames and writes a PNG before exiting. These env vars exist only to make documentation screenshots reproducible under xvfb-run; none are read unless explicitly set, and the normal interactive launch is unaffected.

Device verbs — devices, run, verify

The dynamic-analysis verbs touch a live device, emulator, or process over adb (and, in paid builds, Rutken's own in-house bespoke agent). A typical loop is: list devices, record a session by running the app, then verify the recorded session offline against the static findings.

devices — enumerate targets

Lists every ADB-visible device, including unauthorized and offline ones. Takes no target argument.

rutken devices
rutken devices --format json

With no devices attached it prints No devices found. and exits 0. The JSON form is the scripting hook — fan a run out across every device with a shell loop over rutken devices --format json | jq -r '.devices[].serial'.

run — install, launch, observe

Connects to the device, installs the app (unless --no-install), launches it, observes for a bounded window, records a session, and always runs teardown on every exit path.

rutken app.apk run --frida --duration 60 --session-out s.json --verify
  • --device <serial> / --serial <s> — pick the target device.
  • --duration <secs> — bound the observation window.
  • --session-out <path> — write the recorded session to disk.
  • --frida / --frida-attach — spawn-and-gate or attach a Frida hook/observation session (plain launch + logcat otherwise).
  • --verify — cross-check the observed session against the same static rules rutken rules runs, inline.
  • --correlate — additionally join via the correlation engine.
  • --no-install — observe an already-installed build.
  • --bespoke … — drive Rutken's in-house agent instead of Frida/logcat (paid bespoke-agent builds).

run/verify are intentionally single-device, single-target per invocation; multi-device fan-out is a shell loop, not a built-in flag. Native targets (Linux ELF today) support run too, with their own flags.

verify — offline session report

Renders a runtime-verification report over a session already recorded by run --session-out. No device access — the session is read entirely from disk, and the result is rendered verbatim with no re-scoring.

rutken app.apk verify --session s.json
rutken app.apk verify --session s.json --format json
  • --session <path> — the recorded session (required).
  • --rule <id> / --exclude-rule <id> — narrow the rule set.
  • --interprocedural[-params] — widen the static side of the comparison.

To join several runs — multiple sessions and/or .rcap capture bundles — into one confidence-scored report, use rutken <apk> correlate (monotone-upward confidence: dynamic corroboration raises a finding's confidence but never lowers it).

The active (behaviour-changing) and capture tiers — capture, unpin, intervene — require explicit verbatim consent acknowledgements plus a target-hash match, evaluated before any device work happens; a failed gate exits 2. Plain devices/run/verify observation does not change app behavior, but you must still only test targets you are authorized to test. For the full traffic-capture and TLS-unpinning runbook, see the main docs' Network capture & TLS section and the Dynamic & network capture guide.