srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/PLUGINS.md
AgeCommit message (Collapse)AuthorFilesLines
2026-08-26Second plugin: paramminer, a Param Miner-style hidden parameter probersrdusr1-8/+16
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.
2026-08-25Wire-format JSON tag consistency fix, and the first real pluginsrdusr1-0/+8
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.
2026-08-04Plugin protocol foundation: tag_entry, tag search/sort, TUI tag viewsrdusr1-0/+117
The prerequisite for the plugin ecosystem: any external process - any language - that can reach the control socket can now tag a history entry with a short string marker and an opaque JSON data blob, stored in a new entry_tags table rather than requiring the plugin stay connected for a later live round-trip. A plugin does its analysis once; the data it attaches is what a human reviewing the entry later actually sees. internal/ipc: new "tag_entry" request (id, tag_plugin, tag, tag_data) and EntryDetail.Tags (the full record for one entry, populated by "get"). internal/store: entry_tags table, EntryTag struct, AddEntryTag/ ListEntryTags, a comma-joined Tags aggregate added to List/Search via a correlated subquery (cheap enough per row that showing a tag badge in the history list needs no N+1 query), and a new tag: search filter alongside the existing status:/source:/flagged:. TUI: a Tags column in the history table (sortable via o/O, the eighth sort column), T from detail view opens a tag list (mirroring the WebSocket-messages view's table-then-detail-viewport pattern), enter on one shows its data - JSON-colorized via the existing jsoncolor.go if it parses as JSON, sanitized plain text otherwise. Also fixed a pre-existing gap while touching this: the WebSocket-messages view never got mouse wheel support when it shipped; wired both it and the new tags view up together. PLUGINS.md documents the wire protocol for non-Go plugin authors - connection model (subscribe vs request/response), the handful of request types a plugin actually needs, and the trust boundary (the socket has no auth beyond OS file permissions, same as the TUI's own access). PLAN.md records the architecture decision (external process over an embedded scripting language - mirrors the daemon/TUI split already in place, no interpreter to sandbox, any language) and groups ~20 researched Burp extensions/Pro features into what Phase 1 already covers (Autorize, Param Miner, Backslash Powered Scanner, Retire.js - all just subscribe+repeat+tag, no new capability needed), what needs a second protocol addition (JWT Editor, SAML Raider - live RPC to a specific connected plugin for interactive actions like re-signing), and what deserves its own separate project rather than a plugin (active vulnerability scanning, Collaborator/OAST, a crawler). Verified live end to end against a real daemon: a throwaway program simulating a real plugin tagged a captured entry with structured JWT data over the actual wire protocol; confirmed the tag badge, tag: search filter, and full tag record all round-tripped correctly through List/Search/Get. Confirmed in the TUI itself (tmux, real keystrokes): the Tags column renders, T opens the tag list, entering it shows the JSON data with real ANSI-verified syntax highlighting (not just eyeballed), and tag: search filtering works from the history list.