Skip to content

Releases

v0.8.3

Choose a tag to compare

@github-actions github-actions released this 14 Nov 11:18

brainproxy 0.8.3

What's new: far fewer false positives from SQL injection and the time based rules, JWT scan rules, and an audit's worth of fixes across the app, the CLI and the MCP server (thanks @L1ghtn1ng, #138).

New

  • JWT rules. The active rule 100007 JWT Weaknesses runs on every page that sends a JSON Web Token (header, cookie or parameter). It cracks HMAC secrets offline against common and default ones, then checks the page depends on the token before trying forged tokens: changed or removed signature, alg: none, an expired token signed again, a kid pointing at /dev/null, RS/PS to HS256 algorithm confusion with the site's public key, and jku/x5u callbacks with oob start. The passive rule 100008 JWT Issues reports tokens in query strings, and server-issued tokens with alg: none, no exp, or claims named like secrets.

SQL injection: confirmed before it's reported

On a benchmark of pages that commonly fool SQL injection checks (echoing, searches, live data, flaky and rate-limited pages, validation errors, jittery latency), safe pages raised alerts in 16 of 87 scans at MEDIUM and 27 of 87 at HIGH. Now it's none, with the same true positives (including Juice Shop's login and product search).

  • A comparison that finds SQL (expression, boolean, ORDER BY) is repeated before it's reported, and the changed page must not be a 5xx or 429 the second time.
  • "OR 1=1" findings need "OR 1=2" to keep the original page (word searches matched both).
  • The bare LIKE pair (% against XYZABCDEFGHIJ) is no longer sent: a parameterised LIKE with unescaped wildcards answers it the same way. The quoted LIKE pairs still find concatenated LIKE clauses.
  • Echoed values are also recognised HTML escaped the way frameworks write quotes (', ') and JSON escaped.
  • An SQL error must come back for the same characters after a random value too, so a search whose results quote an SQL error isn't reported. HQL Injection (100003) and NoSQL Injection - MongoDB (40033) do the same.
  • The HTTP 500 check runs for quotes only; the 500 must repeat and go away when the quotes are doubled, so input validation and type errors (true' in a JSON boolean) no longer count.
  • Every time based rule (SQL 40019-40027, command injection 90037, MongoDB 90039, blind SSTI 90036, Shellshock 10048) needs a passing high/low sequence to pass a second time.

Fixes and hardening (#138)

  • Command palette and dialogs: clicks inside the palette no longer take focus out of it; dialogs without a field (Export traffic, report builder) take focus so Esc works; match highlighting after an emoji.
  • MCP: positional arguments followed the client's JSON key order (history_note could note the wrong entry); the provenance mark is set by the server for every command, also for raw and cut-off output; non-UTF-8 raw bytes come back as base64; query refuses statements that write (VACUUM INTO).
  • Scope and session rules: NAT64 addresses no longer slip past IPv4 excludes; a session rule's URL is anchored at the whole origin (https://app.test matched https://app.test.evil.test/, and the vault could send the rule's values there).
  • Proxy and HTTP: absolute-form URLs with a query and no path, URLs inside an origin-form query over HTTP/2 and HTTP/3, responses with more than 256 headers, bodies decoding past 64 MiB.
  • CLI: out-of-range times and rates (--timeout inf, --rate 1e-300) are errors instead of panics; findings list --limit without --all, --state typos, --remove-header Content-Length; auth add --keep-password keeps a stored password when a profile is replaced (the app's edit form no longer deletes it).
  • Core and scanner: the redactor's panic on some non-ASCII text (report, repro, ticket, HAR export); grouped findings show the highest risk; OpenAPI percent-encoded $refs and Postman nested variables and inherit auth; passive rules and <3 / <!-->.
  • App: traffic rows recorded before their response stay "error" no more; the list no longer jumps to the selection on every poll; Scope keeps unsaved edits; the guided scan's job poll stops; deleting a project removes its .record.log.
  • AGENTS.md for coding agents; every unsafe block documents why it's sound.

Behaviour changes: negative or non-finite times and rates are errors rather than clamped; a session rule URL like https://app.test no longer covers other ports or longer host names; query refuses statements that write.

Project format

Unchanged (schema 21).

Dependencies

flate2 1.1.11 and brotli-decompressor 6.3.0 (#137), serde-saphyr 2.1.1 (#134), vite 8.3.6 (#133), Rust image 44819b2 (#136), softprops/action-gh-release 3.0.4 (#132), taiki-e/install-action 2.90.2 (#135).

v0.8.2

Choose a tag to compare

@github-actions github-actions released this 12 Nov 22:00

brainproxy 0.8.2

What's new: check a finding by comparing the response with and without its payload, see the payload highlighted in Replay, HTTP/3, request scripts that can block or answer a request, and a command palette with rebindable shortcuts.

New

  • Compare with and without the payload. Findings has a Compare with/without payload button. It sends the request the scan started from and the attack request again, now, and shows each one's status, length, time and whether the evidence appears, what differs, and a diff of the two responses.
    • From the CLI: findings verify ID; over MCP: findings_verify.
    • --repeat N sends the two alternately N times and compares median times, for time-based checks.
    • --request - sends an edited attack instead of the recorded one.
    • Active-scan findings now record the request their attack was built from (base_history_id). For older findings, a matching request is looked for in history; with none, it says no baseline was recorded.
  • The payload is highlighted in Replay. Send to Replay from a finding marks the injected part of the request, even when it was URL- or JSON-encoded. The mark follows the text as you edit. A tab opened from a finding has Compare with baseline, which sends what's in the editor.
  • HTTP/3 (#129). send, fuzz run and scan active take --http3, and Replay, Fuzzer and Scans have an HTTP/3 option. Endpoints a site advertises with Alt-Svc are used only after they pass the engagement scope. When HTTP/3 can't be used, the request goes over TCP and a note says why. Two new rules: a passive one for sites offering HTTP/3, and an active one for responses that differ between HTTP/3 and TCP.
  • Request scripts (#130). A match-and-replace rule with location request runs a script on each whole request (proxy, send, fuzz, scan). The script can let it go, rewrite it, block it, or answer it itself so nothing is sent. Blocked and answered requests are recorded and marked. Over MCP an agent can't switch off, remove or replace an active request rule.
  • Command palette (#131): Mod+K lists every view, tab and action. Settings › Keyboard lets you change any shortcut.

Fixes and hardening

  • A request script now runs after every other request rule, so a rule added later can't rewrite what the script let through.
  • An edited request forwarded from the intercept goes through the request scripts again before it is sent.
  • return { block: false } lets a request go (it was an error).
  • An HTTP/3 endpoint the scope refused no longer turns HTTP/3 back on for every request. Quiet HTTP/3 connections are kept alive.
  • The palette's recent projects are checked like the Welcome screen's.
  • Mod+F (Forward) no longer fires while typing in the held-message editor.

Project format

Schema 20 → 21 (findings.base_history_id). Projects are upgraded when opened; older versions can't open an upgraded project.

Dependencies

taiki-e/install-action 2.90.1 (#128).

v0.8.1

Choose a tag to compare

@github-actions github-actions released this 11 Nov 17:24

brainproxy 0.8.1

What's new: agents over MCP read local files only from the project folder, the intercept holds what a filter query matches, access-control testing leaves out static assets and other noise, and more CLI features are in the app.

Security

  • Agents over MCP read local files only from the project folder (or stdin), in every command that reads one: send FILE, fuzz run FILE, --payloads file:, ws send, macro steps, payload files and templates. This closes #112 (#125).
  • The project database, its SQLite -wal, -shm and -journal files, its lock files, browser profiles and the logs and staged requests named after it are refused too, though they sit in that folder. An agent can't send the database's contents and read them back from history.

New

  • Intercept by query: intercept enable --filter QUERY holds only what a filter-language query matches, for example method=POST NOT path:/static or status:5xx. The app has this too (#126).
  • Less noise in access-control testing: authz and the Access view leave out static assets (judged by content type, Sec-Fetch-Dest or extension), HEAD and OPTIONS requests, and the paths you list to skip. What was left out is counted and can be shown. There is also an issues-only view (#124). --include-static tests static assets again.
  • More of the CLI in the app (#121, #122):
    • Traffic › Export… writes what the filter shows as a HAR file;
    • Scans › Rules › Passive adds, tests and removes script checks;
    • Findings has a Ticket menu (GitHub or Jira write-ups, record the ticket link) and Repro pack…;
    • the report builder offers JSON, CSV, SARIF and DefectDojo, picks which findings go in, has masking options and drafts, and edits the executive summary.
  • Development builds: make dev-deb and make dev-macos build a separate brainproxy-dev app that installs beside a release (#127).

Changes

  • Settings' "Rules & data" tab is now "Rules & Updates" (#120).
  • Access-control testing no longer tests images, audio, video and fonts by default. To test a private image, use --include-static or name the request with --history-id.

Fixes

  • In the add-script-check dialog, Enter in "Test on history #" tests the check rather than adding it.

Dependencies

taiki-e/install-action 2.90.0 (#123).

No schema change: 0.8.0 projects open as they are.

v0.8.0

Choose a tag to compare

@github-actions github-actions released this 10 Nov 17:17

brainproxy 0.8.0

What's new: structured match-and-replace rules with a tester, sandboxed JavaScript hooks, server-sent event streams through the proxy and send, and replayed logins that need a one-time code, a browser or a passkey.

New

  • Match-and-replace rules (#116): structured locations next to the five raw ones: method, path, a query parameter, a request or response header by name, the status code, and WebSocket messages. Matchers are regex, literal and whole. A rule can be limited to engines (--applies-to proxy, send/Replay, fuzz, scan) and to hosts. rules test tries rules on a request or response and sends nothing; in the app it is in Settings › Match & replace. History keeps the request before the rules and the response after them. rules import reads what rules list prints.

  • Scripts (#119): a sandboxed JavaScript hook, run in the same sandbox as the request-signing script. It can supply a rule's replacement (rules add --script), act as a fuzz payload processor, or run a passive check of your own.

  • Server-sent events (#117): text/event-stream responses are relayed through the proxy as they arrive instead of waiting for the end. Their events are recorded in the project (sse commands, the app's Event streams view). send reads a stream for a bounded time.

  • Login replay (#118):

    • auth profiles can hold a TOTP secret (RFC 6238; --totp-secret-env reads it at each login and stores nothing), with {{totp}} in login steps;
    • auth record start also records what is done in the page (Chromium-based browsers, Linux and macOS). When plain requests can't repeat a login (single sign-on, a login built in JavaScript, a passkey), or with --in-browser, the steps are replayed in a headless browser;
    • --passkey records with a virtual authenticator; the passkey is kept with the profile and used at every replay.

    The login is made again when the session is lost.

Fixes

  • A response-body rule leaves 204, 304 and HEAD responses without a body. A rule that matches an empty body no longer adds a body to them.
  • The head of a relayed event stream gets response-header rules only, and keeps its framing headers.
  • A login form with a company, invite or similar code is no longer taken for a one-time code.
  • The app builds on case-insensitive file systems again.
  • Tests: fixed a BrokenPipe failure, a leaked process and a likely hang on macOS (#113).

Project format

Schema 19 → 20 (event stream tables). Projects are upgraded when opened; older versions can't open an upgraded project.

Dependencies

@vitejs/plugin-react 6.2.1 (#115), taiki-e/install-action 2.89.1 (#114).

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 09 Nov 19:29

brainproxy 0.7.0

What's new: saved scan policies, a filter language for traffic, HAR import and export, racing a group of different requests, and better crawling of JavaScript apps. This release also masks more credentials and limits which files an agent can read over MCP.

New

  • Scan policies: save a policy with a strength and threshold per rule (#108).
  • Traffic filters: a filter language for history list --filter and the app's Query mode. Filters can be saved in the project, and history export takes --filter too (#110).
  • HAR: import HAR files as scan targets, and export history as HAR (#109).
  • Race: race a group of different requests together, from send and Replay (#107).
  • MCP: the 2026-07-28 protocol is served alongside the handshake one (#111).
  • Crawler: finds paths built with JavaScript template strings, and follows code-split script chunks. Single-page apps are mapped much more fully.
  • App: every toolbar wraps onto more lines on narrow windows, so no control is cut off.

Behaviour changes

  • Agents over MCP read local files only from the project folder (or stdin). This applies to import api/har/openapi/postman, graphql --schema, scan active --api and --environment. These are refused as project folders: your home folder, a folder above it, and /. Import parse errors give the line and column only.
  • The import preview shows only the method and origin for out-of-scope requests.
  • Files written with --out / -o are readable only by you (0600). So are background job logs and fuzz request and log files. --force still works with /dev/null and pipes.
  • More credentials are masked:
    • any header whose value carries an auth scheme, whatever the header is called;
    • any *-Key header that isn't a data key (Sort-Key, Primary-Key and similar stay visible);
    • Authorisation;
    • WebSocket subprotocol tokens, including the Kubernetes form;
    • bare cookie values;
    • JSON names written with \u escapes;
    • token … in text;
    • refresh tokens.

Known gap

Over MCP, send FILE, ws send and macro steps can still read files outside the project folder. This is tracked in #112.

CI

The checks now also run on macOS (#105) and use nextest (#106).

brainproxy 0.6.1

Choose a tag to compare

@github-actions github-actions released this 08 Nov 16:37

brainproxy 0.6.1

Fixes for 0.6.0, plus a scope check on the Host header, a record of who changed what, and every scan request written down before it goes out.

Update if you use 0.6.0 reports: 0.6.0 printed the decoded password of an HTTP Basic Authorization header in every report that included the finding about it. 0.6.1 masks it. Regenerate any report made with 0.6.0 that you have shared or kept.

Schema change (v17 → v19): a project opened with 0.6.1 can't be opened by 0.6.0 again. Keep a copy if you need to go back.

Changed: check these before updating scripts or CI

  • SARIF fingerprints are brainproxy/v3 (#103). Path parameters such as ;jsessionid= no longer make a new finding per session. The first upload after updating may show existing alerts as closed and reopened.
  • Issues have hosts (#103): an issue merged across hosts lists them all; host stays for the first.
  • Risk can go down (#103): a rescan that sees a finding at a lower risk lowers it, and the timeline records the change.
  • The Host header is checked against scope (#83). A request whose Host, :authority or absolute URL names a host outside scope is refused, wherever it comes from: send, fuzz, scans, logins, macros, proxy rules. Header values with a line break or NUL are refused for everyone.
    • Host header tests are still possible: pass --host-header-test (send, fuzz, scan active, auth login/status, macro run, rules add/enable), and the request goes out with a warning.
    • A proxy rule added by an agent without the flag that would put a foreign host on a request gets a 502 instead.
    • With an IP address or range in scope, any name that resolves to it is in scope. See Scope in the manual.
  • More is refused through MCP (#102): --force on report, ca export, ca init and findings repro; report-profile save over an existing layout; report-profile remove is not a tool.
  • Every scan request is recorded before it is sent (#85): crawls, active scans, authz, fuzz --store all and callbacks. A stopped or crashed run keeps what it sent. Active scans now keep every attack request by default, so projects grow faster.
    • To keep only the attack requests that back a finding, turn on scan prune on (or Keep only attack requests that back a finding in the app's New scan), or pass scan active --prune for one scan. Pruning runs when the scan ends or is stopped, and never deletes the requests the scan started from or anything a finding, note or tag points to. Through MCP, pruning can't be turned on: an agent's scan always keeps everything.

New

  • --mask on report and findings repro (#101): masks extra values you name (at least 6 characters). Not with --no-redact.
  • Provenance (#84): who changed an auth profile, session rule or macro (edited_by), who started a job, fuzz run, authz run, WebSocket or callback payload, and a log of setting changes. proxy status says when a running proxy is older than the project's rules.
  • Delete a project from the app (#104).

Fixed

  • Redaction (#101): overlapping secrets no longer leave a tail; the unsigned half of a signed cookie is masked; titles, company, scope, filters and host lists are scrubbed too; masking happens before a body is cut.
  • The script signer's memory limit now also works on macOS and Windows (#65).
  • Nuclei checks run about twice as fast (#87).
  • ZAP data synced with upstream (#64).
  • The app stops the proxy it started when you close a project, also without auto-start (#68).
  • Scan depth times in the wizard are rough ranges now: quick 5 to 10 minutes, standard around an hour, thorough several hours depending on the site's size (#69).
  • Findings bookkeeping (#100): marking a finding with the state it already has no longer records a change, and a retest that finds it still present no longer counts twice in the passive scan.

Thanks to @L1ghtn1ng for #103 and #104.

brainproxy 0.6.0

Choose a tag to compare

@github-actions github-actions released this 07 Nov 14:20

brainproxy 0.6.0

Reports you can hand over. Secrets are masked by default, findings become records with a history, and reports come in presets, with your branding, as PDF or Word. What an agent writes only reaches a report once a person has read it.

Schema change (v14 → v17): a project opened with 0.6.0 can't be opened by 0.5.x again. Keep a copy if you need to go back.

Changed: check these before updating scripts or CI

  • Reports mask session secrets by default in every format: cookie values, Authorization credentials, API-key headers, secret-named parameters, hidden fields, JWTs, and your auth profiles' passwords and tokens. A value masked in one place is masked wherever else the report quotes it. --no-redact keeps everything, and the report says so.
  • findings list and reports show work still to do by default: open, confirmed and retest pending. They used to show everything except false positives. Pass --state all for everything.
  • SARIF fingerprints are brainproxy/v2. They hash the alert, method, URL without its query, and parameter. The first upload after updating may show existing alerts as closed and reopened.
  • New risk level: Critical. Checks and vulnerable JavaScript libraries rated critical are now critical instead of high. A finding seen again at a higher risk is promoted.
  • New states: fixed, accepted_risk and retest_pending. Gates never count an accepted risk or a fixed finding.

New

  • Issues (#95): one issue per alert type on one host, with the findings it was seen at (findings issues, findings issue show | split | merge | title). findings mark --issue N triages them all.
  • Timelines (#95): findings timeline ID shows who did what and when (created, triaged, retested, regressed, moved, removed).
    • A finding marked fixed reopens when a scanner sees it in traffic recorded after the mark.
  • Retest (#95): findings retest ID sends a passive finding's request again and marks it fixed when it no longer shows.
    • It refuses rather than guess: a disabled rule, or a login redirect or error page in reply.
    • It sends only GET, HEAD and OPTIONS unless --allow-unsafe, and stays within scope.
  • Posture (#95): findings posture gives open work at a glance, plus what each active scan found new or no longer found.
  • Report presets and branding (#96):
    • report --preset technical | executive | developer | retest picks the sections, or --sections sets them directly.
    • The developer preset has a curl line per finding; the retest preset is a letter of what changed since --since.
    • --company, --accent and --logo go on the cover.
    • report-profile save | list | show | remove keeps layouts by name.
  • PDF and Word (#96): report pdf prints through a headless Chromium, which fetches nothing; report docx writes a Word document.
  • CVSS 4.0 (#96): findings issue cvss ID VECTOR rates an issue, and reports and SARIF use the score.
  • The report builder in the app (#96): audience, sections, branding and format, with a live preview. Layouts can be saved.
  • Reviewed write-ups (#97):
    • findings issue narrative and report-summary set write an issue's write-up and the executive summary.
    • A new text is a draft until a person reviews it, by the hash of exactly what they read: findings issue review ID --hash H, or Mark reviewed in the app.
    • Reports leave drafts out unless --drafts.
    • Reviewing is refused through MCP.
  • Agent trail (#97): findings trail ID lists what an agent did for a finding: its requests around it, its changes, and the first change a person made afterwards. Reports tag agent-touched findings as reviewed or not.
  • Repro packs and tickets (#97):
    • findings repro ID gives the masked request, a curl command, the response around the evidence and the command that checks it again.
    • findings ticket ID --to github|jira writes a ticket and sends nothing.
    • --record URL keeps the filed ticket's link on the finding. It is refused through MCP.
  • Exports (#97): report csv (formula injection defused), report junit and report defectdojo (with the fingerprint as unique_id_from_tool).
  • Bulk triage (#94):
    • findings mark 7 8 9 --state confirmed marks several findings: all of them change, or none does.
    • The app's findings view has search, source and host filters, checkboxes for bulk marking, and a note editor.
  • A finding's latest sighting (#94) is shown next to its first.
  • CI baselines from a file:
    • findings compare --scan J --baseline FILE compares a scan against a saved report json, matching by fingerprint, so a redacted baseline still compares as unchanged.
    • findings mark --from FILE copies a file's marks (confirmed, false positive, accepted risk) onto the findings that match, from a report json or a list of known false positives. It is refused through MCP.

Fixed

  • A flaky authz live-mode test (#98).

Thanks to @L1ghtn1ng for #94, #95, #96, #97 and #98.

brainproxy 0.5.1

Choose a tag to compare

@github-actions github-actions released this 05 Nov 13:30

brainproxy 0.5.1

This release fixes recorded logins that never counted as logged in. It adds HQL injection scanning and makes the time-based SQL injection payloads actually wait. An agent working through MCP can no longer change what the proxy records, or where your traffic goes, without it showing.

No schema change: 0.5.0 still opens projects saved by this version.

Fixed

  • Recorded logins judged as failed. A recorded login used "the page has a password field" to tell when you were logged out. A logged-in page with a change-password form matched that, so every login, though it worked, was reported as failed ("logged-out pattern matched after login") and retried.
    • Recording now picks a sign that is on the login page and on none of the pages after it: any password field, the login form's own field by name, or the form that posts to the login.
    • The logged-in page can now be the check page even with a password field on it.
    • Profiles recorded before this release keep their old pattern: record the login again, or change the profile's "Logged out" pattern in Settings.
  • sqli-time payloads now wait 5 seconds. 31 of them sent the placeholder __TIME__ as it was, so they could never slow a response. The list's header line, which was also being sent as a payload, is gone (41 payloads).
  • GitHub's download limit. When GitHub's hourly limit for API requests without login is used up, checks update and scan data update now say so and when it resets, instead of a bare "HTTP 403". A full 40-character commit id given as --ref needs no API request.

New

  • HQL injection rule (100003). It finds input built into Hibernate HQL or JPQL queries (EclipseLink, OpenJPA).
    • A random dotted path that only the ORM's query parser reports as unknown confirms it, with high confidence, and the finding names the entity.
    • Otherwise it looks for a new query parser error (medium confidence).
    • 3, 6 or 9 requests per parameter, by strength.
    • The SQL injection rule (40018) no longer reports Hibernate's "unexpected token" parser error as "SQL Injection - Hypersonic SQL".
  • Traffic outside the recording scope still leaves a row (#91, @L1ghtn1ng). Plain HTTP gets a row with its request line; an HTTPS tunnel gets a CONNECT row, written when it opens, so a proxy that is killed still leaves it.
  • Changes to what the proxy records, and to where traffic goes, are logged with who made them. That covers the recording scope, the TLS pass-through list, upstream proxies, host overrides and client certificates (scope show, proxy status, Target › Scope).
    • Narrowing recording: an agent doing it through MCP shows a "Recording narrowed by an agent" warning.
    • Changing routing: an agent doing it shows a "Routing changed by an agent" warning.
    • Clearing a warning: it stays until a person changes that setting or keeps it as it is. Keeping a routing change is the new connection review, which an agent can't run.
    • Keeping the log: an agent's changes stay in the log however many follow; a flood of them is capped at 5,000 and counted.
  • Proxy restarts that are killed partway no longer leave the proxy off (#89, @L1ghtn1ng). If the restart dies partway through, a small background process puts the old proxy back, and proxy status says so. The app keeps track of the proxy it brought back.
  • --sni is checked before connecting (#90, @L1ghtn1ng), and recorded with each request. A refused name leaves no row claiming it was sent.

Changed: opt-ins for requests that can change data

  • A request now needs its method and MUTATION separately. A GraphQL mutation sent as POST to authz run needs --include-methods POST,MUTATION, where MUTATION alone used to be enough. A DELETE that names a persisted query needs DELETE and MUTATION. The app passes both after asking you. Scripts that pass only MUTATION to authz run will now be refused.
  • More GraphQL operations count as mutations, since they can't be shown to be read-only:
    • persisted queries (a hash instead of the query) and Relay doc_id;
    • multipart uploads and form-encoded queries;
    • bodies that can't be decoded;
    • application/graphql+json bodies.
  • authz run --url needs the same opt-in as a request named from history.
  • import api now treats a GraphQL mutation in a Postman collection's body as one.

Other

  • brainproxy capabilities lists 145 commands (new: connection review).
  • Dependencies: tauri-plugin-dialog 2.8.4, @types/node 26.6.6.

Thanks to @L1ghtn1ng for #89, #90 and #91.

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 03 Nov 21:10

brainproxy 0.5.0

This release makes the project a complete record of what was sent, and of who sent it: you, the app, or an AI agent through MCP. It also adds a batch of testing features in the desktop app.

Projects are upgraded to schema v14 when this version opens them. After that, 0.4.x can't open them.

Records you can rely on

  • Every request is recorded before it goes out. This covers send, races, ws send, logins and session checks, check templates, API document fetches and OAuth discovery. A request still leaves a row if the command is stopped, killed or crashes. The app's Stop and an MCP cancel send SIGTERM first, so a stopped request is recorded as cancelled; on Windows it keeps the "sent; no response recorded" row. WebSocket runs are recorded as they happen.
  • proxy stop and restart wait for requests in flight. Ones still unanswered are recorded as stopped.
  • Who did what. History rows record their origin: gui, cli or mcp (an agent). They also record the proxy client's address, the TLS server name used, and who edited a request before it went out (intercept or match-and-replace rule).
    • Findings record who added them, who last changed their state and their note, and when. Reports say so, e.g. "confirmed via MCP (an agent)", and list findings an agent marked false positive.
    • history list --origin mcp finds an agent's traffic, and Traffic has a By column.
  • --no-store keeps a row. The row has the request line without the query string, so a send is never invisible.
  • Rescanning keeps triage. scan passive --rescan keeps your state and notes on findings it finds again.

What an agent can do through MCP

  • Refused:
    • --no-store and fuzz run --store none|matches;
    • a proxy listening anywhere but loopback (start, restart, and saving that as the proxy setup);
    • saving a redirect or invisible mode as the proxy setup;
    • browser open;
    • findings remove;
    • replacing a finding's write-up.
  • --sni must be in scope. A server name other than the target's has to be listed by name in the scope, whoever sends.
  • Naming a request isn't opting in. scan active --history-id and authz run --history-id need --include-methods for DELETE, PUT, PATCH or a GraphQL mutation. authz run refuses a named logout unless --exclude is changed. The app asks before passing these.
  • Check templates follow the same rules. Their requests are recorded, and their PUT, PATCH and DELETE requests or mutations need --include-methods.

New in the app and the CLI

  • Replay:
    • per-tab send options: HTTP/2, send as typed, SNI, timeout, TLS checks, don't record;
    • Stop;
    • racing a request (last-byte sync or the single-packet attack), with each race's rows tagged;
    • pasting a cURL command as a tab, and Copy as cURL;
    • tabs kept in the project (replay tabs list|save).
  • Traffic:
    • search inside requests and responses, and saved filters;
    • scan a request, test its access control, or remove a highlight from the right-click menu.
  • Findings: add findings found by hand (findings add|remove), kept apart from scanner findings in compares and gates.
  • Site map: import an API definition into history without scanning it.
  • Proxy:
    • invisible mode, a redirect, and who can connect, kept per project (proxy setup show|set);
    • proxy restart, so a port move can't be cut into.
  • Codec: gzip, zlib, deflate and brotli, and a smart decode that finds the layers and says why it stopped.
  • Guided API scan: says when a new server sets a saved query key aside, and won't start or import without it.

Behaviour changes

  • A failed HTTP/2 race records every copy and exits 3, with each copy's id in data.results.
  • Every check-template request is recorded, so --checks nuclei runs add many more history rows.
  • An imported API document's fetch is recorded with the response head only. The body's length and sha256 are noted instead, since the document can hold credentials.
  • npm run dev prints a #bridge= link; the dev UI works only when opened from it.

Known limitations

Not covered yet:

  • narrowing the recording scope hides proxy traffic (#82);
  • the Host header isn't checked against scope, on purpose, for Host-header tests (#83);
  • remaining provenance gaps (#84);
  • crawl, authz, fuzz and scan attacks still record after the response (#85);
  • smaller items: #86, #87, #88.

Thanks to @L1ghtn1ng for PRs #70–#81.

v0.4.7

Choose a tag to compare

@github-actions github-actions released this 02 Nov 21:05

brainproxy 0.4.7

A guided scan for APIs, four new active rules, and a choice of proxy port in the desktop app.

Guided API scan

  • The desktop app's new wizard takes an OpenAPI, Swagger or Postman definition (or a GraphQL schema or endpoint). It shows every operation before anything is sent, then runs one job that sends each ticked operation once and attacks it.
  • On the command line:
    • import api detects the format, and --dry-run previews the import.
    • scan active --api imports and scans in one job.
    • Both take --server, --only, --expect-sha256 and --include-methods.
  • PUT, PATCH, DELETE and GraphQL mutations stay off unless you tick them or pass --include-methods. This holds in later scans too, however the request was recorded.
  • Credentials a document declares are reported by name, never sent or stored. Postman environment files (--environment) are handled the same way.
  • Authentication is optional:
    • API keys in a header or the query (auth add --header-env, --query-key).
    • OAuth 2.0: client credentials, password, refresh token, and browser sign-in with PKCE (auth oauth authorize). Tokens are renewed before they expire and on a 401. auth oauth discover reads an OpenID Connect discovery document.
    • Request signing: AWS SigV4, private-key signatures, and JWTs.
    • A collection's pre-request script can be used as a signer (auth sign add --script), but only after you have read and chosen it. Each script runs in its own process with no file, network or process access, and is stopped after 5 seconds.
  • A refresh token is saved in the project only with --oauth-store-secrets.
  • Through MCP, a tool call can't add a script signer or open a browser. Environment variables it names must start with BRAINPROXY_SECRET_.

Active rules

Four rules ported from ZAP's ascanrulesBeta:

  • CORS misconfiguration (40040)
  • Server Side Request Forgery (40046, uses oob start)
  • NoSQL injection for MongoDB (40033)
  • NoSQL injection for MongoDB, time-based (90039)

scan active now runs 52 rules.

Desktop app

  • Settings › Proxy lets you choose the port the proxy listens on. A running proxy can be moved there, and goes back to the old port if the new one can't be opened.
  • Closing a project stops only a proxy the app started itself, not one started from a shell or an agent.

Known limitations

  • Script signers have a memory limit only on Linux (#65).
  • In the guided API scan, changing the server drops a saved query key without saying so (#66).