Skip to content

row 159: a settings-derived need target drops its userinfo; the webhook sink sends it as Basic, as 1.5.5 did (audit export-webhook #1, HIGH) - #842

Merged
MattJackson merged 4 commits into
predevfrom
lane-audit-webhook-userinfo
Oct 15, 2026
Merged

MattJackson merged 4 commits into
predevfrom
lane-audit-webhook-userinfo

Conversation

@MattJackson

Copy link
Copy Markdown
Collaborator

Audit pinned export-webhook finding #1 (HIGH), under the ARCHITECT ruling and its conditions (a) to (d).

Why. THE DESIGN §2, "A port keeps 1.5.5's surface ... wire bytes ... the default is 1.5.5's behaviour."

  • In 1.5.5, a webhook URL https://user:pass@host/path was sent with Authorization: Basic. reqwest 0.12's RequestBuilder::new (extract_authority) moved the userinfo into basic_auth.
  • Today the sink's need targets the raw settings.url. The connector refuses any need target that carries a userinfo, so the sink is disabled (BUSBAR-7070) and delivers nothing.

What.

  1. Connector (crates/busbar-core-connector/src/lib.rs, declare).

    • (a) A target read from the plugin's own settings through target_from (settings.<key>[...], not a member path) is declared without its userinfo. The authority's text through its last @ is left out.
    • (a) The general refusal stays. Any other target carrying a userinfo is still refused: no target_from, a member path, or a path outside the plugin's settings. A settings-derived target whose userinfo this reading cannot clear is also refused.
    • (b) The text left out is dropped. It is never stored (the pin holds the cleared target), never logged, never judged and never put in any error text.
    • (d) The rule is neutral and names no scheme: userinfo is not part of a settings-derived target. Nothing in busbar-contract changes.
  2. Sink (c). export-webhook: a userinfo in the URL is sent as authorization: Basic, as 1.5.5 sent it (audit export-webhook #1, HIGH) busbar-export-webhook#19 (export-webhook: a userinfo in the URL is sent as authorization: Basic, as 1.5.5 sent it (audit export-webhook #1, HIGH) busbar-export-webhook#19, head b5240b33d1da15007fac3f74a1ead87f06289fe4) builds authorization: Basic from its own settings.url the way reqwest 0.12 did:

    • the same percent-decoding,
    • the same user:pass join, with a user alone sent as user:,
    • the same precedence when an auth header is also configured: the Basic field first, then content-type, then the configured header. One also named Authorization is sent too, right after the Basic field, as HeaderMap::append held both in 1.5.5.

    The parity tests are in that PR.

  3. Pin. busbar-export-webhook and busbar-export-webhook-plugin move from 46cd95ba78f6 to b5240b33d1da (Cargo.toml rev, Cargo.lock sources). That head also carries the plugin's dev commits since 46cd95ba78f6: the door states ready, refusals are said in 1.5.5's words, and dropped deliveries are warned. If the plugin PR squashes, re-point this pin to the plugin's merged commit before this lands.

REDs (crates/busbar-core-connector/src/tests/connector_tests.rs).

  • a_settings_derived_target_is_declared_without_its_userinfo covers the http://user:pass@host:port/path, user:pass@host:port and user@host:port forms.
    • Each one declares, is pinned to the cleared target, and opens there.
    • It runs under a log capture (busbar_contract::testkit::WarnCapture at DEBUG). The kept records (the pinned target and the declared spec) and every error text from a refused settings-derived target (a metadata host) and its open are scanned for the user and the password.
  • a_target_not_from_its_own_settings_carrying_a_userinfo_is_still_refused checks that a userinfo target under target_from "", settings.*.url, request.url, settings. and settings..url is refused, with the refusal kept and nothing opening on it. A backslash-spelled settings-derived target is also refused.
    • It replaces a_declared_target_carrying_a_userinfo_is_refused, whose settings.url arm the ruling reverses.

tracing joins the connector's [dev-dependencies], only to install the capture. Cargo.lock gains one line for it.

Collision check. The open connector PRs #804, #805 and #800 move the proxy env reading and do not touch declare or carries_userinfo. #837, #834, #827, #825, #819, #807, #778 and #561 touch other hunks of lib.rs. This change is two small helpers next to carries_userinfo plus three lines in declare.

…nector drops it, and still refuses any other target carrying one

Audit export-webhook #1 (HIGH), ARCHITECT ruling (a), (b), (d). A need's target read from the
plugin's own settings through target_from (settings.<key>[...], no member path) is declared
without its userinfo: the authority's text through its last '@' is left out, and the text left out
is never recorded, judged, logged or put in an error. Every other target carrying a userinfo (no
target_from, a member path, a path outside its settings), and a settings-derived one whose
userinfo this reading cannot clear, is refused as before. The rule names no scheme; nothing in the
contract changes.

REDs (crates/busbar-core-connector/src/tests/connector_tests.rs):
- a_settings_derived_target_is_declared_without_its_userinfo: URL, user:pass@host:port and
  user@host:port forms declare, pin to the cleared target and open there; a log capture
  (busbar_contract::testkit::WarnCapture at DEBUG), the kept records and every error text are
  scanned for the user and the password.
- a_target_not_from_its_own_settings_carrying_a_userinfo_is_still_refused: replaces
  a_declared_target_carrying_a_userinfo_is_refused, whose settings.url arm the ruling reverses.

tracing joins the connector's dev-dependencies to install the capture.
…bhook#19): a userinfo in the webhook URL is sent as authorization: Basic, as 1.5.5's reqwest 0.12 sent it

Audit export-webhook #1 (HIGH), ARCHITECT ruling (c). The pin moves from 46cd95ba78f6 to the
plugin PR's head, which also carries the plugin's dev commits since 46cd95ba78f6 (the door states
ready; refusals in 1.5.5's words; drops warned). Re-point to the plugin's merged commit before
this lands if that PR squashes.
…nce (law0 busbar-core-connector x export 4 -> 1)

Three comments cited the finding by the export instance's name, three instance-vocabulary hits in
a neutral crate (kind-isolation:law0 / law0-base). They now cite the ruling without naming it; no
code moves and no ceiling is touched.
…ar-export-webhook pin b5240b33d1da. BUSBAR-7071/7072 are actionable and warned on every dropped line, as 1.5.5 warned them (the sink's declares since 98d4432d84, which the old pin 46cd95ba78 predated)
@MattJackson
MattJackson merged commit b5c00f6 into predev Oct 15, 2026
1 check was pending
@MattJackson
MattJackson deleted the lane-audit-webhook-userinfo branch October 15, 2026 05:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant