Skip to content

Redact credentials from logged URLs, VEX product ids and hosted Composer locks - #1026

Draft
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
mainfrom
arch-fix/sec-credentials
Draft

Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
mainfrom
arch-fix/sec-credentials

Conversation

@mikolalysenko

Copy link
Copy Markdown
Collaborator

Problem

Architecture audit, credential leaks:

  • B02 / Hosted Composer rewrite keeps the entry's transport-options, so Composer sends a private repository's auth headers to the hosted patch URL #399: the hosted Composer rewrite pointed dist.url at the patch host but kept the entry's transport-options. Composer copies a repository's options (http.header auth tokens, ssl client certificates, http.proxy) into each lock entry and applies them to that entry's dist download, so every composer install sent the private registry's credentials to the hosted patch server. The vendored backend already dropped the key, but with its own hand-written list.

  • B26: grant tokens and URL userinfo reached --json events, CI logs, debug output and telemetry:

    • 8 hand-written vendor_prebuilt_downloaded advisories quoted the grant URL;
    • registry_fetch::download and the Maven fetch errors quoted GOPROXY, .npmrc and mirror URLs, reqwest's error text included;
    • client.rs debug lines and artifact errors quoted grant URLs;
    • telemetry::sanitize_error_message only replaced $HOME, and patch_fetch_failed.uuid carried whatever identifier the user passed (CVE, purl, private package name).

    redirect::redact_grant_token had a single caller.

  • B21: the VEX product @id fell back to the raw git origin URL for unknown hosts and GitLab subgroups, so https://gitlab-ci-token:<token>@… and https://<PAT>@… were published in the OpenVEX document.

