// docs · v3.8.0
Documentation
Self-host first. Everything here runs on your machine, offline, with no account.
Getting started
nullock is a man-in-the-middle proxy. It sits between your client and the network, captures every request and response, and lets you intercept, replay, and rewrite them. Three things to know before you start:
- It generates a local CA so it can inspect TLS. You choose where to trust its certificate. The private key stays in your Nullock profile.
- History lives in a project directory: the NDJSON archive stores exchanges, SQLite indexes them, and project.json stores settings and note overrides. Close the project before backing up its whole directory.
- There is no usage telemetry. Automatic release checks are enabled by default; disable them with
--no-update-check. Target traffic and configured services such as updates, marketplace, certificate-transparency lookups and workspace sync make their own network requests.
Install
Grab a build for your OS from Releases, or compile from source.
# prebuilt: github.com/Bikebrainz/Nullock/releases/latest # Windows Nullock-<ver>-win64.exe # Linux .AppImage · .deb · .rpm # macOS Nullock-<ver>-Darwin.dmg (right-click → Open) # or build from source — Qt 6.10.3 + CMake + nghttp2 + a C++ compiler: cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build --target NullockApp
On first run the app generates a local CA and prints its path. Download its public certificate from Settings → CA & TLS and trust it in a dedicated test browser when you need HTTPS interception. Nullock does not automatically modify the OS trust store.
Sections marked unreleased describe the current development build and supplied beta packages. They may not be included in the latest public release. See the repository build instructions for platform prerequisites.
Your first capture
In the development build, a First capture guide opens in an empty project’s Proxy tab. You can reopen it from the HTTP History toolbar. Follow the same workflow below:
- Project and scope. Choose or create a project in Settings. Add your authorized target host under Scope. Advanced scope can restrict ports, protocols and URL paths; correct any validation error before sending active traffic.
- Connect your test browser. Use the live HTTP proxy address shown by the guide or Settings → Browser setup. Configure both HTTP and HTTPS traffic through that address. Download this profile’s CA certificate and trust it in the test browser for HTTPS interception.
- Verify a capture. Browse an in-scope page and inspect its request and response in HTTP History. If nothing appears, check the browser proxy address, scope filters and whether interception is holding the request.
- Replay and verify authentication. Use Stage first request or send a selected history row to Repeater. Inspect it before pressing Send. Confirm the expected response and login state before launching a scanner. Scanner session rules and login macros are described below.
- Keep the useful results. Add comments or highlights to history rows, export a report, and let pending saves finish. Save failures remain visible. Reopening a project restores tool work with active captures idle.
To choose explicit ports from a terminal, start the app below, then run the CLI commands in a second shell. Confirm the actual listening ports in the startup output or Settings; if the requested port is occupied, Nullock can select a fallback.
NullockApp --proxy-port=8080 --control-port=17777 # [nul-] proxy on :8080 · control API on :17777 # then, in another shell — set scope, watch it fill: nullock scope add 'app.local' nullock status # ─── 42 rows · scope: app.local ───
Simple scope rules match host names, such as app.local or *.example.test; they do not restrict a URL path or port. Captured exchanges appear in the history table. Click a row to inspect the raw exchange, or send it to Repeater.
Out-of-scope traffic is still proxied. Enable logging of out-of-scope traffic before browsing if you need to retain those exchanges; widening scope later cannot recover traffic that was never recorded.
Project notes (unreleased)
In the development build, right-click a history row or Site map leaf to add a comment or highlight. Notes are saved with the project and synchronized between connected clients. The ANNOTATED filter finds marked exchanges.
If this browser has older local notes, use SAVE BROWSER NOTES TO PROJECT. Existing project notes take priority; a failed import retains the browser copy so you can retry.
Comments and highlights travel with HAR files and appear in selected-item XML and branch HTML reports. Other message tables and global report formats do not yet share these annotations.
nullock history-notes
nullock history-note 42 --color purple --comment 'Review this exchange'
nullock history-note 42 --comment ''
nullock history-note 42 --clearThe CLI needs jq and a running app. GET /api/history/annotations returns notes, their revision and the history generation. POST /api/history/annotation accepts a row ID, that generation, and a comment and/or colour. Unspecified fields stay unchanged. Stale generations are rejected with HTTP 409; failed saves keep the previous note.
Comments are limited to 4096 UTF-16 code units and the annotation map to 1 MiB. Colours are red, orange, yellow, green, cyan, blue, purple, pink and gray; an empty string clears a field. Clearing history clears its notes too.
Repeater while a request runs (unreleased)
Sending a Repeater request runs in the background. Its busy state remains visible while you inspect other tools or edit the next request. The response and history belong to the request that was actually sent; later edits stay in the request pane. One Repeater request runs at a time, and project switching or closing tabs waits until it finishes.
Stop takes effect after the current response or transport timeout. It prevents any further redirects; it cannot undo a request already sent to the server. A slow client uploading to the control API no longer stalls the UI. Some other synchronous scanner and extension handlers still share the UI thread.
Workspace recovery (unreleased)
The development build saves changed Repeater tabs, Intruder work, cookies and Sequencer data every two seconds. It also saves before switching projects and after active workers finish during shutdown. Work entered since the last successful autosave can still be lost if the process is forcibly terminated.
Sequencer retains its manual corpus, captured samples, extraction settings and significance level across tab changes, browser reloads and project reopening. Captures restore idle: inspect the recovered work and explicitly start another capture when ready. Each new capture appends samples to the manual corpus once. Analysis reports can be regenerated from the saved corpus.
Repeater also saves request encoding, automatic Content-Length, redirect policy and redirect cookie processing. A new project starts with its own defaults, so another project’s request settings do not carry over.
If a project file cannot be saved, a banner identifies the failure, the current project stays open, and autosave retries. Token text edits that conflict with another client or a live capture remain visible as unsaved edits; copy that text before choosing Reload saved corpus. Other settings use field updates so changing one setting preserves unrelated fields.
The manual corpus and captured token collection each have a four-million-character limit, with at most 10,000 samples per capture. Export samples before clearing large corpora. Project files contain raw requests and credentials; keep them in a private location.
Authenticated HTTP scans (unreleased)
- Set the engagement scope first. Advanced rules can limit the protocol, port and path. Redirects and generated scan requests stay inside those limits.
- Capture a signed-in request through the proxy. In Sessions, enable cookie injection for the target if scans should reuse its cookie jar. Secure cookies remain restricted to HTTPS, and cookie paths are respected.
- For CSRF or header tokens, add a session-handling rule and select Scanner in its tool scope. Choose the response field to extract and the request header, cookie, form field, JSON placeholder or query parameter to update.
- Record the HTTP login steps as a named login macro and configure its logged-out status or body condition. An expired scan response triggers that macro before the same scan loop continues. The expired request is not automatically replayed.
- Check the captured request and response before expanding the scan. Crawler history preserves the authentication headers actually sent. Multi-user authorization tests use each identity's supplied credentials.
Login macro requests must also be in scope. A login flow that requires browser JavaScript must be completed in a browser; the macro runner replays HTTP requests.
CLI
The CLI drives a running instance over its local control API ($NULLOCK_API, default 127.0.0.1:17777) — it needs curl and jq. Anything you do in the UI, you can script.
| Command | What it does |
|---|---|
nullock status | Proxy, scope & findings summary |
nullock scope add <glob> | Add a target to scope (e.g. http://app.local/*) |
nullock scan <host> [top100] | Port-scan & run the active battery against a host |
nullock findings | List findings as JSON (filter by severity) |
nullock export sarif|sbom|nmap|har | Export for CI & other tooling |
nullock replay <id> | Re-send a captured request |
Extensions
Drop a single .js file into the extensions directory. It's loaded on next start — no build step, no marketplace gate. Each file runs in a sandboxed QJSEngine and hooks the proxy pipeline:
// nullock:permissions modify-requests nullock.onRequest(req => { req.headers.push(["X-Debug", "nullock"]); return req; });
Hooks: nullock.onRequest(fn) and nullock.onResponse(fn) — mutating traffic needs the modify-requests / modify-responses permission (declared in a header comment); observing and nullock.reportFinding(...) need none. Full guide: EXTENSIONS.md.
Security model
A MITM proxy is, by design, a tool that reads encrypted traffic. Here is exactly what nullock can and cannot see, and where the lines are:
- The CA is yours. Generated locally on first run, stored in your OS keychain. We never ship a shared key. Delete it and interception stops.
- Captures stay local. History is a file on disk. Nothing syncs unless you buy Hosted and opt in per scope.
- Secrets in history. Tokens and cookies land in plaintext in your project files — that's the point. Encrypt the disk; don't commit the file.
- Reporting a flaw. Report privately via GitHub Security Advisories. We respond within 72 hours and credit you on the advisory.
Only intercept traffic you own or are authorized to test. nullock is a tool; the law is yours to follow.