Skip to content

fix: SDK credential hygiene in HTTP wrappers and tools client [SAP-4383] - #1267

Closed
antoine-berger wants to merge 21 commits into
mainfrom
antoine-berger/ship-plan-sap-4383
Closed

antoine-berger wants to merge 21 commits into
mainfrom
antoine-berger/ship-plan-sap-4383

Conversation

@antoine-berger

Copy link
Copy Markdown
Contributor

Primary change type

  • Bug fix
  • Documentation
  • Feature
  • Tests
  • Dependency update
  • Maintenance or refactor

Problem and motivation

Credential hygiene pass over the HTTP wrappers and the tools client: tighten where the SDK attaches or records credentials, so each one stays on the channel and host it was meant for and out of serialized or recorded data.

Summary and scope

  • core / analytics-core: Sapiom-Identity is attached only over https (or http to loopback). New shared helpers: sanitizeFactHeaders / redactUrlForFacts / redactSearch for transaction facts, and fetchDroppingIdentityCrossOrigin, which drops Sapiom-Identity on a cross-origin redirect. sapiom-identity joins the cross-origin drop list.
  • axios: the identity audience is checked against getUri(config), the URL axios actually requests. __sapiom.enabled: false also skips identity. A chained beforeRedirect drops the header on a cross-origin hop. Facts go through the shared redaction.
  • fetch: __sapiom is read from init as well as from a Request (the opt-out and per-request metadata now work in both places). Identity is dropped on cross-origin redirects. Facts are redacted.
  • node-http: facts are redacted through the same helpers.
  • tools:
    • Transport keeps the API key and resume token in runtime-private fields and serializes and logs only non-secret settings.
    • A shared encodeSegment rejects "", . and .. for ids used as path segments.
    • Service-returned URLs (LLM grant links, media poll URLs) must stay within the configured Sapiom deployment.
    • Google connector bare paths are resolved before being appended to the proxy route.

Out of scope: credentialFetch itself is unchanged, and so are sandbox filesystem paths (they keep their own check).

Related work

Related issue or discussion: SAP-4383 (internal tracker)

Validation

pnpm build — pass
pnpm typecheck — pass
pnpm lint — pass
pnpm credential-header:check — pass
pnpm -r --no-bail --filter='./packages/*' --filter='!@sapiom/harness' test — pass (all packages)
pnpm test (harness) — node-pty native module not built in this environment (installed with --ignore-scripts); unrelated to this diff

Tests and documentation

New or extended tests:

  • core: IdentityManager channel, identity-fetch, facts-redaction.
  • axios: identity.test.ts, with local http servers for the redirect cases.
  • fetch: per-request __sapiom handling and redirects.
  • Facts redaction in all three wrappers' integration tests.
  • tools: transport-serialization.spec.ts, path-segment.spec.ts and trusted-url.spec.ts, plus llm redeem, content-generation poll and Google bare-path cases.

The fetch README documents init.__sapiom.

Compatibility and release impact

  • Breaking or externally visible changes:
    • Identity is no longer sent over plain http to non-loopback hosts.
    • Ids "", . and .. now throw TypeError before any request.
    • A service-returned URL outside the configured deployment now throws CredentialChannelError.
    • llm.redeem takes an optional trailing baseUrl.
    • Recorded transaction facts no longer carry credential headers or query values.
  • Changeset: Added (sdk-credential-hygiene.md, patch for core, analytics-core, axios, fetch, node-http, tools).

Security

  • I have not included secrets, credentials, private data, or unsanitized logs.
  • This pull request does not publicly disclose a suspected vulnerability. I
    will follow the
    Security Policy for
    private reporting.

AI assistance

  • I did not use AI assistance for this change.
  • I used AI assistance and have described it below.

Claude Code (Opus) wrote the implementation and tests from an approved plan. The result was verified with the build, typecheck, lint and test commands above, plus independent review before marking ready.

Checklist

  • I read CONTRIBUTING.md, and this contribution follows the direct-PR or issue-first policy.
  • This pull request addresses one focused problem and contains no unrelated cleanup.
  • I added or updated tests, or explained above why tests are not applicable.
  • I ran the relevant build, typecheck, lint, and test commands, or explained
    any N/A checks above.
  • I updated documentation for user-facing changes, or marked it N/A above.
  • I added a Changeset for a published-package change, or explained why it is not applicable.
  • I can explain and maintain every submitted change, including any AI-assisted work.

🤖 Generated with Claude Code

antoine-berger and others added 9 commits October 28, 2026 00:23
…4383]

Sapiom-Identity is only attached over https (or http to a loopback host),
and the shared cross-origin drop list now includes it. Adds
fetchDroppingIdentityCrossOrigin, sanitizeFactHeaders and redactUrlForFacts
for the HTTP wrappers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolve the target with getUri, honour __sapiom.enabled === false, drop
Sapiom-Identity on cross-origin redirects, and record transaction facts
through the shared redaction helpers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…in [SAP-4383]

Read __sapiom from the Request or init before copying the request, so the
documented per-request opt-out and overrides take effect. Send through
fetchDroppingIdentityCrossOrigin, including the paid retry, and record
transaction facts through the shared redaction helpers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… [SAP-4383]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t [SAP-4383]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@antoine-berger

Copy link
Copy Markdown
Contributor Author

/devin review

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Starting Devin Review.

Devin Review

devin-ai-integration[bot]

This comment was marked as resolved.

antoine-berger and others added 8 commits October 28, 2026 02:37
…he identity path [SAP-4383]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…383]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ts new destination [SAP-4383]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…383]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…entity path [SAP-4383]

The first hop is now the caller's Request itself with `redirect: "manual"`, so
its body streams and keepalive works as with `fetch`. Only a redirect rebuilds
the request; a 307/308 resends the body from the clone already taken for the
402 retry. Integrity is checked on the final response.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@antoine-berger
antoine-berger marked this pull request as ready for review October 28, 2026 03:46
devin-ai-integration[bot]

This comment was marked as resolved.

antoine-berger and others added 2 commits October 28, 2026 04:35
…p [SAP-4383]

A non-empty init resets a Request's referrer and referrer policy, so the
first hop now passes them back explicitly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…URL [SAP-4383]

Through a forward proxy the absolute target URL is in `path`, so a caller
hook that rewrites only `path` now counts as a retarget.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gwitwer

gwitwer commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the thorough work on this, Antoine. We're going to pass on this one for now.

The gap is real but narrow: it needs a user to open or run a project they chose to clone, on a surface (Studio / the local dev tooling) that isn't core product today. Against that, the change adds behaviour developers and customers will notice, and the cost of reviewing, releasing and supporting it is higher than the risk it removes. We'd rather keep the security effort on the server-side gaps (billing scope, payment replay, OAuth, auth claims), which are approved.

Please close this PR and move the ticket to Canceled with a one-line note pointing here. If this area becomes core, or we see the gap exploited, we'll reopen it from the ticket.

Specific to this one: 2,343 lines for a ticket rated Low, and two customer-visible failure modes (identity dropped silently over non-loopback http, ignoring SAPIOM_ALLOW_INSECURE_HTTP; CredentialChannelError on a server URL outside the configured deployment).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Devin Review

Comment thread .changeset/sdk-credential-hygiene.md Resolved
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

2 participants