<feed xmlns='http://www.w3.org/2005/Atom'>
<title>mitmux/plugins, branch main</title>
<subtitle>Terminal-based intercepting HTTP proxy.
</subtitle>
<id>https://srdusr.com/git/mitmux/atom?h=main</id>
<link rel='self' href='https://srdusr.com/git/mitmux/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/mitmux/'/>
<updated>2026-08-28T07:42:00+00:00</updated>
<entry>
<title>Fourth plugin: bpscanner, a Backslash Powered Scanner-style detector</title>
<updated>2026-08-28T07:42:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2026-08-28T07:42:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/mitmux/commit/?id=2ee4a95c9ccc701482c88f58840568738354dc36'/>
<id>urn:sha1:2ee4a95c9ccc701482c88f58840568738354dc36</id>
<content type='text'>
- Phase 1 plugin ecosystem complete

The last of the four "cheap IPC win" plugins identified in the
original research pass. Different mechanism from the other three,
deliberately: where paramminer finds parameters that shouldn't exist,
bpscanner tests parameters that already do, asking a more general
question than a signature-based scanner does - does the backend treat
syntactically-significant characters ('"\&lt;&gt;(){}$;|&amp;, covering SQL
quoting, HTML/JS, shell metacharacters, and template syntax at once)
differently than an equal-length string of inert filler? That question
doesn't need to know what the backend is built on, the whole appeal of
the real tool this borrows its name and idea from.

For each existing query parameter, sends two same-length replacement
values wrapped in a stable marker - one filler, one special-character
- and checks whether the marker itself came back intact, not just
whether the response looks different overall. An endpoint that never
reflects the parameter at all naturally produces "both intact: false,"
which correctly isn't a finding - the marker-reflection design avoids
false-positiving on the common case of a parameter that's read but
never echoed.

Verified live against a deliberately realistic scenario: an origin
with one endpoint that strips a few special characters before
reflecting a parameter (a naive-sanitizer/WAF-like pattern) and one
that reflects verbatim (the control case) - the sanitizing endpoint
was correctly tagged with the exact differential
(control_marker_intact: true, special_marker_intact: false), the
verbatim endpoint correctly left alone.

This closes Phase 1: every plugin identified as a "cheap IPC win" - no
new protocol capability needed beyond tag_entry itself - is now real,
working, and live-verified (authcheck, paramminer, jslibscan,
bpscanner).
</content>
</entry>
<entry>
<title>Third plugin: jslibscan, a Retire.js-style passive JS library scanner</title>
<updated>2026-08-27T19:21:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2026-08-27T19:21:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/mitmux/commit/?id=8748df8a30b038e429aeeff1684e1014f42a68ee'/>
<id>urn:sha1:8748df8a30b038e429aeeff1684e1014f42a68ee</id>
<content type='text'>
The first purely passive plugin in the reference set: subscribe,
inspect a response body already captured by ordinary proxying, tag -
no repeat calls at all, unlike authcheck and paramminer. Deliberately
included as the safest possible plugin to try first, since it never
sends anything of its own.

Checks any JS library version string found in a response against a
small, explicitly-illustrative built-in table (jQuery, Lodash,
Handlebars, Moment.js, AngularJS - one well-known vulnerable-version
threshold each), tagging a match jslibscan:hit with the version found,
the fix version, and a plain-language advisory. Not a maintained
vulnerability feed the way real Retire.js's database is, and says so
in its own package doc; CVE numbers deliberately omitted in favor of
describing the vulnerability class, rather than asserting a specific
identifier this reference implementation hasn't independently verified.

Found and fixed a real regex bug by testing live rather than trusting
the code: the first version failed to match jQuery's own actual banner
comment ("jQuery v1.8.3") because the separator pattern only allowed a
single character between library name and version digits, and that
banner has two (space, then "v"). Fixed with a bounded non-greedy gap
verified against three real-world version-string shapes at once
(banner comment, minified filename, cache-busting query string) before
going back into the plugin.

