Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ developer-facing record.

## [Unreleased]

### Build follow-up
- Add the September 29 to-do list with reproduced gaps and acceptance checks.
- Correct website release labels: v3.7.0 is the latest public release; v3.8.0
remains an unpublished draft.
- Correct stale scope-enforcement evidence and distinguish native QML Send
behavior from asynchronous browser/API/CLI sends.
- Label roadmap grade changes as changes, including downward corrections.

### Repeater CLI and roadmap
- Reject empty drafts and blank target hosts before accepting an API send, so
the CLI cannot report a previous response as a successful new request.
Expand Down Expand Up @@ -1651,7 +1659,9 @@ developer-facing record.
the mechanism the doc comment always described actually produces a report
now instead of only ever being reachable from a crash signal.

## [3.8.0] — 2026-08-20
## 3.8.0 — unpublished draft

Notes prepared August 20, 2026. This version has not been published as a GitHub release.

This release folds in a large security-and-correctness pass: a whole-codebase
security review (16 findings, from a CRITICAL CI-action fix down to
Expand Down
9 changes: 5 additions & 4 deletions docs/changelog.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ <h1 class="h1-page grad-text" style="margin:10px 0 0;">What shipped</h1>
<span class="badge"><span class="dot"></span>development</span>
</div>
<div class="rel-body">
<p class="rel-note">Security checks now distinguish effective response headers from malformed lookalikes. These changes are in the development build; v3.8.0 remains the latest release listed below.</p>
<p class="rel-note">The development build includes corrected security checks, certificate-cache validation and Repeater CLI fixes; v3.7.0 remains the latest public release, and the v3.8.0 notes below are a draft.</p>
<ul>
<li><span class="tag fix">fix</span> <strong>Build follow-up and roadmap corrections.</strong> The <a href="https://github.com/Bikebrainz/Nullock/blob/Nullock/docs/reviews/2026-09-29-build-follow-up.md">September 29 checklist</a> records remaining byte-fidelity, HTML-context, cancellation, fixture-isolation and certificate-lifecycle work. Scope enforcement evidence is refreshed, and the native window's blocking Send path is called out separately.</li>
<li><span class="tag fix">fix</span> <strong>Request files keep their binary bodies.</strong> Repeater CLI file and stdin loading preserves NUL bytes, non-UTF-8 data and trailing newlines. Invalid input leaves the draft unchanged; an empty file explicitly clears it. Tab summaries distinguish fresh tabs from completed responses, and duplicated tabs clear their old response metadata. Empty drafts and blank targets are rejected instead of reporting an old response as a successful send.</li>
<li><span class="tag fix">fix</span> <strong>Repeater CLI loads the right request and waits for sends.</strong> History IDs select the complete captured request, including binary bodies. Send polling handles pending responses and reports refusals or unfinished waits. The new <code class="inline">repeater stop</code> command stops after the current response. The roadmap now distinguishes working views and responsive sends from the remaining byte-fidelity and immediate-cancellation gaps.</li>
<li><span class="tag fix">fix</span> <strong>Reflected-XSS checks respect HTML tag boundaries.</strong> Iframe fallback text stays inert; custom tag names and abruptly closed comments no longer hide reflections. The roadmap now marks this probe as partial because template and SVG/MathML context handling still needs work.</li>
Expand All @@ -70,8 +71,8 @@ <h1 class="h1-page grad-text" style="margin:10px 0 0;">What shipped</h1>
<article class="rel">
<div class="rel-meta">
<span class="rel-ver">v3.8.0</span>
<span class="caption">Aug 20, 2026</span>
<span class="badge"><span class="dot"></span>released</span>
<span class="caption">Draft notes &middot; Aug 20, 2026</span>
<span class="badge"><span class="dot"></span>unpublished draft</span>
</div>
<div class="rel-body">
<p class="rel-note">The pre-launch blocker push &mdash; five of the first-hour blockers fixed: scan findings and Repeater tabs now survive app close and project reopen, Repeater auto-updates Content-Length, the proxy can bind off-loopback for device testing, and interception is now rule-driven &mdash; alongside a detector-hardening pass over the passive scanner (mutation-proven regression coverage around every finding kind), the false-negative bugs those tests surfaced, and new Burp-parity features on the roadmap.</p>
Expand Down Expand Up @@ -148,7 +149,7 @@ <h1 class="h1-page grad-text" style="margin:10px 0 0;">What shipped</h1>
<article class="rel">
<div class="rel-meta">
<span class="rel-ver">v3.7.0</span>
<span class="caption">Jul 5, 2026</span>
<span class="caption">Published Jul 21, 2026</span>
<span class="badge ok"><span class="dot"></span>latest</span>
</div>
<div class="rel-body">
Expand Down
4 changes: 2 additions & 2 deletions docs/docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

<!-- CONTENT -->
<main class="docs-content">
<p class="eyebrow">// docs · v3.8.0</p>
<p class="eyebrow">// docs · development build</p>
<h1 class="h1-page" style="margin:8px 0 0;">Documentation</h1>
<p class="lead" style="margin:14px 0 0;">Self-host first. Everything here runs on your machine, offline, with no account.</p>

Expand Down Expand Up @@ -86,7 +86,7 @@ <h2 class="h2-section">Install</h2>
<span class="c-purple">cmake</span> --build build --target NullockApp</pre>
</div>
<p>On first run the app generates a local CA and prints its path. Download its public certificate from Settings → CA &amp; TLS and trust it in a dedicated test browser when you need HTTPS interception. Nullock does not automatically modify the OS trust store.</p>
<p>Sections marked <strong>unreleased</strong> describe the current development build and supplied beta packages. They may not be included in the latest public release. See the <a href="https://github.com/Bikebrainz/Nullock#readme">repository build instructions</a> for platform prerequisites.</p>
<p>Sections marked <strong>unreleased</strong> describe the current development build and supplied beta packages. The latest public release is <a href="https://github.com/Bikebrainz/Nullock/releases/tag/v3.7.0">v3.7.0</a>; v3.8.0 remains an unpublished draft. See the <a href="https://github.com/Bikebrainz/Nullock#readme">repository build instructions</a> for platform prerequisites.</p>
</section>

<section id="first-capture" class="doc-sec">
Expand Down
164 changes: 164 additions & 0 deletions docs/reviews/2026-09-29-build-follow-up.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# September 29 build follow-up

Owner: Bikebrainz. This is the next-work checklist from the September 29 build
and verification pass. The [capability register](../roadmap/parity.json) remains
the full roadmap; this list prioritizes gaps reproduced or inspected during the
session. An unchecked item is not implemented.

## Changes from this build

| Change | Pull request | Status |
| --- | --- | --- |
| Effective security headers and strict TLS certificate compatibility | [#21](https://github.com/Bikebrainz/Nullock/pull/21) | Merged |
| Reflected-XSS media types and HTML boundaries; certificate-cache validation | [#22](https://github.com/Bikebrainz/Nullock/pull/22) | Merged |
| Stable history IDs, asynchronous CLI send polling and Stop | [#25](https://github.com/Bikebrainz/Nullock/pull/25) | Merged |
| Binary file/stdin requests, tab indicators and empty-send rejection | [#26](https://github.com/Bikebrainz/Nullock/pull/26) | Merged |

Each implementation PR passed all eight CI jobs on its reviewed head before
merge. Every implementation PR also updates the public changelog and roadmap. These
are development changes; they do not create a release or change the latest
published version. GitHub release metadata checked on September 29 identifies
v3.7.0 as the latest public release and v3.8.0 as an unpublished draft.
Certificate details from #23 and HTML-context details from
#24 were incorporated into #22.

## Next work, in priority order

### 1. Preserve response bytes through Repeater and Hex views

- [ ] Carry the original response bytes through the tab model, snapshot and
per-tab history, with a separate decoded display representation.
- [ ] Make request Hex honor the request's actual UTF-8 or Latin-1 encoding.
- [ ] Make response Hex and binary export use the selected byte representation.

**Evidence:** a loopback response body `00 ff 80 41` becomes
`00 U+FFFD U+FFFD 41` in Repeater. `Repeater::send` converts the raw or decoded
body with `QString::fromUtf8`; `toHexDump` then UTF-8-encodes the display text.
The original bytes cannot be recovered from that string. A Latin-1 request can
send correctly while its Hex view shows different bytes.

**Done when:** all 256 byte values survive send, snapshot, history navigation,
project save/reload and export; Hex matches the fixture bytes. Compressed
responses distinguish original wire bytes from decoded body bytes. Include
empty bodies, invalid UTF-8, NULs and bodies larger than the preview limit.

### 2. Correct the remaining reflected-XSS HTML contexts

- [ ] Handle inert template contents and SVG/MathML parsing contexts.
- [ ] Expand the pinned-browser corpus before changing the parser or its grade.

**Evidence:** after the tag-boundary fixes, a 97-context browser comparison left
two mismatches for the marker `<nlk0a1b2c3d>`:

| HTML | Native marker classification | Chromium element present |
| --- | --- | --- |
| `<template><nlk0a1b2c3d>` | true | false |
| `<svg><title><nlk0a1b2c3d>` | false | true |

The browser result describes this marker's parsed context, not a proof that an
arbitrary script payload executes. Existing committed browser coverage lives in
`Tests/ui/xss_context_browser_test.cjs` and `xss_media_types_browser_test.cjs`.

**Done when:** the corpus covers nested templates, foreign-content integration
points, malformed nesting and script/raw-text states, with native results
matching the pinned browser. Keep XML execution, stored XSS and DOM XSS outside
the claim unless they receive their own implementation and verification.

### 3. Finish Repeater cancellation and native-window responsiveness

- [ ] Route the native QML Send button through the asynchronous send path and
expose the same Stop state as the browser.
- [ ] Add cancellation to the socket-owning worker during connection, TLS,
header and body waits.
- [ ] Keep concurrent sends from separate tabs as a separate design task.

**Evidence:** browser/API/CLI sends use `sendAsync`, but `Src/App/app.qml` still
calls `repeater.send()` directly. Current Stop sets an atomic flag checked
between responses and redirects; it does not interrupt a stalled socket.
`HttpClient` uses per-wait timeouts and a five-minute total read budget.

**Done when:** a controlled stalled connection, TLS handshake, header, fixed body
and chunked body can each be stopped promptly without cross-thread socket use.
The native window and browser remain responsive, no extra redirect is sent,
newer edits survive completion, and shutdown joins the worker cleanly.

### 4. Isolate OAST smoke fixtures and retain callback diagnostics

- [ ] Allocate separate HTTP and DNS sink ports for each smoke run, alongside
the control/proxy ports, and verify startup on the requested listeners.
- [ ] Report callback failures from the mock instead of discarding exceptions.
- [ ] Check concurrent isolated runs and deliberate IPv4/IPv6 port conflicts.
- [ ] Verify that a callback to the advertised address reaches this app; a
running flag alone is insufficient on the reproduced Windows bind path.

**Evidence:** one integrated run passed 193 checks and missed three HTTP OAST
callbacks (SSRF, RCE and XXE); an isolated retry passed all 196. The cause of
that first failure is not established. `scripts/probe_smoke.sh` uses the default
OAST ports and suppresses exceptions from its HTTP callback mock. In a separate
controlled Windows experiment, occupying the requested port on IPv4 loopback
left the app reporting `oast.running=true`, while a request to its advertised
IPv4 address reached the pre-existing owned fixture. Occupying that port on a
dual-stack listener instead left `running=false, port=0` while the control API
remained available. Neither experiment proves the earlier transient cause.

**Done when:** concurrent runs do not share sinks or state, listener failures
produce a clear startup error, and a minted callback confirms ownership of the
advertised address. Callback diagnostics must identify the failed operation. Retain token-specific positive assertions and safe-target negative
controls; do not replace them with longer blind waits or automatic pass-on-retry.

### 5. Complete CA and certificate-cache lifecycle controls

- [ ] Revalidate expiry before returning an in-memory leaf.
- [ ] Define explicit CA/key validation and repair, including operator-visible
trust changes.
- [ ] Add supported CA replacement and leaf-cache clearing/eviction controls.

**Evidence:** `CertAuthority::leafCertFor` returns an in-memory cache hit before
checking dates or the current CA. Disk-cache reuse after restart now checks the
CA signature, private key, DNS/IP SAN, dates and key identifiers. That fix does
not provide live CA replacement or repair of a broken root/key pair.

**Done when:** a controlled clock test refreshes an expired memory entry; valid
entries remain reusable; CA rotation cannot leave mixed old/new leaves; failures
are actionable without silently replacing a trusted root. Preserve owner-only
key permissions and test both OpenSSL and LibreSSL certificate generation.

### 6. Keep roadmap evidence specific and current

- [ ] Audit remaining entries whose gap text contradicts their current state or
cites superseded line numbers and behavior.
- [ ] Give browser, CLI and native-window behavior separate descriptions when
their implementations differ.
- [ ] Require a runnable regression or a precise source reference for each
reconciliation; retain limitations instead of inferring full parity.
- [ ] When publishing a release, update draft/latest labels and public dates
against the GitHub release metadata as part of the same release checklist.

This pass corrects the obsolete Repeater scope-bypass claim: the shared
`HttpClient` checks outbound scope before connecting, including redirects, and
the API snapshots the request synchronously before scheduling its worker.
The 41-check outbound-scope regression passes. The native window's remaining
blocking Send behavior is a separate issue described above.

## Verification to carry forward

- Native suites: 102 passed on the combined XSS/certificate implementation.
- Public probe smoke: 196 passed on the isolated rerun; the earlier OAST misses
remain recorded above.
- Strict TLS and runtime regressions: all 64 checks, including native-window
startup, passed on the final CLI build.
- Pinned Chromium: 72 media-type and 95 HTML-context comparisons passed. An
additional 1,238 generated media-type comparisons found no mismatches.
- CLI fixtures and real-app checks cover stable IDs, binary history bodies,
multiple busy polls, refusal/timeouts, Stop, binary files/stdin, UTF-8, invalid
base64, empty-send rejection and fresh/completed/duplicated tab indicators.
The final CLI build also passed all 102 native suites and 20 control
responsiveness checks.
- Website checks cover links, script integrity, generated-page freshness and
desktop/mobile roadmap and changelog layout.

For each follow-up, update `CHANGELOG.md`, `docs/changelog.html` and the affected
roadmap evidence together. Run `python scripts/parity_report.py` after changing
the register, then `python scripts/check_web_assets.py` and the relevant
application/browser regression. Cross-platform CI must pass on the exact PR
head before an implementation merge.
1 change: 1 addition & 0 deletions docs/reviews/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ Keep dated engineering reviews here. These describe the repository at the time
of review; historical paths and findings may differ from the current code.

- [2026-08-11 HTTP security review](2026-08-11-http-security.md)
- [2026-09-29 build follow-up and to-do list](2026-09-29-build-follow-up.md)
Loading
Loading