Repository navigation
Releases
v0.8.3
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, akidpointing at/dev/null, RS/PS to HS256 algorithm confusion with the site's public key, andjku/x5ucallbacks withoob start. The passive rule 100008 JWT Issues reports tokens in query strings, and server-issued tokens withalg: none, noexp, 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 (
%againstXYZABCDEFGHIJ) is no longer sent: a parameterisedLIKEwith 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_notecould 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;queryrefuses 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.testmatchedhttps://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 --limitwithout--all,--statetypos,--remove-header Content-Length;auth add --keep-passwordkeeps 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 andinheritauth; 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.mdfor coding agents; everyunsafeblock 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
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 Nsends 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.
- From the CLI:
- 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 runandscan activetake--http3, and Replay, Fuzzer and Scans have an HTTP/3 option. Endpoints a site advertises withAlt-Svcare 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
requestruns 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
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,-shmand-journalfiles, 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 QUERYholds only what a filter-language query matches, for examplemethod=POST NOT path:/staticorstatus:5xx. The app has this too (#126). - Less noise in access-control testing:
authzand the Access view leave out static assets (judged by content type,Sec-Fetch-Destor 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-statictests 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-debandmake dev-macosbuild 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-staticor 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
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,literalandwhole. A rule can be limited to engines (--applies-toproxy, send/Replay, fuzz, scan) and to hosts.rules testtries 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 importreads whatrules listprints. -
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-streamresponses are relayed through the proxy as they arrive instead of waiting for the end. Their events are recorded in the project (ssecommands, the app's Event streams view).sendreads a stream for a bounded time. -
Login replay (#118):
- auth profiles can hold a TOTP secret (RFC 6238;
--totp-secret-envreads it at each login and stores nothing), with{{totp}}in login steps; auth record startalso 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;--passkeyrecords 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.
- auth profiles can hold a TOTP secret (RFC 6238;
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
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 --filterand the app's Query mode. Filters can be saved in the project, andhistory exporttakes--filtertoo (#110). - HAR: import HAR files as scan targets, and export history as HAR (#109).
- Race: race a group of different requests together, from
sendand 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 --apiand--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/-oare readable only by you (0600). So are background job logs and fuzz request and log files.--forcestill works with/dev/nulland pipes. - More credentials are masked:
- any header whose value carries an auth scheme, whatever the header is called;
- any
*-Keyheader that isn't a data key (Sort-Key,Primary-Keyand similar stay visible); Authorisation;- WebSocket subprotocol tokens, including the Kubernetes form;
- bare cookie values;
- JSON names written with
\uescapes; 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
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;hoststays 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,
:authorityor 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.
- Host header tests are still possible: pass
- More is refused through MCP (#102):
--forceon report, ca export, ca init and findings repro;report-profile saveover an existing layout;report-profile removeis not a tool. - Every scan request is recorded before it is sent (#85): crawls, active scans, authz,
fuzz --store alland 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 passscan active --prunefor 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.
- To keep only the attack requests that back a finding, turn on
New
--maskonreportandfindings 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 statussays 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
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,
Authorizationcredentials, 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-redactkeeps everything, and the report says so. findings listand reports show work still to do by default: open, confirmed and retest pending. They used to show everything except false positives. Pass--state allfor 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_riskandretest_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 Ntriages them all. - Timelines (#95):
findings timeline IDshows 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 IDsends 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 posturegives 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 | retestpicks the sections, or--sectionssets them directly.- The developer preset has a curl line per finding; the retest preset is a letter of what changed since
--since. --company,--accentand--logogo on the cover.report-profile save | list | show | removekeeps layouts by name.
- PDF and Word (#96):
report pdfprints through a headless Chromium, which fetches nothing;report docxwrites a Word document. - CVSS 4.0 (#96):
findings issue cvss ID VECTORrates 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 narrativeandreport-summary setwrite 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 IDlists 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 IDgives the masked request, a curl command, the response around the evidence and the command that checks it again.findings ticket ID --to github|jirawrites a ticket and sends nothing.--record URLkeeps the filed ticket's link on the finding. It is refused through MCP.
- Exports (#97):
report csv(formula injection defused),report junitandreport defectdojo(with the fingerprint asunique_id_from_tool). - Bulk triage (#94):
findings mark 7 8 9 --state confirmedmarks 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 FILEcompares a scan against a savedreport json, matching by fingerprint, so a redacted baseline still compares as unchanged.findings mark --from FILEcopies a file's marks (confirmed, false positive, accepted risk) onto the findings that match, from areport jsonor a list of known false positives. It is refused through MCP.
Fixed
- A flaky authz live-mode test (#98).
brainproxy 0.5.1
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-timepayloads 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 updateandscan data updatenow say so and when it resets, instead of a bare "HTTP 403". A full 40-character commit id given as--refneeds 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
CONNECTrow, 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 statussays so. The app keeps track of the proxy it brought back. --sniis 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 runneeds--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 toauthz runwill 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+jsonbodies.
- persisted queries (a hash instead of the query) and Relay
authz run --urlneeds the same opt-in as a request named from history.import apinow treats a GraphQL mutation in a Postman collection's body as one.
Other
brainproxy capabilitieslists 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
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 stopand restart wait for requests in flight. Ones still unanswered are recorded as stopped.- Who did what. History rows record their origin:
gui,cliormcp(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 mcpfinds an agent's traffic, and Traffic has a By column.
--no-storekeeps a row. The row has the request line without the query string, so a send is never invisible.- Rescanning keeps triage.
scan passive --rescankeeps your state and notes on findings it finds again.
What an agent can do through MCP
- Refused:
--no-storeandfuzz 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.
--snimust 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-idandauthz run --history-idneed--include-methodsfor DELETE, PUT, PATCH or a GraphQL mutation.authz runrefuses a named logout unless--excludeis 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.
- invisible mode, a redirect, and who can connect, kept per project (
- 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 nucleiruns 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 devprints 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
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 apidetects the format, and--dry-runpreviews the import.scan active --apiimports and scans in one job.- Both take
--server,--only,--expect-sha256and--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 discoverreads 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.
- API keys in a header or the query (
- 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.