Verified live end to end: a real daemon, a real origin serving both an
outdated jQuery 1.8.3 banner and a current 3.7.1 one - the outdated
file was correctly tagged with the right version and threshold, the
current one correctly left alone. The same run incidentally
reconfirmed the regex fix was real: an entry captured moments earlier
against the buggy binary sat right next to the correctly-tagged one,
itself untagged.
</content>
</entry>
<entry>
<title>Second plugin: paramminer, a Param Miner-style hidden parameter prober</title>
<updated>2026-08-25T23:06:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2026-08-25T23:06:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/mitmux/commit/?id=cfe01fef65af082dccfc69b2fc78cb07a36ac2b4'/>
<id>urn:sha1:cfe01fef65af082dccfc69b2fc78cb07a36ac2b4</id>
<content type='text'>
For every distinct GET endpoint (deduplicated in-memory so revisiting
a URL doesn't rerun the whole wordlist each time), sends a fresh
baseline resend plus one probe per candidate from a ~40-entry wordlist
of parameter names real backends surprisingly often read even when
never part of any observed request (debug, admin, redirect, role,
token, and similar). A probe whose response differs from baseline by
more than a small threshold (body length, or a different status
outright) is a likely hit, tagged paramminer:hit with the parameter
name and both response sizes as evidence. Deliberately GET-only with a
modest wordlist, not exhaustive POST/JSON-aware probing - same "small
honest v1" reasoning as authcheck's single-identity simplification.

Same discipline as authcheck: speaks the wire protocol directly, no
internal/ipc import, proving PLUGINS.md's documented protocol is
actually sufficient on its own.

Found and documented two real, non-obvious net/http behaviors while
building this: Request.Write ignores the RequestURI field entirely
(confirmed directly - a deliberately stale RequestURI still produced
the correct output, since Write derives the request line from
Request.URL instead) and silently adds a default User-Agent header if
the cloned request didn't already have one. Neither affects
correctness here since baseline and every probe get identical
treatment, but both are worth knowing before reusing this resend
pattern elsewhere.

Verified live end to end: a real daemon, a real Python origin with a
genuinely hidden debug parameter that substantially changes the
response, and a control endpoint that's stable regardless of any extra
parameter - the hidden-parameter endpoint was correctly tagged with
exactly the right parameter name, the stable one correctly left alone,
confirmed via tag: search and visually in the TUI with the JSON-array
tag payload rendering correctly.
</content>
</entry>
<entry>
<title>Wire-format JSON tag consistency fix, and the first real plugin</title>
<updated>2026-08-25T13:58:00+00:00</updated>
<author>
<name>srdusr</name>
<email>99972264+srdusr@users.noreply.github.com</email>
</author>
<published>2026-08-25T13:58:00+00:00</published>
<link rel='alternate' type='text/html' href='https://srdusr.com/git/mitmux/commit/?id=9e94bcbc939afd38b45f9ef42e1b1666fafd8d45'/>
<id>urn:sha1:9e94bcbc939afd38b45f9ef42e1b1666fafd8d45</id>
<content type='text'>
Writing PLUGINS.md as an authoritative external spec surfaced a real,
pre-existing bug: store.Summary/Entry/EntryTag/WSMessage, rules.Rule,
scope.Rule, and clientcert.Cert had no JSON struct tags at all, so Go's
default marshaling serialized them PascalCase ("ID", "StartedAt")
while the rest of the protocol (EntryDetail's own fields, every
Request/Response wrapper field) uses snake_case. Confirmed live against
a real daemon before touching anything: a raw socket "list" request
came back with "ID"/"StartedAt"/"StatusCode", exactly the mismatch
suspected. Nothing outside this repo's own Go code consumes this wire
format yet, so this was a free, purely additive fix rather than
something to work around - every affected struct now tags snake_case
consistently.

plugins/authcheck is the first real plugin: an Autorize-style
authorization checker. For every proxied request carrying an
Authorization or Cookie header, resends it with that header stripped
and compares status classes - a resend that still succeeds where the
original did too is a likely missing-function-level-access-control
bug, tagged authcheck:bypass with structured detail. Deliberately
speaks the wire protocol directly (its own local request/response/
summary/entryDetail structs mirroring the real ones field-for-field,
not imported from internal/ipc) rather than taking the shortcut a Go
plugin could - proof the documented protocol is actually sufficient on
its own, since that's all a non-Go plugin author has to work with.

Verified live end to end: a real daemon, a real Python origin with one
endpoint that looks like it enforces auth but doesn't (vulnerable by
design) and one that actually does (the control case) - the broken
endpoint was correctly tagged, the secure one correctly left alone, no
false positive, confirmed both via the stored tag data directly and
visually in the TUI (tmux, real keystrokes): the Tags column badge, T's
tag list, and the tag detail view's JSON-colorized data (ANSI-verified,
not eyeballed) all showing the plugin's actual findings.
</content>
</entry>
</feed>