Change

  • New utils::redact is the one redactor. redact_url / redact_urls_in replace userinfo, the Socket grant-token level (the path level before the patch uuid under /patch/ or /patch-registry/) and secret query values with <redacted>. strip_url_credentials is the identifier form, and url_host is the userinfo-safe host.

  • Each emission point now goes through it:

    • VendorWarning::new (every vendor advisory);
    • registry_fetch::download and maven_repo::fetch_registry_bytes;
    • api::client's debug_log, network_error_detail and artifact errors;
    • telemetry::sanitize_error_message.

    patch_fetch_failed now sends uuid only when the identifier is a uuid.

  • VEX: a remote that falls back to the URL is stripped of credentials first. An ssh login name (ssh://git@host/…) and scp-like remotes are kept, so existing product ids don't change.

  • Composer: formats::composer::ORIGIN_BOUND_ENTRY_KEYS (source, transport-options) is shared by the vendored rewrite_lock_entry and the hosted apply_dist_edit.

    • The hosted splice drops every listed member, rescanning between removals so adjacent members never leave a dangling comma.
    • It widens the recorded edit to cover every changed byte, so the ledger's fragment revert restores them.
    • It warns with the new code redirect_composer_transport_options_removed, documented in docs/testing/composer-compatibility.md.

Duplicate copies deleted

What Before After
vendor_prebuilt_downloaded advisory builders 8 1 (VerifiedArchive::downloaded_warning, pinned by a ratchet test)
URL redactors 2 (redirect::redact_grant_token with 1 caller; hosted::guidance::url_host's userinfo strip) 1 (utils::redact)
Userinfo-stripping host extractors 2 (hosted::guidance::url_host, patch/redirect/upstream/uv.rs) 1
Composer origin-bound key lists 2 (vendored match arms; hosted source-only plan) 1

Testing

Run on macOS:

  • cargo test -p socket-patch-core --lib: 5585 passed, 2 failed. After regenerating the vex-discover golden for the new fixture, vex::discover::testing::golden passes. The other failure, utils::digest::tests::production_digests_go_through_the_helpers, fails on main too: it names crawlers/gradle_cache.rs, patch/jvm_jar.rs and patch/sidecars/maven.rs, none of which this PR touches.
  • cargo test -p socket-patch-core --test redirect_golden --test upstream_restore_golden passed, including the new composer-lock/transport-options case and its round-trip restore.
  • cargo test -p socket-patch-cli passed for in_process_redirect, hosted_memory_engine, hosted_memory_parity, e2e_vex, covgap_commands_vex, in_process_vendor, scan_vendor_e2e, e2e_vendored_production, e2e_hosted_production and e2e_embedded_vex.
  • cargo clippy -p socket-patch-core --all-targets -- -D warnings reports only lints that already fail on main under the local toolchain: maven_repo.rs:2514 and nuget_feed.rs:2005 (empty line after doc comment) and python_crawler.rs:2734 (unused unix_default). There are no lints in changed code. The same python_crawler lint stops the CLI clippy build.
  • New tests:
    • utils::redact unit tests and the ratchet;
    • telemetry URL redaction and uuid-only field;
    • vex::product::remote_url_credentials_never_reach_the_product_id;
    • formats::composer::source::transport_options_are_dropped_with_source_in_any_layout;
    • golden composer-lock/transport-options.

Deferred

🤖 Generated with Claude Code

Add utils::redact, the one place a URL is made safe to show: userinfo,
the Socket grant-token path level (the level before the patch uuid under
/patch/ or /patch-registry/) and secret query values become <redacted>.
Route every emission through it:

- VendorWarning::new redacts its detail, so the vendor_prebuilt_downloaded
  advisory (8 hand-written copies, now one VerifiedArchive::
  downloaded_warning builder) no longer puts the grant URL into --json
  events and --verbose output;
- registry_fetch::download and maven_repo::fetch_registry_bytes errors
  (GOPROXY / .npmrc / mirror userinfo, reqwest's own error text);
- api::client debug_log, network_error_detail and the artifact
  not-found / still-building / non-http errors;
- telemetry::sanitize_error_message; patch_fetch_failed now reports the
  uuid field only when the identifier is a uuid, not a CVE, purl or
  private package name.

Consolidation: redirect::redact_grant_token (1 caller, vlt preflight) is
deleted and the caller routed through redact_urls_in; the userinfo-safe
host extractor hosted::guidance::url_host and the upstream/uv.rs copy
are replaced by utils::redact::url_host. A ratchet test pins the
download advisory to its single builder.

Audit B26.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
remote_url_to_purl fell back to the raw origin URL for any host other
than github.com / gitlab.com / bitbucket.org and for any non owner/repo
path (a GitLab subgroup), so a CI clone's
https://gitlab-ci-token:<job token>@host/... or https://<PAT>@host/...
was published verbatim in the OpenVEX document. The fallback now goes
through utils::redact::strip_url_credentials (userinfo and secret query
parameters dropped); an ssh login name (ssh://git@host/...) and
scp-like remotes stay as they were, so existing product ids do not move.

Audit B21.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Composer copies a repository's options (http.header auth tokens, ssl
client certificates, http.proxy) into every lock entry it resolves from
it as transport-options, and applies them to that entry's dist download.
The hosted rewrite retargeted dist.url to the patch host but kept
transport-options, so every composer install sent the private
repository's credentials to the hosted patch server.

The origin-bound entry members are now one list,
formats::composer::ORIGIN_BOUND_ENTRY_KEYS (source, transport-options),
used by both backends: the vendored rewrite_lock_entry (which already
dropped both by hand) and the hosted apply_dist_edit, which now drops
each member, re-scanning between removals so adjacent members never
leave a dangling comma, and widens the recorded edit to cover every
changed byte so the ledger's fragment revert restores them. A new
warning, redirect_composer_transport_options_removed, says so.

New golden case composer-lock/transport-options (plus its vex-discover
golden entry) and a unit test over five member layouts.

Fixes #399. Audit B02.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko Mikola Lysenko (mikolalysenko) added the arch-refactor PR opened by the scheduled architecture refactor routine label Oct 7, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-refactor PR opened by the scheduled architecture refactor routine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant